Merge branch 'MDL-32471-thumbnails' of git://github.com/mudrd8mz/moodle

This commit is contained in:
Eloy Lafuente (stronk7)
2012-04-25 15:14:27 +02:00
47 changed files with 575 additions and 182 deletions
+3 -2
View File
@@ -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);
}
/**
+6
View File
@@ -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 ===
+71 -36
View File
@@ -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 @@ class filetype_parser {
*
* @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();
+126
View File
@@ -152,6 +152,113 @@ class file_storage {
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 @@ class file_storage {
$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) {
@@ -0,0 +1,80 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for /lib/filestorage/file_storage.php
*
* @package core
* @category test
* @copyright 2012 David Mudrak <[email protected]>
* @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());
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

+139 -53
View File
@@ -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;
}
+2 -2
View File
@@ -822,8 +822,8 @@ abstract class portfolio_plugin_pull_base extends portfolio_plugin_base {
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();
}
+11 -8
View File
@@ -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);
}
/**
+3
View File
@@ -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:
+8 -3
View File
@@ -1979,11 +1979,15 @@ class assignment_base {
}
/**
* 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
@@ -375,7 +375,7 @@ class assignment_online extends assignment_base {
}
}
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 @@ class assignment_online extends assignment_base {
}
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);
}
/**
+7
View File
@@ -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
@@ -614,7 +614,7 @@ class assignment_upload extends assignment_base {
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 @@ class assignment_upload extends assignment_base {
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 @@ class assignment_upload extends assignment_base {
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;
@@ -300,7 +300,7 @@ class assignment_uploadsingle extends assignment_base {
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 @@ class assignment_uploadsingle extends assignment_base {
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) {
+3 -2
View File
@@ -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;
+3 -2
View File
@@ -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;
}
+3 -2
View File
@@ -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);
}
/**
+3 -3
View File
@@ -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!
}
/**
+3 -2
View File
@@ -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);
+4 -3
View File
@@ -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;
+3 -2
View File
@@ -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!
}
/**
+3 -2
View File
@@ -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);
}
}
+6 -4
View File
@@ -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);
}
/**
+3 -2
View File
@@ -35,8 +35,9 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
/**
+3 -2
View File
@@ -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);
}
/**
+3 -2
View File
@@ -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);
}
/**
+3
View File
@@ -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 ===
+4 -2
View File
@@ -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);
}
}
+3 -2
View File
@@ -38,9 +38,10 @@ require_once($CFG->libdir . '/gradelib.php'); // to handle float vs de
* @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);
}
/**
+3 -2
View File
@@ -38,9 +38,10 @@ require_once($CFG->libdir . '/gradelib.php'); // to handle float vs de
* @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);
}
/**
+3 -2
View File
@@ -38,9 +38,10 @@ require_once($CFG->libdir . '/gradelib.php'); // to handle float vs de
* @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);
}
/**
+3 -2
View File
@@ -38,9 +38,10 @@ require_once($CFG->libdir . '/gradelib.php'); // to handle float vs de
* @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);
}
/**
+13 -12
View File
@@ -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;
+3
View File
@@ -29,6 +29,9 @@
<directory suffix="_test.php">lib/ajax/tests</directory>
<directory suffix="_test.php">lib/form/tests</directory>
</testsuite>
<testsuite name="core_files">
<directory suffix="_test.php">lib/filestorage/tests</directory>
</testsuite>
<testsuite name="core_grade">
<directory suffix="_test.php">lib/grade/tests</directory>
<directory suffix="_test.php">grade/tests</directory>
+2 -1
View File
@@ -33,5 +33,6 @@ require_once('lib/filelib.php');
$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);
+3 -2
View File
@@ -224,10 +224,11 @@ class question_preview_options extends question_display_options {
* @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);
}
/**
+3 -2
View File
@@ -38,10 +38,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -38,12 +38,13 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -39,12 +39,13 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -38,10 +38,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -37,10 +37,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -38,10 +38,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -38,10 +38,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -37,10 +37,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3 -2
View File
@@ -37,10 +37,11 @@ defined('MOODLE_INTERNAL') || die();
* @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);
}
+3
View File
@@ -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 ===