PageRenderTime 59ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/import/lib.php

https://github.com/Br3nda/mahara
PHP | 305 lines | 221 code | 39 blank | 45 comment | 19 complexity | 7561450940b3a5a351ab302ba068bbe7 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MIT
  1. <?php
  2. /**
  3. * Mahara: Electronic portfolio, weblog, resume builder and social networking
  4. * Copyright (C) 2006-2008 Catalyst IT Ltd (http://www.catalyst.net.nz)
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. * @package mahara
  20. * @subpackage import
  21. * @author Catalyst IT Ltd
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
  23. * @copyright (C) 2006-2008 Catalyst IT Ltd http://catalyst.net.nz
  24. *
  25. */
  26. defined('INTERNAL') || die();
  27. abstract class PluginImport extends Plugin {
  28. private $id;
  29. private $data;
  30. private $host; // this might move
  31. private $expirytime;
  32. private $token;
  33. private $usr;
  34. private $usrobj;
  35. private $importertransport;
  36. public function __construct($id, $record=null) {
  37. if (empty($record)) {
  38. if (!$record = get_record('import_queue', 'id', $id)) {
  39. throw new NotFoundException("Failed to find import queue record with id $id");
  40. }
  41. }
  42. foreach ((array)$record as $field => $value) {
  43. if ($field == 'data' && !is_array($value)) {
  44. $value = unserialize($value);
  45. }
  46. $this->{$field} = $value;
  47. }
  48. $this->usrobj = new User();
  49. $this->usrobj->find_by_id($this->usr);
  50. if (!empty($this->host)) {
  51. $this->importertransport = new MnetImporterTransport($this);
  52. }
  53. else {
  54. $this->importertransport = new LocalImporterTransport($this);
  55. }
  56. // we could do more here later I guess
  57. }
  58. public function prepare() {
  59. $this->importertransport->prepare_files();
  60. }
  61. /**
  62. * processes the files and adds them to the user's artefact area
  63. */
  64. public abstract function process();
  65. public function cleanup() {
  66. $this->importertransport->cleanup();
  67. }
  68. public function get($field) {
  69. if (!property_exists($this,$field)) {
  70. throw new ParamOutOfRangeException("Field $field wasn't found in class " . get_class($this));
  71. }
  72. return $this->{$field};
  73. }
  74. public static function class_from_format($format) {
  75. $format = trim($format);
  76. if ($format == 'files') {
  77. $format = 'file';
  78. }
  79. safe_require('import', $format);
  80. return generate_class_name('import', $format);
  81. }
  82. /**
  83. * @todo check the rest of the queue table for options
  84. * Generate a new import to be queued
  85. *
  86. * @param int $userid idof user to import for
  87. * @param string $plugin plugin to handle the import
  88. * not always known at this point
  89. * @param string $host wwwroot of mnet host if applicable
  90. * @param int $ready whether the import is ready to start (usually no)
  91. */
  92. public static function create_new_queue($userid, $plugin=null, $host=null, $ready=0) {
  93. // generate a token, insert it into the queue table
  94. $queue = (object)array(
  95. 'token' => generate_token(),
  96. 'host' => $host,
  97. 'usr' => $userid,
  98. 'queue' => (int)!(PluginImport::import_immediately_allowed()),
  99. 'ready' => $ready,
  100. 'expirytime' => db_format_timestamp(time()+(60*60*24)),
  101. 'plugin' => $plugin
  102. );
  103. $queue->id = insert_record('import_queue', $queue);
  104. return $queue;
  105. }
  106. public static function create_importer($id, $record=null) {
  107. if (empty($record)) {
  108. if (!$record = get_record('import_queue', 'id', $id)) {
  109. throw new NotFoundException("Failed to find import queue record with id $id");
  110. }
  111. }
  112. $class = self::class_from_format($record->format);
  113. return new $class($id,$record);
  114. }
  115. public static abstract function validate_import_data($importdata);
  116. public static final function import_immediately_allowed() {
  117. // @todo change this (check whatever)
  118. return true;
  119. }
  120. /**
  121. * if we're sending stuff back to wherever we were called from
  122. * use this method
  123. * at the moment, the only implementation is for mnet
  124. * sending back a list of file ids.
  125. */
  126. public function get_return_data() {
  127. return array();
  128. }
  129. }
  130. function import_process_queue() {
  131. if (!$ready = get_records_select_array('import_queue',
  132. 'ready = ? OR expirytime < ?', array(1, db_format_timestamp(time())),
  133. '', '*,' . db_format_tsfield('expirytime', 'ex'))) {
  134. return true;
  135. }
  136. $now = time();
  137. $processed = array();
  138. foreach ($ready as $item) {
  139. if ($item->ex < $now) {
  140. log_debug('deleting expired import record', $item);
  141. $processed[] = $item->id;
  142. continue;
  143. }
  144. $importer = PluginImport::create_importer($item->id, $item);
  145. try {
  146. $importer->prepare();
  147. $importer->process();
  148. $importer->cleanup();
  149. $processed[] = $item->id;
  150. }
  151. catch (Exception $e) {
  152. log_debug('an error occured on import: ' . $e->getMessage());
  153. $importer->get('importertransport')->cleanup();
  154. }
  155. }
  156. if (empty($processed)) {
  157. return true;
  158. }
  159. delete_records_select(
  160. 'import_queue',
  161. 'id IN ( ' . implode(',', db_array_to_ph($processed)) . ')',
  162. $processed
  163. );
  164. }
  165. abstract class ImporterTransport {
  166. /**
  167. * this might be a path to a directory containing the files
  168. * or an array containing some other info
  169. * or the path to a file, depending on the format
  170. */
  171. public abstract function files_info();
  172. /**
  173. * do whatever is necessary to retrieve the file(s)
  174. */
  175. public abstract function prepare_files();
  176. /**
  177. * cleanup temporary working area
  178. */
  179. public abstract function cleanup();
  180. }
  181. class LocalImporterTransport extends ImporterTransport {
  182. private $relativepath;
  183. private $zipfilename;
  184. public function __construct(Importer $importer/* TODO: wtf is an Importer? */) {
  185. }
  186. public function cleanup() {
  187. // TODO
  188. }
  189. public function prepare_files() {
  190. }
  191. /**
  192. * For this to work with the 'file' import plugin, it needs to provide 'zipfile' and 'relativepath'
  193. *
  194. * Other import plugins might need different things
  195. */
  196. public function files_info() {
  197. return array(
  198. 'zipfile' => $this->zipfilename,
  199. 'relativepath' => $this->relativepath,
  200. );
  201. }
  202. }
  203. class MnetImporterTransport extends ImporterTransport {
  204. private $importer;
  205. private $host;
  206. private $token;
  207. private $relativepath;
  208. private $tempdir;
  209. private $zipfilename;
  210. public function __construct(Importer $importer) {
  211. $this->importer = $importer;
  212. $this->token = $importer->get('token');
  213. $this->host = get_record('host', 'wwwroot', $importer->get('host'));
  214. }
  215. public function cleanup() {
  216. if (empty($this->tempdir)) {
  217. return;
  218. }
  219. rmdirr($this->tempdir);
  220. }
  221. public function prepare_files() {
  222. require_once(get_config('docroot') . 'api/xmlrpc/client.php');
  223. $client = new Client();
  224. try {
  225. $client->set_method('portfolio/mahara/lib.php/fetch_file')
  226. ->add_param($this->token)
  227. ->send($this->host->wwwroot);
  228. } catch (XmlrpcClientException $e) {
  229. throw new ImportException('Failed to retrieve zipfile from remote server: ' . $e->getMessage());
  230. }
  231. if (!$filecontents = base64_decode($client->response)) {
  232. throw new ImportException('Failed to retrieve zipfile from remote server');
  233. }
  234. $this->relativepath = 'temp/import/' . $this->importer->get('id') . '/';
  235. if ($tmpdir = get_config('unziptempdir')) {
  236. $this->tempdir = $tmpdir . $this->relativepath;
  237. }
  238. else {
  239. $this->tempdir = get_config('dataroot') . $this->relativepath;
  240. }
  241. if (!check_dir_exists($this->tempdir)) {
  242. throw new ImportException('Failed to create the temporary directories to work in');
  243. }
  244. $this->zipfilename = 'import.zip';
  245. if (!file_put_contents($this->tempdir . $this->zipfilename, $filecontents)) {
  246. throw new ImportException('Failed to write out the zipfile to local temporary storage');
  247. }
  248. }
  249. public function files_info() {
  250. return array(
  251. 'zipfile' => $this->zipfilename,
  252. 'tempdir' => $this->tempdir,
  253. 'relativepath' => $this->relativepath,
  254. );
  255. }
  256. public function get_description() {
  257. return get_string('remotehost', 'mahara', $this->host->name);
  258. }
  259. }
  260. ?>