Source for file pdfimporter.php
Documentation is available at pdfimporter.php
// This file is part of the Sloodle project (www.sloodle.org) and is released under the GNU GPL v3.
* Defines the SLOODLE Presenter importer plugin for converting a PDF file to a list of images (1 image per page).
* Many thanks to Jordan Guinaud for his original code which made this plugin possible.
* Note: this plugin requires PHP >= 4.1.0 and the presence of the IMagick extension.
* @copyright Copyright (c) 2009 Sloodle (various contributors)
* @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
* @contributor Jordan Guinaud
* @contributor Peter R. Bloomfield
// Path to the ImageMagick "convert" file. Leave it blank to DISABLE this feature for security.
// Likely to be something like this: '/usr/bin/convert' or '/usr/local/bin/convert'
global $IMAGICK_CONVERT_PATH;
$IMAGICK_CONVERT_PATH =
'/usr/local/bin/convert';
* Presenter plugin for importing a PDF file as a series of image slides.
* Render this importer on a web page.
* All importing functionality should be handled by this function as well.
* @param string $url A URL to this Presenter, without a "mode" parameter.
* @param SloodleModulePresenter $presenter An object representing this Presenter.
function render($url, $presenter)
// Get translation strings
$struploadfile =
get_string('upload:file', 'sloodle');
$strselectuploadfile =
get_string('upload:selectfile', 'sloodle');
$strimportposition =
get_string('presenter:importposition', 'sloodle');
$strimportfromcomputer =
get_string('presenter:importfrommycomputer', 'sloodle');
$strimportname =
get_string('presenter:importname', 'sloodle');
$strimportnamecaption =
get_string('presenter:importnamecaption', 'sloodle');
// Get expected form data
$selectfile =
optional_param('selectfile', '', PARAM_CLEAN);
$uploadfile =
optional_param('uploadfile', '', PARAM_CLEAN);
$importname =
optional_param('importname', '', PARAM_CLEAN);
$position = (int)
optional_param('sloodleentryposition', -
1, PARAM_INT);
// Has a file been selected?
if (!empty($selectfile)) {
// Has a local file name been specified to import from?
$localfile =
optional_param('sloodleimportfile', '', PARAM_CLEAN);
if (!empty($localfile)) return $this->import_file($presenter, $localfile, $importname, $position);
// Has a file been uploaded?
if (!empty($uploadfile)) {
// Has an upload been made which we can import from?
$localfile =
''; $name =
'';
return $this->import_file($presenter, $localfile, $importname, $position);
if (is_string($res)) error($res, $url.
'&mode=edit');
// No file specified - display forms to let the user select or upload the file.
// Determine our maximum upload size
echo
'<form action="" method="post" enctype="multipart/form-data"><fieldset style="border-style:none;">';
echo
'<input type="hidden" name="id" id="id" value="'.
$presenter->cm->id.
'" />';
echo
'<input type="hidden" name="mode" id="mode" value="importslides" />';
echo
'<input type="hidden" name="sloodleplugintype" id="sloodleplugintype" value="'.
$this->get_id().
'" />';
// Let the user specify a name for the imported files
echo
'<label for="importname" title="'.
$strimportnamecaption.
'">'.
$strimportname.
': </label>';
echo
'<input type="text" name="importname" id="importname" value="" size="30" maxlength="100" title="'.
$strimportnamecaption.
'" />';
// Let the user select the position to upload to in the Presentation
// Display our upload form
echo
'<fieldset style="width:50%; margin-left:auto; margin-right:auto;">';
echo
'<h3>'.
$strimportfromcomputer.
"</h3>\n";
echo
'<input type="hidden" name="MAX_FILE_SIZE" value="'.
$maxsize.
'" />';
echo
'<label for="userfile">'.
$strselectuploadfile.
': </label>';
echo
'<input type="file" name="userfile" id="userfile" size="50" />';
echo
'<p style="font-style:italic; font-size:90%;">['.
get_string('upload:maxsize', 'sloodle', $maxsizedesc).
"]</p><br/>\n";
echo
'<input type="submit" name="uploadfile" id="uploadfile" value="'.
$struploadfile.
'" /><br/>'.
"\n";
// TODO: add a separate section allowing the import of a file elsewhere on the web
// TODO: add a separate section allowing the import of a file already in the course/site files
echo
"</fieldset></form><br/>\n";
* Display a drop-down menu of slides in the current presentation.
* @param SloodleModulePresenter $presenter An object representing the Preseter to work from.
* @param integer $position Specifies the intially selected position, if known. Defaults to end.
// Get translation strings
$strimportposition =
get_string('presenter:importposition', 'sloodle');
$strimportpositioncaption =
get_string('presenter:importpositioncaption', 'sloodle');
$slides =
$presenter->get_slides();
// Display the form element
echo
'<label for="sloodleentryposition" title="'.
$strimportpositioncaption.
'">'.
$strimportposition.
': </label>';
echo
'<select name="sloodleentryposition" id="sloodleentryposition" size="1" title="'.
$strimportpositioncaption.
'">'.
"\n";
foreach ($slides as $curslide) {
// Add this slide to the menu
echo
"<option value=\"{$curslide->slideposition}\"
";
if ($curslide->slideposition ==
$position) {
echo
' selected="selected"';
echo
">{$curslide->slideposition}: {
$curslide->name}</option>\n
";
$endentrynum =
$curslide->slideposition +
1;
echo
"<option value=\"{$endentrynum}\"";
if (!$selected) echo
" selected=\"selected\"";
echo
">--".
get_string('end', 'sloodle').
"--</option>\n";
* Attempt to process a file upload.
* @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.
* @param string $name [out] This reference parameter will contain the original name of the uploaded file if an upload has been performed.
* @return bool|stringReturns true if an upload occurred succesfully. Returns false if no upload has happened. Returns a string containing an error message if an error occurred.
// If no file has been uploaded, then there is nothing to do
if (empty($_FILES['userfile']['name'])) return false;
if ((int)
$_FILES['userfile']['size'] ==
0) return get_string('upload:emptyfile', 'sloodle');
// Was an error code specified?
if (isset
($_FILES['userfile']['error'])) {
switch ($_FILES['userfile']['error']) {
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
return get_string('upload:toobig', 'sloodle');
case UPLOAD_ERR_PARTIAL:
return get_string('upload:partial', 'sloodle');
if ($_FILES['userfile']['error'] !=
UPLOAD_ERR_OK) return get_string('upload:error', 'sloodle');
// Store the file path and name
$name =
$_FILES['userfile']['name'];
$path =
$_FILES['userfile']['tmp_name'];
* Import a file to this Presenter.
* @param SloodleModulePresenter $presenter An object representing the Presenter we are importing into.
* @param string $path The path of the file to import (must be local... i.e. on disk!)
* @param string $name Optional -- a name for the import. If omitted, it will be taken from the path.
* @param integer $position The position at which the slides should be imported. Optional. Defaults to import at the end.
* @return bool True if successful or false if not.
function import_file($presenter, $path, $name =
'', $position = -
1)
// PHP 4 doesn't support recursive creation of folders, so we need to do this the manual way
$dir_sitefiles =
$CFG->dataroot.
'/'.
SITEID;
$dir_presenter =
$dir_sitefiles.
'/presenter';
$dir_import =
$dir_presenter.
'/'.
$presenter->cm->id;
// Now check on last time that the import folder exists
error("Failed to create directory for imported images. Please check the file permissions for your MoodleData folder.<br/><br/>Attempted to create: {$dir_import}");
// Construct the URL of the folder for viewing the files
$dir_view =
$CFG->wwwroot.
'/file.php/'.
SITEID.
'/presenter/'.
$presenter->cm->id;
// Use the file name from the path if necessary
if (empty($name)) $name =
basename($path);
// Construct a basic identifier for the files which will be imported.
// It will consist of a timestamp and the import name
// We'll use JPG files as standard just now. We could make this customizable in future?
// Attempt each importing method in turn
$result =
$this->_import_MagickWand($presenter, $path, $dir_import, $dir_view, $filebase, $ext, $name, $position);
if ($result ===
false) $result =
$this->_import_ImageMagick($presenter, $path, $dir_import, $dir_view, $filebase, $ext, $name, $position);
// Prepare a "Continue" link which takes us to edit mode
$continueURL =
$CFG->wwwroot.
"/mod/sloodle/view.php?id={$presenter->cm->id}&mode=edit
";
// 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)
echo
"<h3>",get_string('presenter:importfailed', 'sloodle'),"</h3>\n";
echo
"<h4>",get_string('presenter:importneedimagick', 'sloodle'),"</h4>\n";
redirect($continueURL, '', 5);
echo
"<h3>",get_string('presenter:importsuccessful', 'sloodle', $result),"</h3>\n";
redirect($continueURL, '', 5);
* Imports the given file using the MagickWand extension if possible. (Internal only)
* @param SloodleModulePresenter $presenter An object representing the Presenter we are importing into.
* @param string $srcfile Full path of the PDF file we are importing
* @param string $destpath Folder path to which the imported files will be added.
* @param string $viewurl URL of the folder in which the imported files will be viewed
* @param string $destfile Name for the output files (excluding extension, such as .jpg). The page numbers will be appended automatically, before the extension
* @param string $destfileext Extension for destination files, not including the dot. (e.g. "jpg" or "png").
* @param string $destname Basic name to use for each imported slide. The page numbers will be appended automatically.
* @param integer $position The position within the Presentation to add the new slides. Optional. Default is to put them at the end.
* @return integer|boolIf successful, an integer indicating the number of slides loaded is displayed. If the import does not (or cannot) work, then boolean false is returned.
function _import_MagickWand($presenter, $srcfile, $destpath, $viewurl, $destfile, $destfileext, $destname, $position = -
1)
// Check to see if the MagickWand extension is already loaded.
// Attempt to load it if not -- the name will vary depending on OS
sloodle_debug('<br/><strong>Checking for presence of extension "magickwand"...</strong> ');
sloodle_debug('Windows.<br/>Attempting to load "php_magickwand.dll"... ');
@dl('php_magickwand.dll');
sloodle_debug('Non-Windows.<br>Attempting to load "magickwand.so"... ');
// If it's still not loaded, then we cannot use this function
$mwand =
NewMagickWand();
if (!MagickReadImage($mwand, $srcfile)) {
// Quick validation - position should start at 1. (-ve numbers mean "at the end")
if ($position ==
0) $position =
1;
sloodle_debug('Preparing to iterate through pages of document...<br/>');
MagickSetFirstIterator($mwand);
$pagenum =
0; $page_position = -
1;
// Determine this page's position in the Presentation
if ($position >
0) $page_position =
$position +
$pagenum;
// Construct the file and slide names for this page
$page_filename =
"{
$destpath}/{
$destfile}-{
$pagenum}.{
$destfileext}"; // Where it gets uploaded to
$page_slidesource =
"{
$viewurl}/{
$destfile}-{
$pagenum}.{
$destfileext}"; // The URL to access it publicly
$page_slidename =
"{
$destname} ({
$pagenum})
";
if (!MagickWriteImage($mwand, $page_filename)) {
// Add the entry to the Presenter
sloodle_debug(" Adding slide \"{$page_slidename}\" to presentation at position {$page_position}... ");
if (!$presenter->add_entry($page_slidesource, 'PresenterSlideImage', $page_slidename, $page_position)) {
} while (MagickNextImage($mwand));
DestroyMagickWand($mwand);
* Imports the given file using the ImageMagick command line programs if possible. (Internal only)
* @param SloodleModulePresenter $presenter An object representing the Presenter we are importing into.
* @param string $srcfile Full path of the PDF file we are importing
* @param string $destpath Folder path to which the imported files will be added.
* @param string $viewurl URl of the folder in which the files can be viewed
* @param string $destfile Name for the output files (excluding extension, such as .jpg). The page numbers will be appended automatically, before the extension
* @param string $destfileext Extension for destination files, not including the dot. (e.g. "jpg" or "png").
* @param string $destname Basic name to use for each imported slide. The page numbers will be appended automatically.
* @param integer $position The position within the Presentation to add the new slides. Optional. Default is to put them at the end.
* @return integer|boolIf successful, an integer indicating the number of slides loaded is displayed. If the import does not (or cannot) work, then boolean false is returned.
function _import_ImageMagick($presenter, $srcfile, $destpath, $viewurl, $destfile, $destfileext, $destname, $position = -
1)
global $IMAGICK_CONVERT_PATH;
// Do a security check -- has command-line execution of IMagick been disabled by the admin?
sloodle_debug("<br/><strong>Attempting to use ImageMagick by command-line.</strong><br/>");
if (empty($IMAGICK_CONVERT_PATH)) {
sloodle_debug(" ERROR: path to ImageMagick \"convert\" program is blank.");
// Now make sure there are no quotation marks in the source/destination file and path names
// (these could be used to execute malicious commands on the server)
if (strpos($srcfile, "\"") !==
false ||
strpos($destpath, "\"") !==
false ||
strpos($destfile, "\"") !==
false ||
strpos($destfileext, "\"") !=
false) error("Invalid file name -- please remove quotation marks from file names.");
// Execute the conversion command
$cmd =
escapeshellcmd("{
$IMAGICK_CONVERT_PATH} -verbose \"{
$srcfile}\" \"{
$destpath}/{
$destfile}.{
$destfileext}\"
");
// If all the output is empty, then execution failed
if (empty($result) &&
empty($output)) {
sloodle_debug(" ERROR: execution of the shell command failed.<br/>");
// Quick validation - position should start at 1. (-ve numbers mean "at the end")
if ($position ==
0) $position =
1;
// Go through each page which was created.
// Stop when we encounter a file which wasn't created -- that will be the end of the document.
$pagenum =
0; $page_position = -
1;
while ($stop ==
false &&
$pagenum <
10000) {
// Determine this page's position in the Presentation
if ($position >
0) $page_position =
$position +
$pagenum;
// Construct the file and slide names for this page
$page_filename =
"{
$destpath}/{
$destfile}-{
$pagenum}.{
$destfileext}"; // Where it gets uploaded to
$page_slidesource =
"{
$viewurl}/{
$destfile}-{
$pagenum}.{
$destfileext}"; // The URL to access it publicly
$page_slidename =
"{
$destname} (
".
($pagenum +
1).
")";
// Was this file created?
// Add it to the Presenter
$presenter->add_entry($page_slidesource, 'PresenterSlideImage', $page_slidename, $page_position);
* Gets the human-readable name of this plugin.
* @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.
* @return string The human-readable name of this plugin
* Gets the human-readable description of this plugin.
return 'Imports an Adbobe Acrobat (PDF) file into your Presentation. Each page becomes a single image slide.';
* Gets the internal version number of this plugin.
* This should be a number like the internal version number for Moodle modules, containing the date and release number.
* For example, "2009012302" would be the 3rd release on the 23rd January 2009.
* @return int The version number of this module.
Documentation generated on Fri, 17 Jul 2009 11:02:21 +0100 by phpDocumentor 1.4.0