pdfimporter.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. <?php
  2. // This file is part of the Sloodle project (www.sloodle.org) and is released under the GNU GPL v3.
  3. /**
  4. * Defines the SLOODLE Presenter importer plugin for converting a PDF file to a list of images (1 image per page).
  5. * Many thanks to Jordan Guinaud for his original code which made this plugin possible.
  6. * Note: this plugin requires PHP >= 4.1.0 and the presence of the IMagick extension.
  7. *
  8. * @package sloodle
  9. * @copyright Copyright (c) 2009 Sloodle (various contributors)
  10. * @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
  11. * @since Sloodle 0.4.1
  12. *
  13. * @contributor Jordan Guinaud
  14. * @contributor Peter R. Bloomfield
  15. *
  16. */
  17. // Path to the ImageMagick "convert" program. Leave it blank to DISABLE this feature for security.
  18. // On Linux, it is likely to be '/usr/bin/convert' or '/usr/local/bin/convert'
  19. // On Windows, you can probably just use 'convert'
  20. // Note: the PDF Importer plugin will attempt to auto-detect the location. You only need to modify this if the plugin can't find it.
  21. global $IMAGICK_CONVERT_PATH;
  22. $IMAGICK_CONVERT_PATH = '/usr/bin/convert';
  23. /**
  24. * Presenter plugin for importing a PDF file as a series of image slides.
  25. *
  26. * @package sloodle
  27. */
  28. class SloodlePluginPresenterPDFImporter extends SloodlePluginBasePresenterImporter
  29. {
  30. /**
  31. * This string will contain a description of the plugin's compatibility after the compatibility check function is called.
  32. * It will be stored in the current language when the compatibility check function is called, assuming there is a suitable SLOODLE language file installed.
  33. * @var string
  34. * @access public
  35. */
  36. var $compatibility_summary = '';
  37. /**
  38. * Gets the identifier of this plugin.
  39. * This function MUST be overridden by sub-classes to return an ID that is unique to the category.
  40. * It is possible to have different plugins of the same ID in different categories.
  41. * This function is given a very explicitly sloodley name as it lets us ignore any classes which don't declare it.
  42. * @access public
  43. * @return string|bool The ID of this plugin, or boolean false if this is a base class and should not be instantiated as a plugin.
  44. */
  45. function sloodle_get_plugin_id()
  46. {
  47. return 'pdf-imagemagick';
  48. }
  49. /**
  50. * Render this importer on a web page.
  51. * All importing functionality should be handled by this function as well.
  52. * @param string $url A URL to this Presenter, without a "mode" parameter.
  53. * @param SloodleModulePresenter $presenter An object representing this Presenter.
  54. */
  55. function render($url, $presenter)
  56. {
  57. // Get translation strings
  58. $struploadfile = get_string('upload:file', 'sloodle');
  59. $strselectuploadfile = get_string('upload:selectfile', 'sloodle');
  60. $strimportposition = get_string('presenter:importposition', 'sloodle');
  61. $strimportfromcomputer = get_string('presenter:importfrommycomputer', 'sloodle');
  62. $strimportname = get_string('presenter:importname', 'sloodle');
  63. $strimportnamecaption = get_string('presenter:importnamecaption', 'sloodle');
  64. // Get expected form data
  65. $selectfile = optional_param('selectfile', '', PARAM_CLEAN);
  66. $uploadfile = optional_param('uploadfile', '', PARAM_CLEAN);
  67. $importname = optional_param('importname', '', PARAM_CLEAN);
  68. $position = (int)optional_param('sloodleentryposition', -1, PARAM_INT);
  69. // Has a file been selected?
  70. if (!empty($selectfile)) {
  71. // Has a local file name been specified to import from?
  72. $localfile = optional_param('sloodleimportfile', '', PARAM_CLEAN);
  73. if (!empty($localfile)) return $this->import_file($presenter, $localfile, $importname, $position);
  74. }
  75. // Has a file been uploaded?
  76. if (!empty($uploadfile)) {
  77. // Has an upload been made which we can import from?
  78. $localfile = ''; $clientfile = '';
  79. $res = $this->process_upload($localfile, $clientfile);
  80. if ($res === true) {
  81. sloodle_debug("Upload successful<br/>\n");
  82. return $this->import_file($presenter, $localfile, $importname, $position, $clientfile);
  83. }
  84. if (is_string($res)) error($res, $url.'&amp;mode=edit');
  85. }
  86. // No file specified - display forms to let the user select or upload the file.
  87. // Determine our maximum upload size
  88. $maxsize = sloodle_get_max_post_upload();
  89. $maxsizedesc = sloodle_get_size_description($maxsize);
  90. // Open the form
  91. echo '<form action="" method="post" enctype="multipart/form-data"><fieldset style="border-style:none;">';
  92. echo '<input type="hidden" name="id" id="id" value="'.$presenter->cm->id.'" />';
  93. echo '<input type="hidden" name="mode" id="mode" value="importslides" />';
  94. echo '<input type="hidden" name="sloodleplugintype" id="sloodleplugintype" value="'.$this->sloodle_get_plugin_id().'" />';
  95. echo '</fieldset><br/>';
  96. // Let the user specify a name for the imported files
  97. echo '<label for="importname" title="'.$strimportnamecaption.'">'.$strimportname.': </label>';
  98. echo '<input type="text" name="importname" id="importname" value="" size="30" maxlength="100" title="'.$strimportnamecaption.'" />';
  99. echo "<br/><br/>\n";
  100. // Let the user select the position to upload to in the Presentation
  101. $this->print_slide_position_menu($presenter, $position);
  102. echo "<br/><br/>\n";
  103. // Display our upload form
  104. echo '<fieldset style="width:50%; margin-left:auto; margin-right:auto;">';
  105. echo '<h3>'.$strimportfromcomputer."</h3>\n";
  106. echo '<input type="hidden" name="MAX_FILE_SIZE" value="'.$maxsize.'" />';
  107. echo '<label for="userfile">'.$strselectuploadfile.': </label>';
  108. echo '<input type="file" name="userfile" id="userfile" size="50" />';
  109. echo '<p style="font-style:italic; font-size:90%;">['.get_string('upload:maxsize', 'sloodle', $maxsizedesc)."]</p><br/>\n";
  110. echo '<input type="submit" name="uploadfile" id="uploadfile" value="'.$struploadfile.'" /><br/>'."\n";
  111. echo '</fieldset><br/>';
  112. // TODO: add a separate section allowing the import of a file elsewhere on the web
  113. // TODO: add a separate section allowing the import of a file already in the course/site files
  114. // Close the form
  115. echo "</fieldset></form><br/>\n";
  116. }
  117. /**
  118. * Display a drop-down menu of slides in the current presentation.
  119. * @param SloodleModulePresenter $presenter An object representing the Presenter to work from.
  120. * @param integer $position Specifies the intially selected position, if known. Defaults to end.
  121. */
  122. function print_slide_position_menu($presenter, $position = -1)
  123. {
  124. // Get translation strings
  125. $strimportposition = get_string('presenter:importposition', 'sloodle');
  126. $strimportpositioncaption = get_string('presenter:importpositioncaption', 'sloodle');
  127. // Get a list of slides
  128. $slides = $presenter->get_slides();
  129. // Display the form element
  130. echo '<label for="sloodleentryposition" title="'.$strimportpositioncaption.'">'.$strimportposition.': </label>';
  131. echo '<select name="sloodleentryposition" id="sloodleentryposition" size="1" title="'.$strimportpositioncaption.'">'."\n";
  132. $selected = false;
  133. foreach ($slides as $curslide) {
  134. // Add this slide to the menu
  135. echo "<option value=\"{$curslide->slideposition}\"";
  136. if ($curslide->slideposition == $position) {
  137. echo ' selected="selected"';
  138. $selected = true;
  139. }
  140. echo ">{$curslide->slideposition}: {$curslide->name}</option>\n";
  141. }
  142. // Add an 'end' option
  143. if (!empty($curslide)) $endentrynum = $curslide->slideposition + 1;
  144. else $endentrynum = 1;
  145. echo "<option value=\"{$endentrynum}\"";
  146. if (!$selected) echo " selected=\"selected\"";
  147. echo ">--".get_string('end', 'sloodle')."--</option>\n";
  148. echo "</select>\n";
  149. }
  150. /**
  151. * Attempt to process a file upload.
  152. * @param string $path [out] This reference parameter will contain the path of the uploaded file if an upload has been performed. It will be empty if no upload has occurred.
  153. * @param string $name [out] This reference parameter will contain the original name of the uploaded file if an upload has been performed.
  154. * @return bool|string Returns true if an upload occurred succesfully. Returns false if no upload has happened. Returns a string containing an error message if an error occurred.
  155. */
  156. function process_upload(&$path, &$name)
  157. {
  158. // If no file has been uploaded, then there is nothing to do
  159. if (empty($_FILES['userfile']['name'])) return false;
  160. // Is the file empty?
  161. if ((int)$_FILES['userfile']['size'] == 0) return get_string('upload:emptyfile', 'sloodle');
  162. // Was an error code specified?
  163. if (isset($_FILES['userfile']['error'])) {
  164. switch ($_FILES['userfile']['error']) {
  165. case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: return get_string('upload:toobig', 'sloodle');
  166. case UPLOAD_ERR_PARTIAL: return get_string('upload:partial', 'sloodle');
  167. }
  168. if ($_FILES['userfile']['error'] != UPLOAD_ERR_OK) return get_string('upload:error', 'sloodle');
  169. }
  170. // Store the file path and name
  171. $name = $_FILES['userfile']['name'];
  172. $path = $_FILES['userfile']['tmp_name'];
  173. return true;
  174. }
  175. /**
  176. * Import a file to this Presenter.
  177. * @param SloodleModulePresenter $presenter An object representing the Presenter we are importing into.
  178. * @param string $path The path of the file to import (must be local... i.e. on disk!)
  179. * @param string $name Optional -- a name for the import. If omitted, it will be taken from the clientpath or path.
  180. * @param integer $position The position at which the slides should be imported. Optional. Defaults to import at the end.
  181. * @param string $clientpath (Optional) Specifies the original client path from which a file name can be extrapolated.
  182. * @return bool True if successful or false if not.
  183. */
  184. function import_file($presenter, $path, $name = '', $position = -1, $clientpath = '')
  185. {
  186. global $CFG;
  187. $cmid = $presenter->cm->id;
  188. $context = get_context_instance(CONTEXT_MODULE, $cmid);
  189. $contextid = $context->id;
  190. // In Moodle 2, we make an itemid for the file api
  191. $itemid = time();
  192. if (!file_exists($path)) error("Import file doesn't exist.");
  193. // Start by running a compatibility check -- this just makes sure the extensions are loaded.
  194. $this->check_compatibility();
  195. // PHP 4 doesn't support recursive creation of folders, so we need to do this the manual way
  196. // For Moodle 2, we upload to a temporary directory, then use the file api to move to the relevant place.
  197. $dir_sitefiles = SLOODLE_IS_ENVIRONMENT_MOODLE_2 ? $CFG->dataroot.'/temp/sloodle' : $CFG->dataroot.'/'.SITEID;
  198. //$dir_sitefiles = $CFG->dataroot.'/'.SITEID;
  199. $dir_presenter = $dir_sitefiles.'/presenter';
  200. $dir_import = $dir_presenter.'/'.$contextid;
  201. if (!file_exists($dir_sitefiles)) mkdir($dir_sitefiles);
  202. if (!file_exists($dir_presenter)) mkdir($dir_presenter);
  203. if (!file_exists($dir_import)) mkdir($dir_import);
  204. // Now check on last time that the import folder exists
  205. if (!file_exists($dir_import)) {
  206. error("Failed to create directory for imported images. Please check the file permissions for your MoodleData folder.<br/><br/>Attempted to create: {$dir_import}");
  207. }
  208. // Construct the URL of the folder for viewing the files
  209. $dir_view = $CFG->wwwroot;
  210. if (SLOODLE_IS_ENVIRONMENT_MOODLE_2) {
  211. $dir_view .= '/pluginfile.php/'.intval($contextid).'/mod_sloodle/presenter/'.intval($itemid);
  212. } else {
  213. $dir_view .= '/file.php/'.SITEID.'/presenter/'.$presenter->cm->id;
  214. }
  215. // In Moodle 2, make a file path, as distinct to the temporary file saving location
  216. $fileapipath = '';
  217. if (SLOODLE_IS_ENVIRONMENT_MOODLE_2) {
  218. $fileapipath = '/'.intval($contextid).'/mod_sloodle/presenter/'.intval($itemid).'/';
  219. }
  220. // Use the file name from the path if necessary
  221. if (empty($name)) {
  222. if (!empty($clientpath)) $name = basename($clientpath, '.pdf');
  223. else $name = basename($path);
  224. }
  225. // Construct a basic identifier for the files which will be imported.
  226. // It will consist of a timestamp and the import name
  227. $filebase = gmdate('U').'_'.str_replace(" ", "_", $name);
  228. // We'll use JPG files as standard just now. We could make this customizable in future?
  229. $ext = 'jpg';
  230. // Attempt each importing method in turn
  231. $result = $this->_import_MagickWand($presenter, $path, $dir_import, $dir_view, $filebase, $ext, $name, $position, $itemid, $contextid, $fileapipath);
  232. if ($result === false) $result = $this->_import_ImageMagick($presenter, $path, $dir_import, $dir_view, $filebase, $ext, $name, $position, $itemid, $contextid, $fileapipath);
  233. // Prepare a "Continue" link which takes us to edit mode
  234. $continueURL = $CFG->wwwroot."/mod/sloodle/view.php?id={$presenter->cm->id}&amp;mode=edit";
  235. // Display the results (in future, it might be good to show a list of slides, and let the user rename or delete them before addition to the presentation)
  236. if ($result === false) {
  237. echo "<h3>",get_string('presenter:importfailed', 'sloodle'),"</h3>\n";
  238. echo "<h4>",get_string('presenter:importneedimagick', 'sloodle'),"</h4>\n";
  239. $strcontinue = get_string('continue');
  240. echo "<p style=\"text-align:center;\">( <a href=\"{$continueURL}\">{$strcontinue}</a> )</p>";
  241. return false;
  242. }
  243. echo "<h3>",get_string('presenter:importsuccessful', 'sloodle', $result),"</h3>\n";
  244. redirect($continueURL, '', 5);
  245. return true;
  246. }
  247. /**
  248. * Imports the given file using the MagickWand extension if possible. (Internal only)
  249. * @param SloodleModulePresenter $presenter An object representing the Presenter we are importing into.
  250. * @param string $srcfile Full path of the PDF file we are importing
  251. * @param string $destpath Folder path to which the imported files will be added.
  252. * @param string $viewurl URL of the folder in which the imported files will be viewed
  253. * @param string $destfile Name for the output files (excluding extension, such as .jpg). The page numbers will be appended automatically, before the extension
  254. * @param string $destfileext Extension for destination files, not including the dot. (e.g. "jpg" or "png").
  255. * @param string $destname Basic name to use for each imported slide. The page numbers will be appended automatically.
  256. * @param integer $position The position within the Presentation to add the new slides. Optional. Default is to put them at the end.
  257. * @return integer|bool If successful, an integer indicating the number of slides loaded is displayed. If the import does not (or cannot) work, then boolean false is returned.
  258. * @access private
  259. */
  260. function _import_MagickWand($presenter, $srcfile, $destpath, $viewurl, $destfile, $destfileext, $destname, $position = -1, $itemid = '', $contextid= '', $fileapipath = '')
  261. {
  262. global $CFG;
  263. // Only continue if the MagickWand extension is loaded (this is done by the check_compatibility function)
  264. if (!extension_loaded('magickwand')) return false;
  265. // Load the PDF file
  266. sloodle_debug('Loading PDF file... ');
  267. $mwand = NewMagickWand();
  268. if (!MagickReadImage($mwand, $srcfile)) {
  269. sloodle_debug('failed.<br/>');
  270. return false;
  271. }
  272. sloodle_debug('OK.<br/>');
  273. // Quick validation - position should start at 1. (-ve numbers mean "at the end")
  274. if ($position == 0) $position = 1;
  275. // Go through each page
  276. sloodle_debug('Preparing to iterate through pages of document...<br/>');
  277. MagickSetFirstIterator($mwand);
  278. $pagenum = 0; $page_position = -1;
  279. do {
  280. // Determine this page's position in the Presentation
  281. if ($position > 0) $page_position = $position + $pagenum;
  282. $pagenum++;
  283. // Construct the file and slide names for this page
  284. $page_filename = "{$destpath}/{$destfile}-{$pagenum}.{$destfileext}"; // Where it gets uploaded to
  285. $page_slidesource = "{$viewurl}/{$destfile}-{$pagenum}.{$destfileext}"; // The URL to access it publicly
  286. $page_slidename = "{$destname} ({$pagenum})";
  287. // Output the file
  288. sloodle_debug(" Writing page {$pagenum} to file...");
  289. if (!MagickWriteImage($mwand, $page_filename)) {
  290. sloodle_debug('failed.<br/>');
  291. } else {
  292. sloodle_debug('OK.<br/>');
  293. }
  294. if (SLOODLE_IS_ENVIRONMENT_MOODLE_2) {
  295. $registered = $this->_register_moodle_api_file( $page_filename, $itemid, $contextid, $fileapipath, "{$destfile}-{$pagenum}.{$destfileext}");
  296. @unlink($page_filename);
  297. if (!$registered) {
  298. return false;
  299. }
  300. }
  301. // Add the entry to the Presenter
  302. sloodle_debug(" Adding slide \"{$page_slidename}\" to presentation at position {$page_position}... ");
  303. if (!$presenter->add_entry($page_slidesource, 'image', $page_slidename, $page_position)) {
  304. sloodle_debug('failed.<br/>');
  305. } else {
  306. sloodle_debug('OK.<br/>');
  307. }
  308. } while (MagickNextImage($mwand));
  309. sloodle_debug('Finished.<br/>');
  310. DestroyMagickWand($mwand);
  311. return $pagenum;
  312. }
  313. /**
  314. * Imports the given file using the ImageMagick command line programs if possible. (Internal only)
  315. * @param SloodleModulePresenter $presenter An object representing the Presenter we are importing into.
  316. * @param string $srcfile Full path of the PDF file we are importing
  317. * @param string $destpath Folder path to which the imported files will be added.
  318. * @param string $viewurl URl of the folder in which the files can be viewed
  319. * @param string $destfile Name for the output files (excluding extension, such as .jpg). The page numbers will be appended automatically, before the extension
  320. * @param string $destfileext Extension for destination files, not including the dot. (e.g. "jpg" or "png").
  321. * @param string $destname Basic name to use for each imported slide. The page numbers will be appended automatically.
  322. * @param integer $position The position within the Presentation to add the new slides. Optional. Default is to put them at the end.
  323. * @param string $itemid The item id - used to make a unique directory name to avoid naming clashes.
  324. * @return integer|bool If successful, an integer indicating the number of slides loaded is displayed. If the import does not (or cannot) work, then boolean false is returned.
  325. * @access private
  326. */
  327. function _import_ImageMagick($presenter, $srcfile, $destpath, $viewurl, $destfile, $destfileext, $destname, $position = -1, $itemid = '', $contextid = '', $fileapipath = '')
  328. {
  329. global $IMAGICK_CONVERT_PATH;
  330. // Do a security check -- has command-line execution of IMagick been disabled by the admin?
  331. sloodle_debug("<br/><strong>Attempting to use ImageMagick by command-line.</strong><br/>");
  332. if (empty($IMAGICK_CONVERT_PATH)) {
  333. sloodle_debug(" ERROR: path to ImageMagick \'convert\' program is blank.");
  334. return false;
  335. }
  336. // Now make sure there are no quotation marks in the source/destination file and path names
  337. // (these could be used to execute malicious commands on the server)
  338. if (strpos($srcfile, "\"") !== false || strpos($destpath, "\"") !== false || strpos($destfile, "\"") !== false || strpos($destfileext, "\"") != false) error("Invalid file name -- please remove quotation marks from file names.");
  339. // Construct the conversion command
  340. $srcfile_shell_clean = escapeshellarg($srcfile);
  341. $destpath_shell_clean = escapeshellarg($destpath.'/'.$destfile.'-');
  342. $destfileext_shell_clean = escapeshellarg('.'.$destfileext);
  343. //$cmd = "\"{$IMAGICK_CONVERT_PATH}\" -verbose \"{$srcfile_shell_clean}\" \"{$destpath_shell_clean}/{$destfile_shell_clean}-%d.{$destfileext_shell_clean}\"";
  344. $cmd = "{$IMAGICK_CONVERT_PATH} -verbose {$srcfile_shell_clean} {$destpath_shell_clean}%d{$destfileext_shell_clean}";
  345. if (substr(php_uname(), 0, 7) == "Windows") $cmd = 'start /B "" '.$cmd; // Windows compatibility
  346. sloodle_debug(" Executing shell command: {$cmd}<br/>");
  347. $output = array();
  348. $result = @exec($cmd, $output);
  349. // If all the output is empty, then execution failed
  350. if (empty($result) && empty($output)) {
  351. sloodle_debug(" ERROR: execution of the shell command failed.<br/>");
  352. //echo "<hr><pre>"; print_r($output); echo "</pre><hr>";
  353. return false;
  354. }
  355. // Quick validation - position should start at 1. (-ve numbers mean "at the end")
  356. if ($position == 0) $position = 1;
  357. // Go through each page which was created.
  358. // Stop when we encounter a file which wasn't created -- that will be the end of the document.
  359. $pagenum = 0; $page_position = -1;
  360. $stop = false;
  361. while ($stop == false && $pagenum < 10000) {
  362. // Determine this page's position in the Presentation
  363. if ($position > 0) $page_position = $position + $pagenum;
  364. // Construct the file and slide names for this page
  365. $page_filename = "{$destpath}/{$destfile}-{$pagenum}.{$destfileext}"; // Where it gets uploaded to
  366. $page_slidesource = "{$viewurl}/{$destfile}-{$pagenum}.{$destfileext}"; // The URL to access it publicly
  367. $page_slidename = "{$destname} (".($pagenum + 1).")";
  368. // Was this file created?
  369. if (file_exists($page_filename)) {
  370. if (SLOODLE_IS_ENVIRONMENT_MOODLE_2) {
  371. $registered = $this->_register_moodle_api_file( $page_filename, $itemid, $contextid, $fileapipath, "{$destfile}-{$pagenum}.{$destfileext}");
  372. @unlink($page_filename);
  373. if (!$registered) {
  374. return false;
  375. }
  376. }
  377. // Add it to the Presenter
  378. $presenter->add_entry($page_slidesource, 'image', $page_slidename, $page_position);
  379. $pagenum++;
  380. } else {
  381. $stop = true;
  382. }
  383. }
  384. return $pagenum;
  385. }
  386. function _register_moodle_api_file( $tempfile, $itemid, $contextid, $fileapipath, $filename ) {
  387. $fs = get_file_storage();
  388. $fileinfo = array(
  389. 'contextid' => $contextid, // ID of context
  390. 'component' => 'mod_sloodle', // usually = table name
  391. 'filearea' => 'presenter', // usually = table name
  392. 'itemid' => $itemid, // usually = ID of row in table
  393. 'filepath' => $fileapipath,
  394. 'filename' => $filename
  395. );
  396. $fs->create_file_from_pathname( $fileinfo, $tempfile);
  397. return true;
  398. }
  399. /**
  400. * Gets the human-readable name of this plugin.
  401. * @param string $lang Optional -- can specify the language we want the plugin name in, as an identifier like "en_utf8". If unspecified, then the current Moodle language should be used.
  402. * @access public
  403. * @return string The human-readable name of this plugin
  404. */
  405. function get_plugin_name($lang = null)
  406. {
  407. return 'PDF Importer';
  408. }
  409. /**
  410. * Gets the human-readable description of this plugin.
  411. */
  412. function get_plugin_description($lang = null)
  413. {
  414. return 'Imports an Adbobe Acrobat (PDF) file into your Presentation. Each page becomes a single image slide.';
  415. }
  416. /**
  417. * Gets the internal version number of this plugin.
  418. * This should be a number like the internal version number for Moodle modules, containing the date and release number.
  419. * Format is: YYYYMMDD##.
  420. * For example, "2009012302" would be the 3rd release on the 23rd January 2009.
  421. * @return int The version number of this module.
  422. */
  423. function get_version()
  424. {
  425. return 2010020400;
  426. }
  427. /**
  428. * Checks the compatibility of this plugin with the current installation.
  429. * Override this for any plugin which has non-standard requirements, such as relying on particular PHP extensions.
  430. * Note that the default (base class) implementation of this function returns true.
  431. * @todo It would be useful if this function performed the auto-detection of the ImageMagick 'convert' program whether MagickWand is available or not.
  432. * @return bool True if plugin is compatible, or false if not.
  433. */
  434. function check_compatibility()
  435. {
  436. global $IMAGICK_CONVERT_PATH;
  437. $this->compatibility_summary = '';
  438. // Check to see if the MagickWand extension is already loaded..
  439. if (extension_loaded('magickwand'))
  440. {
  441. $this->compatibility_summary .= get_string('presenter:usingmagickwand', 'sloodle');
  442. return true;
  443. }
  444. // Attempt to load the extension, depending on OS.
  445. if ( (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') && function_exists('dl')) @dl('php_magickwand.dll');
  446. else if (function_exists('dl')) @dl('magickwand.so');
  447. // Check if MagickWand has been successfully loaded now.
  448. if (extension_loaded('magickwand'))
  449. {
  450. $this->compatibility_summary .= get_string('presenter:usingmagickwand', 'sloodle');
  451. return true;
  452. }
  453. $this->compatibility_summary .= get_string('presenter:magickwandnotinstalled', 'sloodle').' ';
  454. // Only do this if the use of ImageMagick via shell commands has not been disabled
  455. if (!empty($IMAGICK_CONVERT_PATH)) {
  456. // Build a list of locations to check for the ImageMagick program
  457. $checkLocs = array();
  458. $checkLocs[] = $IMAGICK_CONVERT_PATH;
  459. $checkLocs[] = '/usr/bin/convert';
  460. $checkLocs[] = '/usr/local/bin/convert';
  461. // Edmund Edgar, 2011-10-30:
  462. // Disabling this - I'm not happy with the security implications of trusting any file called "convert" or "convert.exe" in the web user's path.
  463. // Uncomment if you're really sure you want to do this.
  464. // $checkLocs[] = 'convert';
  465. // $checkLocs[] = 'convert.exe';
  466. // Check for the presence of the ImageMagick convert program at each location
  467. foreach ($checkLocs as $loc) {
  468. // Make sure it's a safe command
  469. $cmd = $loc.' -version';
  470. // Attempt to execute it
  471. $output = array();
  472. @exec($cmd, $output);
  473. // Do we have any output? And does it look like ImageMagick output?
  474. if (!empty($output) && strpos($output[0], 'ImageMagick') !== false) {
  475. // Store this path
  476. $this->compatibility_summary .= get_string('presenter:usingexecutable', 'sloodle');
  477. if ($loc != $IMAGICK_CONVERT_PATH) $IMAGICK_CONVERT_PATH = $loc;
  478. return true;
  479. }
  480. }
  481. $this->compatibility_summary .= get_string('presenter:convertnotfound', 'sloodle');
  482. } else {
  483. $this->compatibility_summary .= get_string('presenter:convertdisabled', 'sloodle');
  484. }
  485. return false;
  486. }
  487. /**
  488. * After check_compatibility() has been called, this function will return a string summarising the compatibility of the plugin.
  489. * For example, it may explain that a particular extension is being used, or that it could not be loaded.
  490. * @return string A summary of the compatibility of the plugin.
  491. */
  492. function get_compatibility_summary()
  493. {
  494. return $this->compatibility_summary;
  495. }
  496. /**
  497. * Run a full compatibility test and output the results to the webpage.
  498. * @return bool True if plugin is compatible, or false otherwise.
  499. */
  500. function run_compatibility_test()
  501. {
  502. global $IMAGICK_CONVERT_PATH;
  503. // Check to see if the MagickWand extension is already loaded
  504. echo "<h3>MagickWand</h3>\n";
  505. echo "Checking to see if MagickWand extension is loaded.<br/>";
  506. if (extension_loaded('magickwand'))
  507. {
  508. echo "Success. MagickWand extension was already loaded.<br/>";
  509. return true;
  510. }
  511. echo "MagickWand extension not already loaded.<br/>";
  512. // Attempt to load the extension, depending on OS.
  513. if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
  514. {
  515. echo "Windows OS detected. Attempting to load 'php_magickwand.dll' extension dynamically.<br/>";
  516. if(function_exists('dl')) {
  517. @dl('php_magickwand.dll');
  518. }
  519. } else {
  520. echo "Attempting to load 'php_magickwand.so' extension dynamically.<br/>";
  521. if(function_exists('dl')) {
  522. @dl('magickwand.so');
  523. }
  524. }
  525. // Check if MagickWand has been successfully loaded now.
  526. if (extension_loaded('magickwand'))
  527. {
  528. echo "Success. MagickWand extension can be loaded dynamically.<br/>";
  529. return true;
  530. }
  531. echo "MagickWand extension could not be loaded. This plugin will attempt to use ImageMagick directly.<br/>";
  532. echo "<h3>ImageMagick</h3>\n";
  533. // Only do this if the use of ImageMagick via shell commands has not been disabled
  534. if (!empty($IMAGICK_CONVERT_PATH)) {
  535. echo "Attempting to auto-detect location of the ImageMagick 'convert' program.<br/>";
  536. // Build a list of locations to check for the ImageMagick program
  537. $checkLocs = array();
  538. $checkLocs[] = $IMAGICK_CONVERT_PATH;
  539. $checkLocs[] = '/usr/bin/convert';
  540. $checkLocs[] = '/usr/local/bin/convert';
  541. // Edmund Edgar, 2011-10-30:
  542. // Disabling this - I'm not happy with the security implications of trusting any file called "convert" or "convert.exe" in the web user's path.
  543. // Uncomment if you're really sure you want to do this.
  544. // $checkLocs[] = 'convert';
  545. // $checkLocs[] = 'convert.exe';
  546. // Check for the presence of the ImageMagick convert program at each location
  547. foreach ($checkLocs as $loc) {
  548. echo "<br/>Checking for program at location: \"{$loc}\"...<br/>";
  549. // Make sure it's a safe command
  550. $cmd = $loc.' -version';
  551. // Attempt to execute it
  552. $output = array();
  553. @exec($cmd, $output);
  554. if (empty($output)) {
  555. echo " - path is not executable.<br/>";
  556. } else if (strpos($output[0], 'ImageMagick') === false) {
  557. echo " - executable does not appear to belong to Imagemagick.<br>";
  558. } else {
  559. echo "- success. This appears to be the ImageMagick 'convert' program.<br/>";
  560. return true;
  561. }
  562. }
  563. echo "<br/>Unable to locate the ImageMagick 'convert' program.<br/>";
  564. return false;
  565. }
  566. echo "The use of ImageMagick by shell execution has been disabled.<br/>";
  567. return false;
  568. }
  569. }
  570. ?>