diff --git a/blocks/html/lib.php b/blocks/html/lib.php
index 17d98cecb2823..a2555c3f88e8a 100644
--- a/blocks/html/lib.php
+++ b/blocks/html/lib.php
@@ -28,9 +28,10 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $args, $forcedownload) {
+function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $SCRIPT;
if ($context->contextlevel != CONTEXT_BLOCK) {
@@ -64,7 +65,7 @@ function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $a
}
session_get_instance()->write_close();
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, $options);
}
/**
diff --git a/blocks/upgrade.txt b/blocks/upgrade.txt
index a87cbf8d1ff64..b7e288e9c9bb2 100644
--- a/blocks/upgrade.txt
+++ b/blocks/upgrade.txt
@@ -1,6 +1,12 @@
This files describes API changes in /blocks/* - activity modules,
information provided here is intended especially for developers.
+=== 2.3 ===
+
+required changes in code:
+* block_xxx_pluginfile() is now given the 7th parameter (hopefully the last one) that
+ contains additional options for the file serving. The array should be re-passed
+ to send_stored_file().
=== 2.0 ===
diff --git a/lib/filelib.php b/lib/filelib.php
index 1d0b01ccd2f0d..cb30f23a572ee 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -1950,6 +1950,14 @@ function send_file($path, $filename, $lifetime = 'default' , $filter=0, $pathiss
* Handles the sending of file data to the user's browser, including support for
* byteranges etc.
*
+ * The $options parameter supports the following keys:
+ * (string|null) preview - send the preview of the file (e.g. "thumb" for a thumbnail)
+ * (string|null) filename - overrides the implicit filename
+ * (bool) dontdie - return control to caller afterwards. this is not recommended and only used for cleanup tasks.
+ * if this is passed as true, ignore_user_abort is called. if you don't want your processing to continue on cancel,
+ * you must detect this case when control is returned using connection_aborted. Please not that session is closed
+ * and should not be reopened.
+ *
* @category files
* @global stdClass $CFG
* @global stdClass $COURSE
@@ -1958,16 +1966,41 @@ function send_file($path, $filename, $lifetime = 'default' , $filter=0, $pathiss
* @param int $lifetime Number of seconds before the file should expire from caches (default 24 hours)
* @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
* @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
- * @param string $filename Override filename
- * @param bool $dontdie - return control to caller afterwards. this is not recommended and only used for cleanup tasks.
- * if this is passed as true, ignore_user_abort is called. if you don't want your processing to continue on cancel,
- * you must detect this case when control is returned using connection_aborted. Please not that session is closed
- * and should not be reopened.
- * @return null script execution stopped unless $dontdie is true
+ * @param array $options additional options affecting the file serving
+ * @return null script execution stopped unless $options['dontdie'] is true
*/
-function send_stored_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, $filename=null, $dontdie=false) {
+function send_stored_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, array $options=array()) {
global $CFG, $COURSE, $SESSION;
+ if (empty($options['filename'])) {
+ $filename = null;
+ } else {
+ $filename = $options['filename'];
+ }
+
+ if (empty($options['dontdie'])) {
+ $dontdie = false;
+ } else {
+ $dontdie = true;
+ }
+
+ if (!empty($options['preview'])) {
+ // replace the file with its preview
+ $fs = get_file_storage();
+ $stored_file = $fs->get_file_preview($stored_file, $options['preview']);
+ if (!$stored_file) {
+ // unable to create a preview of the file
+ send_header_404();
+ die();
+ } else {
+ // preview images have fixed cache lifetime and they ignore forced download
+ // (they are generated by GD and therefore they are considered reasonably safe).
+ $lifetime = DAYSECS;
+ $filter = 0;
+ $forcedownload = false;
+ }
+ }
+
if (!$stored_file or $stored_file->is_directory()) {
// nothing to serve
if ($dontdie) {
@@ -3211,9 +3244,10 @@ public function get_extensions($types) {
*
* @param string $relativepath
* @param bool $forcedownload
+ * @param null|string $preview the preview mode, defaults to serving the original file
* @todo MDL-31088 file serving improments
*/
-function file_pluginfile($relativepath, $forcedownload) {
+function file_pluginfile($relativepath, $forcedownload, $preview = null) {
global $DB, $CFG, $USER;
// relative path must start with '/'
if (!$relativepath) {
@@ -3289,7 +3323,7 @@ function file_pluginfile($relativepath, $forcedownload) {
send_file_not_found();
}
- send_stored_file($file, 10*60, 0, true); // download MUST be forced - security!
+ send_stored_file($file, 10*60, 0, true, array('preview' => $preview)); // download MUST be forced - security!
// ========================================================================================================================
} else if ($component === 'grade') {
@@ -3306,7 +3340,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'feedback' and $context->contextlevel == CONTEXT_COURSE) {
//TODO: nobody implemented this yet in grade edit form!!
@@ -3323,7 +3357,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else {
send_file_not_found();
}
@@ -3344,7 +3378,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, true);
+ send_stored_file($file, 60*60, 0, true, array('preview' => $preview));
} else {
send_file_not_found();
@@ -3376,7 +3410,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_USER) {
@@ -3404,7 +3438,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_COURSE) {
@@ -3451,7 +3485,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else {
send_file_not_found();
@@ -3488,7 +3522,7 @@ function file_pluginfile($relativepath, $forcedownload) {
$theme = theme_config::load($themename);
redirect($theme->pix_url('u/'.$filename, 'moodle'));
}
- send_stored_file($file, 60*60*24); // enable long caching, there are many images on each page
+ send_stored_file($file, 60*60*24, 0, false, array('preview' => $preview)); // enable long caching, there are many images on each page
} else if ($filearea === 'private' and $context->contextlevel == CONTEXT_USER) {
require_login();
@@ -3508,7 +3542,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 0, 0, true); // must force download - security!
+ send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security!
} else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_USER) {
@@ -3555,7 +3589,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 0, 0, true); // must force download - security!
+ send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security!
} else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_COURSE) {
$userid = (int)array_shift($args);
@@ -3593,7 +3627,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 0, 0, true); // must force download - security!
+ send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security!
} else if ($filearea === 'backup' and $context->contextlevel == CONTEXT_USER) {
require_login();
@@ -3614,7 +3648,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 0, 0, true); // must force download - security!
+ send_stored_file($file, 0, 0, true, array('preview' => $preview)); // must force download - security!
} else {
send_file_not_found();
@@ -3639,7 +3673,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else {
send_file_not_found();
}
@@ -3662,7 +3696,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'section') {
if ($CFG->forcelogin) {
@@ -3691,7 +3725,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else {
send_file_not_found();
@@ -3723,7 +3757,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'icon') {
$filename = array_pop($args);
@@ -3738,7 +3772,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60);
+ send_stored_file($file, 60*60, 0, false, array('preview' => $preview));
} else {
send_file_not_found();
@@ -3763,7 +3797,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else {
send_file_not_found();
@@ -3782,7 +3816,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 0, 0, $forcedownload);
+ send_stored_file($file, 0, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'section' and $context->contextlevel == CONTEXT_COURSE) {
require_login($course);
@@ -3797,7 +3831,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close();
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'activity' and $context->contextlevel == CONTEXT_MODULE) {
require_login($course, false, $cm);
@@ -3810,7 +3844,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close();
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
} else if ($filearea === 'automated' and $context->contextlevel == CONTEXT_COURSE) {
// Backup files that were generated by the automated backup systems.
@@ -3825,7 +3859,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 0, 0, $forcedownload);
+ send_stored_file($file, 0, 0, $forcedownload, array('preview' => $preview));
} else {
send_file_not_found();
@@ -3871,7 +3905,7 @@ function file_pluginfile($relativepath, $forcedownload) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, $forcedownload);
+ send_stored_file($file, 60*60, 0, $forcedownload, array('preview' => $preview));
}
// ========================================================================================================================
@@ -3905,17 +3939,17 @@ function file_pluginfile($relativepath, $forcedownload) {
$lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
// finally send the file
- send_stored_file($file, $lifetime, 0);
+ send_stored_file($file, $lifetime, 0, false, array('preview' => $preview));
}
$filefunction = $component.'_pluginfile';
$filefunctionold = $modname.'_pluginfile';
if (function_exists($filefunction)) {
// if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
- $filefunction($course, $cm, $context, $filearea, $args, $forcedownload);
+ $filefunction($course, $cm, $context, $filearea, $args, $forcedownload, array('preview' => $preview));
} else if (function_exists($filefunctionold)) {
// if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
- $filefunctionold($course, $cm, $context, $filearea, $args, $forcedownload);
+ $filefunctionold($course, $cm, $context, $filearea, $args, $forcedownload, array('preview' => $preview));
}
send_file_not_found();
@@ -3942,11 +3976,12 @@ function file_pluginfile($relativepath, $forcedownload) {
$filefunction = $component.'_pluginfile';
if (function_exists($filefunction)) {
// if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
- $filefunction($course, $birecord, $context, $filearea, $args, $forcedownload);
+ $filefunction($course, $birecord, $context, $filearea, $args, $forcedownload, array('preview' => $preview));
}
send_file_not_found();
+ // ========================================================================================================================
} else if (strpos($component, '_') === false) {
// all core subsystems have to be specified above, no more guessing here!
send_file_not_found();
@@ -3962,7 +3997,7 @@ function file_pluginfile($relativepath, $forcedownload) {
$filefunction = $component.'_pluginfile';
if (function_exists($filefunction)) {
// if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
- $filefunction($course, $cm, $context, $filearea, $args, $forcedownload);
+ $filefunction($course, $cm, $context, $filearea, $args, $forcedownload, array('preview' => $preview));
}
send_file_not_found();
diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index a60b7c2944ed7..463f9d4f76337 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -152,6 +152,113 @@ public function get_file_instance(stdClass $file_record) {
return new stored_file($this, $file_record, $this->filedir);
}
+ /**
+ * Returns an image file that represent the given stored file as a preview
+ *
+ * At the moment, only GIF, JPEG and PNG files are supported to have previews. In the
+ * future, the support for other mimetypes can be added, too (eg. generate an image
+ * preview of PDF, text documents etc).
+ *
+ * @param stored_file $file the file we want to preview
+ * @param string $mode preview mode, eg. 'thumb'
+ * @return stored_file|bool false if unable to create the preview, stored file otherwise
+ */
+ public function get_file_preview(stored_file $file, $mode) {
+
+ $context = context_system::instance();
+ $path = '/' . trim($mode, '/') . '/';
+ $preview = $this->get_file($context->id, 'core', 'preview', 0, $path, $file->get_contenthash());
+
+ if (!$preview) {
+ $preview = $this->create_file_preview($file, $mode);
+ if (!$preview) {
+ return false;
+ }
+ }
+
+ return $preview;
+ }
+
+ /**
+ * Generates a preview image for the stored file
+ *
+ * @param stored_file $file the file we want to preview
+ * @param string $mode preview mode, eg. 'thumb'
+ * @return stored_file|bool the newly created preview file or false
+ */
+ protected function create_file_preview(stored_file $file, $mode) {
+
+ $mimetype = $file->get_mimetype();
+
+ if ($mimetype === 'image/gif' or $mimetype === 'image/jpeg' or $mimetype === 'image/png') {
+ // make a preview of the image
+ $data = $this->create_imagefile_preview($file, $mode);
+
+ } else {
+ // unable to create the preview of this mimetype yet
+ return false;
+ }
+
+ if (empty($data)) {
+ return false;
+ }
+
+ // getimagesizefromstring() is available from PHP 5.4 but we need to support
+ // lower versions, so...
+ $tmproot = make_temp_directory('thumbnails');
+ $tmpfilepath = $tmproot.'/'.$file->get_contenthash().'_'.$mode;
+ file_put_contents($tmpfilepath, $data);
+ $imageinfo = getimagesize($tmpfilepath);
+ unlink($tmpfilepath);
+
+ $context = context_system::instance();
+
+ $record = array(
+ 'contextid' => $context->id,
+ 'component' => 'core',
+ 'filearea' => 'preview',
+ 'itemid' => 0,
+ 'filepath' => '/' . trim($mode, '/') . '/',
+ 'filename' => $file->get_contenthash(),
+ );
+
+ if ($imageinfo) {
+ $record['mimetype'] = $imageinfo['mime'];
+ }
+
+ return $this->create_file_from_string($record, $data);
+ }
+
+ /**
+ * Generates a preview for the stored image file
+ *
+ * @param stored_file $file the image we want to preview
+ * @param string $mode preview mode, eg. 'thumb'
+ * @return string|bool false if a problem occurs, the thumbnail image data otherwise
+ */
+ protected function create_imagefile_preview(stored_file $file, $mode) {
+ global $CFG;
+ require_once($CFG->libdir.'/gdlib.php');
+
+ $tmproot = make_temp_directory('thumbnails');
+ $tmpfilepath = $tmproot.'/'.$file->get_contenthash();
+ $file->copy_content_to($tmpfilepath);
+
+ if ($mode === 'tinyicon') {
+ $data = generate_image_thumbnail($tmpfilepath, 16, 16);
+
+ } else if ($mode === 'thumb') {
+ $data = generate_image_thumbnail($tmpfilepath, 90, 90);
+
+ } else {
+ throw new file_exception('storedfileproblem', 'Invalid preview mode requested');
+ }
+
+ unlink($tmpfilepath);
+
+ return $data;
+ }
+
/**
* Fetch file using local file id.
*
@@ -1306,6 +1413,25 @@ public function cron() {
$rs->close();
mtrace('done.');
+ // remove orphaned preview files (that is files in the core preview filearea without
+ // the existing original file)
+ mtrace('Deleting orphaned preview files... ', '');
+ $sql = "SELECT p.*
+ FROM {files} p
+ LEFT JOIN {files} o ON (p.filename = o.contenthash)
+ WHERE p.contextid = ? AND p.component = 'core' AND p.filearea = 'preview' AND p.itemid = 0
+ AND o.id IS NULL";
+ $syscontext = context_system::instance();
+ $rs = $DB->get_recordset_sql($sql, array($syscontext->id));
+ foreach ($rs as $orphan) {
+ $file = $this->get_file_instance($orphan);
+ if (!$file->is_directory()) {
+ $file->delete();
+ }
+ }
+ $rs->close();
+ mtrace('done.');
+
// remove trash pool files once a day
// if you want to disable purging of trash put $CFG->fileslastcleanup=time(); into config.php
if (empty($CFG->fileslastcleanup) or $CFG->fileslastcleanup < time() - 60*60*24) {
diff --git a/lib/filestorage/tests/file_storage_test.php b/lib/filestorage/tests/file_storage_test.php
new file mode 100644
index 0000000000000..ba31f8043a9d5
--- /dev/null
+++ b/lib/filestorage/tests/file_storage_test.php
@@ -0,0 +1,80 @@
+.
+
+/**
+ * Unit tests for /lib/filestorage/file_storage.php
+ *
+ * @package core
+ * @category test
+ * @copyright 2012 David Mudrak
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/filelib.php');
+
+class filestoragelib_testcase extends advanced_testcase {
+
+ /**
+ * Local files can be added to the filepool
+ */
+ public function test_create_file_from_pathname() {
+ global $CFG;
+
+ $this->resetAfterTest(false);
+
+ $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+ $syscontext = context_system::instance();
+ $filerecord = array(
+ 'contextid' => $syscontext->id,
+ 'component' => 'core',
+ 'filearea' => 'unittest',
+ 'itemid' => 0,
+ 'filepath' => '/images/',
+ 'filename' => 'testimage.jpg',
+ );
+
+ $fs = get_file_storage();
+ $fs->create_file_from_pathname($filerecord, $filepath);
+
+ $this->assertTrue($fs->file_exists($syscontext->id, 'core', 'unittest', 0, '/images/', 'testimage.jpg'));
+
+ return $fs->get_file($syscontext->id, 'core', 'unittest', 0, '/images/', 'testimage.jpg');
+ }
+
+ /**
+ * Local images can be added to the filepool and their preview can be obtained
+ *
+ * @depends test_create_file_from_pathname
+ */
+ public function test_get_file_preview(stored_file $file) {
+ global $CFG;
+
+ $this->resetAfterTest(true);
+ $fs = get_file_storage();
+
+ $previewtinyicon = $fs->get_file_preview($file, 'tinyicon');
+ $this->assertInstanceOf('stored_file', $previewtinyicon);
+ $this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
+
+ $previewtinyicon = $fs->get_file_preview($file, 'thumb');
+ $this->assertInstanceOf('stored_file', $previewtinyicon);
+ $this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
+ }
+}
diff --git a/lib/filestorage/tests/fixtures/testimage.jpg b/lib/filestorage/tests/fixtures/testimage.jpg
new file mode 100644
index 0000000000000..15e05d1c32dba
Binary files /dev/null and b/lib/filestorage/tests/fixtures/testimage.jpg differ
diff --git a/lib/gdlib.php b/lib/gdlib.php
index 3b026b79d785a..151a722e29a4b 100644
--- a/lib/gdlib.php
+++ b/lib/gdlib.php
@@ -27,61 +27,62 @@
defined('MOODLE_INTERNAL') || die();
/**
+ * Copies a rectangular portion of the source image to another rectangle in the destination image
*
- * long description
- * @global object
- * @param object $dst_img
- * @param object $src_img
- * @param int $dst_x
- * @param int $dst_y
- * @param int $src_x
- * @param int $src_y
- * @param int $dst_w
- * @param int $dst_h
- * @param int $src_w
- * @param int $src_h
- * @return bool
- * @todo Finish documenting this function
+ * This function calls imagecopyresampled() if it is available and GD version is 2 at least.
+ * Otherwise it reimplements the same behaviour. See the PHP manual page for more info.
+ *
+ * @link http://php.net/manual/en/function.imagecopyresampled.php
+ * @param resource $dst_img the destination GD image resource
+ * @param resource $src_img the source GD image resource
+ * @param int $dst_x vthe X coordinate of the upper left corner in the destination image
+ * @param int $dst_y the Y coordinate of the upper left corner in the destination image
+ * @param int $src_x the X coordinate of the upper left corner in the source image
+ * @param int $src_y the Y coordinate of the upper left corner in the source image
+ * @param int $dst_w the width of the destination rectangle
+ * @param int $dst_h the height of the destination rectangle
+ * @param int $src_w the width of the source rectangle
+ * @param int $src_h the height of the source rectangle
+ * @return bool tru on success, false otherwise
*/
-function ImageCopyBicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) {
-
+function imagecopybicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) {
global $CFG;
- if (function_exists('ImageCopyResampled') and $CFG->gdversion >= 2) {
- return ImageCopyResampled($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y,
+ if (function_exists('imagecopyresampled') and $CFG->gdversion >= 2) {
+ return imagecopyresampled($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y,
$dst_w, $dst_h, $src_w, $src_h);
}
$totalcolors = imagecolorstotal($src_img);
for ($i=0; $i<$totalcolors; $i++) {
- if ($colors = ImageColorsForIndex($src_img, $i)) {
- ImageColorAllocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
+ if ($colors = imagecolorsforindex($src_img, $i)) {
+ imagecolorallocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
}
}
- $scaleX = ($src_w - 1) / $dst_w;
- $scaleY = ($src_h - 1) / $dst_h;
+ $scalex = ($src_w - 1) / $dst_w;
+ $scaley = ($src_h - 1) / $dst_h;
- $scaleX2 = $scaleX / 2.0;
- $scaleY2 = $scaleY / 2.0;
+ $scalex2 = $scalex / 2.0;
+ $scaley2 = $scaley / 2.0;
for ($j = 0; $j < $dst_h; $j++) {
- $sY = $j * $scaleY;
+ $sy = $j * $scaley;
for ($i = 0; $i < $dst_w; $i++) {
- $sX = $i * $scaleX;
+ $sx = $i * $scalex;
- $c1 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX,(int)$sY+$scaleY2));
- $c2 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX,(int)$sY));
- $c3 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX+$scaleX2,(int)$sY+$scaleY2));
- $c4 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX+$scaleX2,(int)$sY));
+ $c1 = imagecolorsforindex($src_img, imagecolorat($src_img, (int)$sx, (int)$sy + $scaley2));
+ $c2 = imagecolorsforindex($src_img, imagecolorat($src_img, (int)$sx, (int)$sy));
+ $c3 = imagecolorsforindex($src_img, imagecolorat($src_img, (int)$sx + $scalex2, (int)$sy + $scaley2));
+ $c4 = imagecolorsforindex($src_img, imagecolorat($src_img, (int)$sx + $scalex2, (int)$sy));
$red = (int) (($c1['red'] + $c2['red'] + $c3['red'] + $c4['red']) / 4);
$green = (int) (($c1['green'] + $c2['green'] + $c3['green'] + $c4['green']) / 4);
$blue = (int) (($c1['blue'] + $c2['blue'] + $c3['blue'] + $c4['blue']) / 4);
- $color = ImageColorClosest ($dst_img, $red, $green, $blue);
- ImageSetPixel ($dst_img, $i + $dst_x, $j + $dst_y, $color);
+ $color = imagecolorclosest($dst_img, $red, $green, $blue);
+ imagesetpixel($dst_img, $i + $dst_x, $j + $dst_y, $color);
}
}
}
@@ -106,7 +107,7 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
return false;
}
- $imageinfo = GetImageSize($originalfile);
+ $imageinfo = getimagesize($originalfile);
if (empty($imageinfo)) {
return false;
@@ -119,24 +120,24 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
switch ($image->type) {
case IMAGETYPE_GIF:
- if (function_exists('ImageCreateFromGIF')) {
- $im = ImageCreateFromGIF($originalfile);
+ if (function_exists('imagecreatefromgif')) {
+ $im = imagecreatefromgif($originalfile);
} else {
debugging('GIF not supported on this server');
return false;
}
break;
case IMAGETYPE_JPEG:
- if (function_exists('ImageCreateFromJPEG')) {
- $im = ImageCreateFromJPEG($originalfile);
+ if (function_exists('imagecreatefromjpeg')) {
+ $im = imagecreatefromjpeg($originalfile);
} else {
debugging('JPEG not supported on this server');
return false;
}
break;
case IMAGETYPE_PNG:
- if (function_exists('ImageCreateFromPNG')) {
- $im = ImageCreateFromPNG($originalfile);
+ if (function_exists('imagecreatefrompng')) {
+ $im = imagecreatefrompng($originalfile);
} else {
debugging('PNG not supported on this server');
return false;
@@ -146,13 +147,13 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
return false;
}
- if (function_exists('ImagePng')) {
- $imagefnc = 'ImagePng';
+ if (function_exists('imagepng')) {
+ $imagefnc = 'imagepng';
$imageext = '.png';
$filters = PNG_NO_FILTER;
$quality = 1;
- } else if (function_exists('ImageJpeg')) {
- $imagefnc = 'ImageJpeg';
+ } else if (function_exists('imagejpeg')) {
+ $imagefnc = 'imagejpeg';
$imageext = '.jpg';
$filters = null; // not used
$quality = 90;
@@ -161,10 +162,10 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
return false;
}
- if (function_exists('ImageCreateTrueColor') and $CFG->gdversion >= 2) {
- $im1 = ImageCreateTrueColor(100,100);
- $im2 = ImageCreateTrueColor(35,35);
- if ($image->type == IMAGETYPE_PNG and $imagefnc === 'ImagePng') {
+ if (function_exists('imagecreatetruecolor') and $CFG->gdversion >= 2) {
+ $im1 = imagecreatetruecolor(100, 100);
+ $im2 = imagecreatetruecolor(35, 35);
+ if ($image->type == IMAGETYPE_PNG and $imagefnc === 'imagepng') {
imagealphablending($im1, false);
$color = imagecolorallocatealpha($im1, 0, 0, 0, 127);
imagefill($im1, 0, 0, $color);
@@ -175,8 +176,8 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
imagesavealpha($im2, true);
}
} else {
- $im1 = ImageCreate(100,100);
- $im2 = ImageCreate(35,35);
+ $im1 = imagecreate(100, 100);
+ $im2 = imagecreate(35, 35);
}
$cx = $image->width / 2;
@@ -188,8 +189,8 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
$half = floor($image->height / 2.0);
}
- ImageCopyBicubic($im1, $im, 0, 0, $cx-$half, $cy-$half, 100, 100, $half*2, $half*2);
- ImageCopyBicubic($im2, $im, 0, 0, $cx-$half, $cy-$half, 35, 35, $half*2, $half*2);
+ imagecopybicubic($im1, $im, 0, 0, $cx - $half, $cy - $half, 100, 100, $half * 2, $half * 2);
+ imagecopybicubic($im2, $im, 0, 0, $cx - $half, $cy - $half, 35, 35, $half * 2, $half * 2);
$fs = get_file_storage();
@@ -202,7 +203,7 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
return false;
}
$data = ob_get_clean();
- ImageDestroy($im1);
+ imagedestroy($im1);
$icon['filename'] = 'f1'.$imageext;
$fs->delete_area_files($context->id, $component, $filearea, $itemid);
$fs->create_file_from_string($icon, $data);
@@ -214,10 +215,95 @@ function process_new_icon($context, $component, $filearea, $itemid, $originalfil
return false;
}
$data = ob_get_clean();
- ImageDestroy($im2);
+ imagedestroy($im2);
$icon['filename'] = 'f2'.$imageext;
$fs->create_file_from_string($icon, $data);
return true;
}
+/**
+ * Generates a thumbnail for the given image
+ *
+ * If the GD library has at least version 2 and PNG support is available, the returned data
+ * is the content of a transparent PNG file containing the thumbnail. Otherwise, the function
+ * returns contents of a JPEG file with black background containing the thumbnail.
+ *
+ * @param string $filepath the full path to the original image file
+ * @param int $width the width of the requested thumbnail
+ * @param int $height the height of the requested thumbnail
+ * @return string|bool false if a problem occurs, the thumbnail image data otherwise
+ */
+function generate_image_thumbnail($filepath, $width, $height) {
+ global $CFG;
+
+ if (empty($CFG->gdversion) or empty($filepath) or empty($width) or empty($height)) {
+ return false;
+ }
+
+ $imageinfo = getimagesize($filepath);
+
+ if (empty($imageinfo)) {
+ return false;
+ }
+
+ $originalwidth = $imageinfo[0];
+ $originalheight = $imageinfo[1];
+
+ if (empty($originalwidth) or empty($originalheight)) {
+ return false;
+ }
+
+ $original = imagecreatefromstring(file_get_contents($filepath));
+
+ if (function_exists('imagepng')) {
+ $imagefnc = 'imagepng';
+ $filters = PNG_NO_FILTER;
+ $quality = 1;
+ } else if (function_exists('imagejpeg')) {
+ $imagefnc = 'imagejpeg';
+ $filters = null;
+ $quality = 90;
+ } else {
+ debugging('Neither JPEG nor PNG are supported at this server, please fix the system configuration.');
+ return false;
+ }
+
+ if (function_exists('imagecreatetruecolor') and $CFG->gdversion >= 2) {
+ $thumbnail = imagecreatetruecolor($width, $height);
+ if ($imagefnc === 'imagepng') {
+ imagealphablending($thumbnail, false);
+ imagefill($thumbnail, 0, 0, imagecolorallocatealpha($thumbnail, 0, 0, 0, 127));
+ imagesavealpha($thumbnail, true);
+ }
+ } else {
+ $thumbnail = imagecreate($width, $height);
+ }
+
+ $ratio = min($width / $originalwidth, $height / $originalheight);
+
+ if ($ratio < 1) {
+ $targetwidth = floor($originalwidth * $ratio);
+ $targetheight = floor($originalheight * $ratio);
+ } else {
+ // do not enlarge the original file if it is smaller than the requested thumbnail size
+ $targetwidth = $originalwidth;
+ $targetheight = $originalheight;
+ }
+
+ $dstx = floor(($width - $targetwidth) / 2);
+ $dsty = floor(($height - $targetheight) / 2);
+
+ imagecopybicubic($thumbnail, $original, $dstx, $dsty, 0, 0, $targetwidth, $targetheight, $originalwidth, $originalheight);
+
+ ob_start();
+ if (!$imagefnc($thumbnail, null, $quality, $filters)) {
+ ob_end_clean();
+ return false;
+ }
+ $data = ob_get_clean();
+ imagedestroy($original);
+ imagedestroy($thumbnail);
+
+ return $data;
+}
diff --git a/lib/portfolio/plugin.php b/lib/portfolio/plugin.php
index d86d1ead59198..6c32ffc64204c 100644
--- a/lib/portfolio/plugin.php
+++ b/lib/portfolio/plugin.php
@@ -822,8 +822,8 @@ public function send_file() {
if (!($file instanceof stored_file)) {
throw new portfolio_export_exception($this->get('exporter'), 'filenotfound', 'portfolio');
}
- // the last 'true' on the end of this means don't die(); afterwards, so we can clean up.
- send_stored_file($file, 0, 0, true, null, true);
+ // don't die(); afterwards, so we can clean up.
+ send_stored_file($file, 0, 0, true, array('dontdie' => true));
$this->get('exporter')->log_transfer();
}
diff --git a/lib/questionlib.php b/lib/questionlib.php
index 0cab3184067ac..e49a09ce5c17a 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -1719,8 +1719,9 @@ function question_rewrite_questiontext_preview_urls($questiontext, $contextid,
* @param int $questionid the question id
* @param array $args the remaining file arguments (file path).
* @param bool $forcedownload whether the user must be forced to download the file.
+ * @param array $options additional options affecting the file serving
*/
-function question_send_questiontext_file($questionid, $args, $forcedownload) {
+function question_send_questiontext_file($questionid, $args, $forcedownload, $options) {
global $DB;
$question = $DB->get_record_sql('
@@ -1735,7 +1736,7 @@ function question_send_questiontext_file($questionid, $args, $forcedownload) {
send_file_not_found();
}
- send_stored_file($file, 0, 0, $forcedownload);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
@@ -1759,8 +1760,9 @@ function question_send_questiontext_file($questionid, $args, $forcedownload) {
* @param string $filearea the name of the file area.
* @param array $args the remaining bits of the file path.
* @param bool $forcedownload whether the user must be forced to download the file.
+ * @param array $options additional options affecting the file serving
*/
-function question_pluginfile($course, $context, $component, $filearea, $args, $forcedownload) {
+function question_pluginfile($course, $context, $component, $filearea, $args, $forcedownload, array $options=array()) {
global $DB, $CFG;
if ($filearea === 'questiontext_preview') {
@@ -1768,7 +1770,7 @@ function question_pluginfile($course, $context, $component, $filearea, $args, $f
$questionid = array_shift($args);
component_callback($component, 'questiontext_preview_pluginfile', array(
- $context, $questionid, $args, $forcedownload));
+ $context, $questionid, $args, $forcedownload, $options));
send_file_not_found();
}
@@ -1841,7 +1843,7 @@ function question_pluginfile($course, $context, $component, $filearea, $args, $f
if ($module === 'core_question_preview') {
require_once($CFG->dirroot . '/question/previewlib.php');
return question_preview_question_pluginfile($course, $context,
- $component, $filearea, $qubaid, $slot, $args, $forcedownload);
+ $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options);
} else {
$dir = get_component_directory($module);
@@ -1856,7 +1858,7 @@ function question_pluginfile($course, $context, $component, $filearea, $args, $f
}
$filefunction($course, $context, $component, $filearea, $qubaid, $slot,
- $args, $forcedownload);
+ $args, $forcedownload, $options);
send_file_not_found();
}
@@ -1871,8 +1873,9 @@ function question_pluginfile($course, $context, $component, $filearea, $args, $f
* @param int $questionid the question id
* @param array $args remaining file args
* @param bool $forcedownload
+ * @param array $options additional options affecting the file serving
*/
-function core_question_questiontext_preview_pluginfile($context, $questionid, $args, $forcedownload) {
+function core_question_questiontext_preview_pluginfile($context, $questionid, $args, $forcedownload, array $options=array()) {
global $DB;
// Verify that contextid matches the question.
@@ -1889,7 +1892,7 @@ function core_question_questiontext_preview_pluginfile($context, $questionid, $a
question_require_capability_on($question, 'use');
- question_send_questiontext_file($questionid, $args, $forcedownload);
+ question_send_questiontext_file($questionid, $args, $forcedownload, $options);
}
/**
diff --git a/lib/upgrade.txt b/lib/upgrade.txt
index 80af326ce2f97..ffe792af5f194 100644
--- a/lib/upgrade.txt
+++ b/lib/upgrade.txt
@@ -11,6 +11,9 @@ Note:
* DDL and DML methods which were deprecated in 2.0 have now been removed, they will no longer produce
debug messages and will produce fatal errors
+API changes:
+* send_stored_file() has changed its interface
+
=== 2.2 ===
removed unused libraries:
diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index b1054432fea08..4b2daf02ec1e7 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1979,11 +1979,15 @@ function email_teachers($submission) {
}
/**
+ * Sends a file
+ *
* @param string $filearea
* @param array $args
+ * @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
- function send_file($filearea, $args) {
+ function send_file($filearea, $args, $forcedownload, array $options=array()) {
debugging('plugin does not implement file sending', DEBUG_DEVELOPER);
return false;
}
@@ -3087,9 +3091,10 @@ function assignment_get_participants($assignmentid) {
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - just send the file
*/
-function assignment_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function assignment_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -3106,7 +3111,7 @@ function assignment_pluginfile($course, $cm, $context, $filearea, $args, $forced
$assignmentclass = 'assignment_'.$assignment->assignmenttype;
$assignmentinstance = new $assignmentclass($cm->id, $assignment, $cm, $course);
- return $assignmentinstance->send_file($filearea, $args);
+ return $assignmentinstance->send_file($filearea, $args, $forcedownload, $options);
}
/**
* Checks if a scale is being used by an assignment
diff --git a/mod/assignment/type/online/assignment.class.php b/mod/assignment/type/online/assignment.class.php
index 0985666d17037..be5a238ca28a7 100644
--- a/mod/assignment/type/online/assignment.class.php
+++ b/mod/assignment/type/online/assignment.class.php
@@ -375,7 +375,7 @@ function extend_settings_navigation($node) {
}
}
- public function send_file($filearea, $args) {
+ public function send_file($filearea, $args, $forcedownload, array $options=array()) {
global $USER;
require_capability('mod/assignment:view', $this->context);
@@ -391,7 +391,8 @@ public function send_file($filearea, $args) {
}
session_get_instance()->write_close(); // unlock session during fileserving
- send_stored_file($file, 60*60, 0, true);
+
+ send_stored_file($file, 60*60, 0, true, $options);
}
/**
diff --git a/mod/assignment/type/upgrade.txt b/mod/assignment/type/upgrade.txt
new file mode 100644
index 0000000000000..20a9f6f418818
--- /dev/null
+++ b/mod/assignment/type/upgrade.txt
@@ -0,0 +1,7 @@
+This file describes changes in the assignment type API and DB structures.
+Information provided here is intended especially for developers.
+
+=== 2.3 ===
+
+API changes:
+* send_file() methods now accept $forcedownload and $options parameters
diff --git a/mod/assignment/type/upload/assignment.class.php b/mod/assignment/type/upload/assignment.class.php
index 4f1f567254048..bea044d270acf 100644
--- a/mod/assignment/type/upload/assignment.class.php
+++ b/mod/assignment/type/upload/assignment.class.php
@@ -614,7 +614,7 @@ function upload_file($mform, $options) {
die;
}
- function send_file($filearea, $args) {
+ function send_file($filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB, $USER;
require_once($CFG->libdir.'/filelib.php');
@@ -638,7 +638,8 @@ function send_file($filearea, $args) {
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
return false;
}
- send_stored_file($file, 0, 0, true); // download MUST be forced - security!
+
+ send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
} else if ($filearea === 'response') {
$submissionid = (int)array_shift($args);
@@ -658,7 +659,7 @@ function send_file($filearea, $args) {
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
return false;
}
- send_stored_file($file, 0, 0, true);
+ send_stored_file($file, 0, 0, true, $options);
}
return false;
diff --git a/mod/assignment/type/uploadsingle/assignment.class.php b/mod/assignment/type/uploadsingle/assignment.class.php
index a3998d89dd6de..39b41b7917bba 100644
--- a/mod/assignment/type/uploadsingle/assignment.class.php
+++ b/mod/assignment/type/uploadsingle/assignment.class.php
@@ -300,7 +300,7 @@ function portfolio_exportable() {
return true;
}
- function send_file($filearea, $args) {
+ function send_file($filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB, $USER;
require_once($CFG->libdir.'/filelib.php');
@@ -329,7 +329,7 @@ function send_file($filearea, $args) {
return false;
}
- send_stored_file($file, 0, 0, true); // download MUST be forced - security!
+ send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
}
function extend_settings_navigation($node) {
diff --git a/mod/data/lib.php b/mod/data/lib.php
index e6737d9bec8a5..d816cc3cff5b6 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -2963,9 +2963,10 @@ function mod_data_get_file_info($browser, $areas, $course, $cm, $context, $filea
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function data_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function data_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -3028,7 +3029,7 @@ function data_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa
}
// finally send the file
- send_stored_file($file, 0, 0, true); // download MUST be forced - security!
+ send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
}
return false;
diff --git a/mod/feedback/lib.php b/mod/feedback/lib.php
index 296655975a19c..2e95a1017a807 100644
--- a/mod/feedback/lib.php
+++ b/mod/feedback/lib.php
@@ -182,9 +182,10 @@ function feedback_update_instance($feedback) {
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function feedback_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function feedback_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($filearea === 'item' or $filearea === 'template') {
@@ -273,7 +274,7 @@ function feedback_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
}
// finally send the file
- send_stored_file($file, 0, 0, true); // download MUST be forced - security!
+ send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
return false;
}
diff --git a/mod/folder/lib.php b/mod/folder/lib.php
index 9abc5c21376c7..365dd923aabe5 100644
--- a/mod/folder/lib.php
+++ b/mod/folder/lib.php
@@ -293,9 +293,10 @@ function folder_get_file_info($browser, $areas, $course, $cm, $context, $fileare
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - just send the file
*/
-function folder_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function folder_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -323,7 +324,7 @@ function folder_pluginfile($course, $cm, $context, $filearea, $args, $forcedownl
// finally send the file
// for folder module, we force download file all the time
- send_stored_file($file, 86400, 0, true);
+ send_stored_file($file, 86400, 0, true, $options);
}
/**
diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 96fe4781eb564..9ad53b1003c24 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -4108,9 +4108,10 @@ function forum_get_file_info($browser, $areas, $course, $cm, $context, $filearea
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function forum_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function forum_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -4162,9 +4163,8 @@ function forum_pluginfile($course, $cm, $context, $filearea, $args, $forcedownlo
return false;
}
-
// finally send the file
- send_stored_file($file, 0, 0, true); // download MUST be forced - security!
+ send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
}
/**
diff --git a/mod/glossary/lib.php b/mod/glossary/lib.php
index a2da16dd75832..3f19d2081cda4 100644
--- a/mod/glossary/lib.php
+++ b/mod/glossary/lib.php
@@ -1538,9 +1538,10 @@ function mod_glossary_get_file_info($browser, $areas, $course, $cm, $context, $f
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function glossary_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function glossary_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -1590,7 +1591,7 @@ function glossary_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
}
// finally send the file
- send_stored_file($file, 0, 0, true); // download MUST be forced - security!
+ send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
} else if ($filearea === 'export') {
require_login($course, false, $cm);
diff --git a/mod/imscp/lib.php b/mod/imscp/lib.php
index 517047a0b79cd..f57a22763eb88 100644
--- a/mod/imscp/lib.php
+++ b/mod/imscp/lib.php
@@ -337,9 +337,10 @@ function imscp_get_file_info($browser, $areas, $course, $cm, $context, $filearea
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -367,7 +368,7 @@ function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownlo
}
// finally send the file
- send_stored_file($file, 86400, 0, $forcedownload);
+ send_stored_file($file, 86400, 0, $forcedownload, $options);
} else if ($filearea === 'backup') {
if (!has_capability('moodle/course:managefiles', $context)) {
@@ -383,7 +384,7 @@ function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownlo
}
// finally send the file
- send_stored_file($file, 86400, 0, $forcedownload);
+ send_stored_file($file, 86400, 0, $forcedownload, $options);
} else {
return false;
diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php
index 0157f0ee43d1e..b3252fcfe4155 100644
--- a/mod/lesson/lib.php
+++ b/mod/lesson/lib.php
@@ -876,9 +876,10 @@ function lesson_get_import_export_formats($type) {
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function lesson_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function lesson_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -917,7 +918,7 @@ function lesson_pluginfile($course, $cm, $context, $filearea, $args, $forcedownl
}
// finally send the file
- send_stored_file($file, 0, 0, $forcedownload); // download MUST be forced - security!
+ send_stored_file($file, 0, 0, $forcedownload, $options); // download MUST be forced - security!
}
/**
diff --git a/mod/page/lib.php b/mod/page/lib.php
index 6d960f8530ba2..4512f5e7fca5b 100644
--- a/mod/page/lib.php
+++ b/mod/page/lib.php
@@ -360,9 +360,10 @@ function page_get_file_info($browser, $areas, $course, $cm, $context, $filearea,
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - just send the file
*/
-function page_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function page_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
require_once("$CFG->libdir/resourcelib.php");
@@ -418,7 +419,7 @@ function page_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa
}
// finally send the file
- send_stored_file($file, 86400, 0, $forcedownload);
+ send_stored_file($file, 86400, 0, $forcedownload, $options);
}
}
diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 4f0bc18e666d1..004487fea6285 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1655,9 +1655,10 @@ function quiz_extend_settings_navigation($settings, $quiznode) {
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
-function quiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function quiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -1687,7 +1688,7 @@ function quiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
return false;
}
- send_stored_file($file, 0, 0, true);
+ send_stored_file($file, 0, 0, true, $options);
}
/**
@@ -1704,10 +1705,11 @@ function quiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa
* @param int $slot the id of a question in this quiz attempt.
* @param array $args the remaining bits of the file path.
* @param bool $forcedownload whether the user must be forced to download the file.
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
function mod_quiz_question_pluginfile($course, $context, $component,
- $filearea, $qubaid, $slot, $args, $forcedownload) {
+ $filearea, $qubaid, $slot, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
@@ -1739,7 +1741,7 @@ function mod_quiz_question_pluginfile($course, $context, $component,
send_file_not_found();
}
- send_stored_file($file, 0, 0, $forcedownload);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
diff --git a/mod/quiz/report/statistics/lib.php b/mod/quiz/report/statistics/lib.php
index 484b5a7c886c1..038d12a2bf089 100644
--- a/mod/quiz/report/statistics/lib.php
+++ b/mod/quiz/report/statistics/lib.php
@@ -35,8 +35,9 @@
* @param int $questionid the question id
* @param array $args remaining file args
* @param bool $forcedownload
+ * @param array $options additional options affecting the file serving
*/
-function quiz_statistics_questiontext_preview_pluginfile($context, $questionid, $args, $forcedownload) {
+function quiz_statistics_questiontext_preview_pluginfile($context, $questionid, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
@@ -47,7 +48,7 @@ function quiz_statistics_questiontext_preview_pluginfile($context, $questionid,
// validate questionid, becuase of the complexity of random quetsions.
require_capability('quiz/statistics:view', $context);
- question_send_questiontext_file($questionid, $args, $forcedownload);
+ question_send_questiontext_file($questionid, $args, $forcedownload, $options);
}
/**
diff --git a/mod/resource/lib.php b/mod/resource/lib.php
index 2b109b60e2220..978f2048c5413 100644
--- a/mod/resource/lib.php
+++ b/mod/resource/lib.php
@@ -382,9 +382,10 @@ function resource_get_file_info($browser, $areas, $course, $cm, $context, $filea
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - just send the file
*/
-function resource_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function resource_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG, $DB;
require_once("$CFG->libdir/resourcelib.php");
@@ -443,7 +444,7 @@ function resource_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
}
// finally send the file
- send_stored_file($file, 86400, $filter, $forcedownload);
+ send_stored_file($file, 86400, $filter, $forcedownload, $options);
}
/**
diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php
index 2ad8a133713f0..98490316dc1df 100644
--- a/mod/scorm/lib.php
+++ b/mod/scorm/lib.php
@@ -927,9 +927,10 @@ function scorm_get_file_info($browser, $areas, $course, $cm, $context, $filearea
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - just send the file
*/
-function scorm_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function scorm_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -968,7 +969,7 @@ function scorm_pluginfile($course, $cm, $context, $filearea, $args, $forcedownlo
}
// finally send the file
- send_stored_file($file, $lifetime, 0, false);
+ send_stored_file($file, $lifetime, 0, false, $options);
}
/**
diff --git a/mod/upgrade.txt b/mod/upgrade.txt
index 62b3918fccc55..3419e8200a743 100644
--- a/mod/upgrade.txt
+++ b/mod/upgrade.txt
@@ -7,6 +7,9 @@ information provided here is intended especially for developers.
required changes in code:
* define the capability mod/xxx:addinstance (and the corresponding lang string)
(unless your mod is a MOD_ARCHETYPE_SYSTEM).
+* xxx_pluginfile() is now given the 7th parameter (hopefully the last one) that
+ contains additional options for the file serving. The array should be re-passed
+ to send_stored_file().
=== 2.2 ===
diff --git a/mod/wiki/lib.php b/mod/wiki/lib.php
index 9dbd3f110e8ad..ff84aeaab4631 100644
--- a/mod/wiki/lib.php
+++ b/mod/wiki/lib.php
@@ -445,8 +445,10 @@ function wiki_scale_used_anywhere($scaleid) {
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
+ * @return bool false if the file was not found, just send the file otherwise and do not return anything
*/
-function wiki_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function wiki_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -477,7 +479,7 @@ function wiki_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa
$lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
- send_stored_file($file, $lifetime, 0);
+ send_stored_file($file, $lifetime, 0, $options);
}
}
diff --git a/mod/workshop/form/accumulative/lib.php b/mod/workshop/form/accumulative/lib.php
index 2a266281c009e..6a3a54db808be 100644
--- a/mod/workshop/form/accumulative/lib.php
+++ b/mod/workshop/form/accumulative/lib.php
@@ -38,9 +38,10 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function workshopform_accumulative_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload) {
+function workshopform_accumulative_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -72,7 +73,7 @@ function workshopform_accumulative_pluginfile($course, $cm, $context, $filearea,
}
// finally send the file
- send_stored_file($file);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
diff --git a/mod/workshop/form/comments/lib.php b/mod/workshop/form/comments/lib.php
index 1e7723f1059bd..408ecf427457e 100644
--- a/mod/workshop/form/comments/lib.php
+++ b/mod/workshop/form/comments/lib.php
@@ -38,9 +38,10 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function workshopform_comments_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload) {
+function workshopform_comments_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -72,7 +73,7 @@ function workshopform_comments_pluginfile($course, $cm, $context, $filearea, arr
}
// finally send the file
- send_stored_file($file);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
diff --git a/mod/workshop/form/numerrors/lib.php b/mod/workshop/form/numerrors/lib.php
index 2fd0ce905499a..3e461dd88a360 100644
--- a/mod/workshop/form/numerrors/lib.php
+++ b/mod/workshop/form/numerrors/lib.php
@@ -38,9 +38,10 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function workshopform_numerrors_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload) {
+function workshopform_numerrors_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -72,7 +73,7 @@ function workshopform_numerrors_pluginfile($course, $cm, $context, $filearea, ar
}
// finally send the file
- send_stored_file($file);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
diff --git a/mod/workshop/form/rubric/lib.php b/mod/workshop/form/rubric/lib.php
index 1361c66ebfb4d..eb6425d9f8dc9 100644
--- a/mod/workshop/form/rubric/lib.php
+++ b/mod/workshop/form/rubric/lib.php
@@ -38,9 +38,10 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function workshopform_rubric_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload) {
+function workshopform_rubric_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -72,7 +73,7 @@ function workshopform_rubric_pluginfile($course, $cm, $context, $filearea, array
}
// finally send the file
- send_stored_file($file);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
diff --git a/mod/workshop/lib.php b/mod/workshop/lib.php
index 7dc9a6e35b16f..655c5ddc39c92 100644
--- a/mod/workshop/lib.php
+++ b/mod/workshop/lib.php
@@ -1221,15 +1221,16 @@ function workshop_get_file_areas($course, $cm, $context) {
* @package mod_workshop
* @category files
*
- * @param stdClass $course
- * @param stdClass $cm
- * @param stdClass $context
- * @param string $filearea
- * @param array $args
- * @param bool $forcedownload
- * @return void this should never return to the caller
+ * @param stdClass $course the course object
+ * @param stdClass $cm the course module object
+ * @param stdClass $context the workshop's context
+ * @param string $filearea the name of the file area
+ * @param array $args extra arguments (itemid, path)
+ * @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
+ * @return bool false if the file not found, just send the file otherwise and do not return anything
*/
-function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload) {
+function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) {
global $DB, $CFG;
if ($context->contextlevel != CONTEXT_MODULE) {
@@ -1246,7 +1247,7 @@ function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $fo
array_shift($args); // we do not use itemids here
$relativepath = implode('/', $args);
- $fullpath = "/$context->id/mod_workshop/$filearea/0/$relativepath"; // beware, slashes are not used here!
+ $fullpath = "/$context->id/mod_workshop/$filearea/0/$relativepath";
$fs = get_file_storage();
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
@@ -1256,7 +1257,7 @@ function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $fo
$lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
// finally send the file
- send_stored_file($file, $lifetime, 0);
+ send_stored_file($file, $lifetime, 0, $forcedownload, $options);
}
if ($filearea === 'instructreviewers') {
@@ -1277,7 +1278,7 @@ function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $fo
$lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
// finally send the file
- send_stored_file($file, $lifetime, 0);
+ send_stored_file($file, $lifetime, 0, $forcedownload, $options);
} else if ($filearea === 'submission_content' or $filearea === 'submission_attachment') {
$itemid = (int)array_shift($args);
@@ -1296,7 +1297,7 @@ function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $fo
}
// finally send the file
// these files are uploaded by students - forcing download for security reasons
- send_stored_file($file, 0, 0, true);
+ send_stored_file($file, 0, 0, true, $options);
}
return false;
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index f0838ee6ba82f..be46f6bf50573 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -29,6 +29,9 @@
lib/ajax/tests
lib/form/tests
+
+ lib/filestorage/tests
+
lib/grade/tests
grade/tests
diff --git a/pluginfile.php b/pluginfile.php
index fd187ceb9edb9..8ace6bd0f88da 100644
--- a/pluginfile.php
+++ b/pluginfile.php
@@ -33,5 +33,6 @@
$relativepath = get_file_argument();
$forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
+$preview = optional_param('preview', null, PARAM_ALPHANUM);
-file_pluginfile($relativepath, $forcedownload);
+file_pluginfile($relativepath, $forcedownload, $preview);
diff --git a/question/previewlib.php b/question/previewlib.php
index 3bf47b26c12b6..c3ffc191c30bc 100644
--- a/question/previewlib.php
+++ b/question/previewlib.php
@@ -224,10 +224,11 @@ public function get_url_params() {
* @param int $slot the relevant slot within the usage.
* @param array $args the remaining bits of the file path.
* @param bool $forcedownload whether the user must be forced to download the file.
+ * @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
function question_preview_question_pluginfile($course, $context, $component,
- $filearea, $qubaid, $slot, $args, $forcedownload) {
+ $filearea, $qubaid, $slot, $args, $forcedownload, $options) {
global $USER, $DB, $CFG;
$quba = question_engine::load_questions_usage_by_activity($qubaid);
@@ -255,7 +256,7 @@ function question_preview_question_pluginfile($course, $context, $component,
send_file_not_found();
}
- send_stored_file($file, 0, 0, $forcedownload);
+ send_stored_file($file, 0, 0, $forcedownload, $options);
}
/**
diff --git a/question/type/calculated/lib.php b/question/type/calculated/lib.php
index ca7559ae8befb..57ba58f37e833 100644
--- a/question/type/calculated/lib.php
+++ b/question/type/calculated/lib.php
@@ -38,10 +38,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_calculated_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_calculated_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_calculated', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_calculated', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/calculatedmulti/lib.php b/question/type/calculatedmulti/lib.php
index f78a1668a8c3c..d91370f0c2388 100644
--- a/question/type/calculatedmulti/lib.php
+++ b/question/type/calculatedmulti/lib.php
@@ -38,12 +38,13 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
function qtype_calculatedmulti_pluginfile($course, $cm, $context, $filearea, $args,
- $forcedownload) {
+ $forcedownload, array $options=array()) {
global $DB, $CFG;
require_once($CFG->libdir . '/questionlib.php');
question_pluginfile($course, $context, 'qtype_calculatedmulti', $filearea, $args,
- $forcedownload);
+ $forcedownload, $options);
}
diff --git a/question/type/calculatedsimple/lib.php b/question/type/calculatedsimple/lib.php
index d95bddbbe4cf2..4002e965b65ac 100644
--- a/question/type/calculatedsimple/lib.php
+++ b/question/type/calculatedsimple/lib.php
@@ -39,12 +39,13 @@
* @param string $filearea
* @param array $args
* @param bool $forcedownload
+ * @param array $options additional options affecting the file serving
* @return bool
*/
function qtype_calculatedsimple_pluginfile($course, $cm, $context, $filearea,
- $args, $forcedownload) {
+ $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
question_pluginfile($course, $context, 'qtype_calculatedsimple', $filearea,
- $args, $forcedownload);
+ $args, $forcedownload, $options);
}
diff --git a/question/type/essay/lib.php b/question/type/essay/lib.php
index 38e6557f653b8..0aa4551797cda 100644
--- a/question/type/essay/lib.php
+++ b/question/type/essay/lib.php
@@ -38,10 +38,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_essay_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_essay_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_essay', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_essay', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/match/lib.php b/question/type/match/lib.php
index f997cc41f6ce7..ff31bc4ec23fd 100644
--- a/question/type/match/lib.php
+++ b/question/type/match/lib.php
@@ -37,10 +37,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_match_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_match_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $DB, $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_match', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_match', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/multichoice/lib.php b/question/type/multichoice/lib.php
index 2b0b8857a9c96..9d5b0e20cb8ee 100644
--- a/question/type/multichoice/lib.php
+++ b/question/type/multichoice/lib.php
@@ -38,10 +38,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_multichoice_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_multichoice_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_multichoice', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_multichoice', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/numerical/lib.php b/question/type/numerical/lib.php
index e31de0adafa71..b1b4ec2669398 100644
--- a/question/type/numerical/lib.php
+++ b/question/type/numerical/lib.php
@@ -38,10 +38,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_numerical_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_numerical_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_numerical', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_numerical', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/shortanswer/lib.php b/question/type/shortanswer/lib.php
index e508d68a6414e..606085aab654d 100644
--- a/question/type/shortanswer/lib.php
+++ b/question/type/shortanswer/lib.php
@@ -37,10 +37,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_shortanswer_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_shortanswer_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $DB, $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_shortanswer', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_shortanswer', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/truefalse/lib.php b/question/type/truefalse/lib.php
index a3c4620c4233a..2e71c33be0aa2 100644
--- a/question/type/truefalse/lib.php
+++ b/question/type/truefalse/lib.php
@@ -37,10 +37,11 @@
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
* @return bool
*/
-function qtype_truefalse_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
+function qtype_truefalse_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
- question_pluginfile($course, $context, 'qtype_truefalse', $filearea, $args, $forcedownload);
+ question_pluginfile($course, $context, 'qtype_truefalse', $filearea, $args, $forcedownload, $options);
}
diff --git a/question/type/upgrade.txt b/question/type/upgrade.txt
index 0281c6f08a03a..f399642cdc234 100644
--- a/question/type/upgrade.txt
+++ b/question/type/upgrade.txt
@@ -7,6 +7,9 @@ This files describes API changes for question type plugins.
import and export, then you will probably get PHP strict syntax notices in developer
debug mode until you change the method signature to include qformat_xml $format.
That is, you need to specify the argument type.
+* qtype_xxx_pluginfile() is now given the 7th parameter (hopefully the last
+ one) that contains additional options for the file serving. The array should
+ be re-passed to question_pluginfile() as is.
=== 2.2 ===