Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 232 lines (202 sloc) 9.17 KB
<?php // $Id: file.php,v 1.46.2.5 2009/04/09 09:30:32 skodak Exp $
// This script fetches files from the dataroot directory
//
// You should use the get_file_url() function, available in lib/filelib.php, to link to file.php.
// This ensures proper formatting and offers useful options.
//
// Syntax: file.php/courseid/dir/dir/dir/filename.ext
// file.php/courseid/dir/dir/dir/filename.ext?forcedownload=1 (download instead of inline)
// file.php/courseid/dir (returns index.html from dir)
// Workaround: file.php?file=/courseid/dir/dir/dir/filename.ext
// Test: file.php/testslasharguments
//TODO: Blog attachments do not have access control implemented - anybody can read them!
// It might be better to move the code to separate file because the access
// control is quite complex - see bolg/index.php
require_once('config.php');
require_once('lib/filelib.php');
require_once($CFG->dirroot . '/files/model/manager.php');
require_once($CFG->dirroot . '/repository/manager.php');
if (!isset($CFG->filelifetime)) {
$lifetime = 86400; // Seconds for files to remain in caches
} else {
$lifetime = $CFG->filelifetime;
}
// disable moodle specific debug messages
disable_debugging();
$relativepath = rawurldecode(get_file_argument('file.php'));
$forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
$modelmanager = files_model_manager::get_instance();
// relative path must start with '/', because of backup/restore!!!
if (!$relativepath) {
error('No valid arguments supplied or incorrect server configuration');
} else if ($relativepath{0} != '/') {
error('No valid arguments supplied, path does not start with slash!');
}
if (preg_match('/^\/([0-9]+)$/', $relativepath, $matches)) {
$fileid = $matches[1];
$file = $modelmanager->get_file($fileid);
if ($file && $file->can_download($USER->id)) {
session_write_close();
$file->download(true);
} else {
error('File not found');
}
}
$pathname = $CFG->dataroot.$relativepath;
// extract relative path components
$args = array_filter(explode('/', trim($relativepath, '/')));
if (count($args) == 0) { // always at least courseid, may search for index.html in course root
error('No valid arguments supplied');
}
// security: limit access to existing course subdirectories
if (($args[0]!='blog' && $args[0]!='userfiles') and (!$course = get_record_sql("SELECT * FROM {$CFG->prefix}course WHERE id='".(int)$args[0]."'"))) {
error('Invalid course ID');
}
// security: prevent access to "000" or "1 something" directories
// hack for blogs, needs proper security check too
if (($args[0] != 'blog' && $args[0]!='userfiles') and ($args[0] != $course->id)) {
error('Invalid course ID');
}
// security: login to course if necessary
// Note: file.php always calls require_login() with $setwantsurltome=false
// in order to avoid messing redirects. MDL-14495
if ($args[0] == 'blog') {
if (empty($CFG->bloglevel)) {
error('Blogging is disabled!');
} else if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) {
require_login(0, true, null, false);
} else if ($CFG->forcelogin) {
require_login(0, true, null, false);
}
} else if ($args[0] == 'userfiles') {
if ($USER->id != $args[1]) {
error('Access not allowed');
}
} else if ($course->id != SITEID) {
require_login($course->id, true, null, false);
} else if ($CFG->forcelogin) {
if (!empty($CFG->sitepolicy)
and ($CFG->sitepolicy == $CFG->wwwroot.'/file.php'.$relativepath
or $CFG->sitepolicy == $CFG->wwwroot.'/file.php?file='.$relativepath)) {
//do not require login for policy file
} else {
require_login(0, true, null, false);
}
}
// security: only editing teachers can access backups
if ((count($args) >= 2) and (strtolower($args[1]) == 'backupdata')) {
if (!has_capability('moodle/site:backup', get_context_instance(CONTEXT_COURSE, $course->id))) {
error('Access not allowed');
} else {
$lifetime = 0; //disable browser caching for backups
}
}
if (is_dir($pathname)) {
if (file_exists($pathname.'/index.html')) {
$pathname = rtrim($pathname, '/').'/index.html';
$args[] = 'index.html';
} else if (file_exists($pathname.'/index.htm')) {
$pathname = rtrim($pathname, '/').'/index.htm';
$args[] = 'index.htm';
} else if (file_exists($pathname.'/Default.htm')) {
$pathname = rtrim($pathname, '/').'/Default.htm';
$args[] = 'Default.htm';
} else {
// security: do not return directory node!
not_found($course->id);
}
}
// security: teachers can view all assignments, students only their own
if ((count($args) >= 3)
and (strtolower($args[1]) == 'moddata')
and (strtolower($args[2]) == 'assignment')) {
$lifetime = 0; // do not cache assignments, students may reupload them
if ($args[4] == $USER->id) {
//can view own assignemnt submissions
} else {
$instance = (int)$args[3];
if (!$cm = get_coursemodule_from_instance('assignment', $instance, $course->id)) {
not_found($course->id);
}
if (!has_capability('mod/assignment:grade', get_context_instance(CONTEXT_MODULE, $cm->id))) {
error('Access not allowed');
}
}
}
// Check to see if the file is actually in the course folder or is a reference.
$realpath = false;
if (in_array($args[1], array('moddata', 'backupdata'))) {
$realpath = true;
}
// security: force download of all attachments submitted by students
if (count($args) >= 3 and strtolower($args[1]) === 'moddata') {
$mod = clean_param($args[2], PARAM_SAFEDIR);
if (file_exists("$CFG->dirroot/mod/$mod/lib.php")) {
if (!$forcedownload) {
require_once("$CFG->dirroot/mod/$mod/lib.php");
$trustedfunction = $mod.'_is_moddata_trusted';
if (function_exists($trustedfunction)) {
// force download of all attachments that are not trusted
$forcedownload = !$trustedfunction();
} else {
$forcedownload = 1;
}
}
} else {
// module is not installed - better not serve file at all
not_found($course->id);
}
}
if ($args[0] == 'blog') {
$forcedownload = 1; // force download of all attachments
}
// security: some protection of hidden resource files
// warning: it may break backwards compatibility
if ((!empty($CFG->preventaccesstohiddenfiles))
and (count($args) >= 2)
and (!(strtolower($args[1]) == 'moddata' and strtolower($args[2]) != 'resource')) // do not block files from other modules!
and (!has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_COURSE, $course->id)))) {
$rargs = $args;
array_shift($rargs);
$reference = implode('/', $rargs);
$sql = "SELECT COUNT(r.id) " .
"FROM {$CFG->prefix}resource r, " .
"{$CFG->prefix}course_modules cm, " .
"{$CFG->prefix}modules m " .
"WHERE r.course = '{$course->id}' " .
"AND m.name = 'resource' " .
"AND cm.module = m.id " .
"AND cm.instance = r.id " .
"AND cm.visible = 0 " .
"AND r.type = 'file' " .
"AND r.reference = '{$reference}'";
if (count_records_sql($sql)) {
error('Access not allowed');
}
}
// ========================================
// finally send the file
// ========================================
if ($realpath) {
// check that file exists
if (!file_exists($pathname)) {
not_found($course->id);
}
session_write_close(); // unlock session during fileserving
$filename = $args[count($args)-1];
send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
} else {
$file = $modelmanager->get_model_by_path($relativepath, 'file');
// check that path exists in database
if (!($file->is_loaded() && $file->can_download($USER->id))) {
not_found((isset($course) ? $course->id : 1));
}
session_write_close(); // unlock session during fileserving
$file->download($forcedownload);
}
function not_found($courseid) {
global $CFG;
header('HTTP/1.0 404 not found');
print_error('filenotfound', 'error', $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
}
?>