|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00027 defined('MOODLE_INTERNAL') || die(); 00028 00030 define('BYTESERVING_BOUNDARY', 's1k2o3d4a5k6s7'); 00031 00032 require_once("$CFG->libdir/filestorage/file_exceptions.php"); 00033 require_once("$CFG->libdir/filestorage/file_storage.php"); 00034 require_once("$CFG->libdir/filestorage/zip_packer.php"); 00035 require_once("$CFG->libdir/filebrowser/file_browser.php"); 00036 00049 function file_encode_url($urlbase, $path, $forcedownload=false, $https=false) { 00050 global $CFG; 00051 00052 //TODO: deprecate this 00053 00054 if ($CFG->slasharguments) { 00055 $parts = explode('/', $path); 00056 $parts = array_map('rawurlencode', $parts); 00057 $path = implode('/', $parts); 00058 $return = $urlbase.$path; 00059 if ($forcedownload) { 00060 $return .= '?forcedownload=1'; 00061 } 00062 } else { 00063 $path = rawurlencode($path); 00064 $return = $urlbase.'?file='.$path; 00065 if ($forcedownload) { 00066 $return .= '&forcedownload=1'; 00067 } 00068 } 00069 00070 if ($https) { 00071 $return = str_replace('http://', 'https://', $return); 00072 } 00073 00074 return $return; 00075 } 00076 00096 function file_prepare_standard_editor($data, $field, array $options, $context=null, $component=null, $filearea=null, $itemid=null) { 00097 $options = (array)$options; 00098 if (!isset($options['trusttext'])) { 00099 $options['trusttext'] = false; 00100 } 00101 if (!isset($options['forcehttps'])) { 00102 $options['forcehttps'] = false; 00103 } 00104 if (!isset($options['subdirs'])) { 00105 $options['subdirs'] = false; 00106 } 00107 if (!isset($options['maxfiles'])) { 00108 $options['maxfiles'] = 0; // no files by default 00109 } 00110 if (!isset($options['noclean'])) { 00111 $options['noclean'] = false; 00112 } 00113 00114 //sanity check for passed context. This function doesn't expect $option['context'] to be set 00115 //But this function is called before creating editor hence, this is one of the best places to check 00116 //if context is used properly. This check notify developer that they missed passing context to editor. 00117 if (isset($context) && !isset($options['context'])) { 00118 //if $context is not null then make sure $option['context'] is also set. 00119 debugging('Context for editor is not set in editoroptions. Hence editor will not respect editor filters', DEBUG_DEVELOPER); 00120 } else if (isset($options['context']) && isset($context)) { 00121 //If both are passed then they should be equal. 00122 if ($options['context']->id != $context->id) { 00123 $exceptionmsg = 'Editor context ['.$options['context']->id.'] is not equal to passed context ['.$context->id.']'; 00124 throw new coding_exception($exceptionmsg); 00125 } 00126 } 00127 00128 if (is_null($itemid) or is_null($context)) { 00129 $contextid = null; 00130 $itemid = null; 00131 if (!isset($data)) { 00132 $data = new stdClass(); 00133 } 00134 if (!isset($data->{$field})) { 00135 $data->{$field} = ''; 00136 } 00137 if (!isset($data->{$field.'format'})) { 00138 $data->{$field.'format'} = editors_get_preferred_format(); 00139 } 00140 if (!$options['noclean']) { 00141 $data->{$field} = clean_text($data->{$field}, $data->{$field.'format'}); 00142 } 00143 00144 } else { 00145 if ($options['trusttext']) { 00146 // noclean ignored if trusttext enabled 00147 if (!isset($data->{$field.'trust'})) { 00148 $data->{$field.'trust'} = 0; 00149 } 00150 $data = trusttext_pre_edit($data, $field, $context); 00151 } else { 00152 if (!$options['noclean']) { 00153 $data->{$field} = clean_text($data->{$field}, $data->{$field.'format'}); 00154 } 00155 } 00156 $contextid = $context->id; 00157 } 00158 00159 if ($options['maxfiles'] != 0) { 00160 $draftid_editor = file_get_submitted_draft_itemid($field); 00161 $currenttext = file_prepare_draft_area($draftid_editor, $contextid, $component, $filearea, $itemid, $options, $data->{$field}); 00162 $data->{$field.'_editor'} = array('text'=>$currenttext, 'format'=>$data->{$field.'format'}, 'itemid'=>$draftid_editor); 00163 } else { 00164 $data->{$field.'_editor'} = array('text'=>$data->{$field}, 'format'=>$data->{$field.'format'}, 'itemid'=>0); 00165 } 00166 00167 return $data; 00168 } 00169 00190 function file_postupdate_standard_editor($data, $field, array $options, $context, $component=null, $filearea=null, $itemid=null) { 00191 $options = (array)$options; 00192 if (!isset($options['trusttext'])) { 00193 $options['trusttext'] = false; 00194 } 00195 if (!isset($options['forcehttps'])) { 00196 $options['forcehttps'] = false; 00197 } 00198 if (!isset($options['subdirs'])) { 00199 $options['subdirs'] = false; 00200 } 00201 if (!isset($options['maxfiles'])) { 00202 $options['maxfiles'] = 0; // no files by default 00203 } 00204 if (!isset($options['maxbytes'])) { 00205 $options['maxbytes'] = 0; // unlimited 00206 } 00207 00208 if ($options['trusttext']) { 00209 $data->{$field.'trust'} = trusttext_trusted($context); 00210 } else { 00211 $data->{$field.'trust'} = 0; 00212 } 00213 00214 $editor = $data->{$field.'_editor'}; 00215 00216 if ($options['maxfiles'] == 0 or is_null($filearea) or is_null($itemid) or empty($editor['itemid'])) { 00217 $data->{$field} = $editor['text']; 00218 } else { 00219 $data->{$field} = file_save_draft_area_files($editor['itemid'], $context->id, $component, $filearea, $itemid, $options, $editor['text'], $options['forcehttps']); 00220 } 00221 $data->{$field.'format'} = $editor['format']; 00222 00223 return $data; 00224 } 00225 00238 function file_prepare_standard_filemanager($data, $field, array $options, $context=null, $component=null, $filearea=null, $itemid=null) { 00239 $options = (array)$options; 00240 if (!isset($options['subdirs'])) { 00241 $options['subdirs'] = false; 00242 } 00243 if (is_null($itemid) or is_null($context)) { 00244 $itemid = null; 00245 $contextid = null; 00246 } else { 00247 $contextid = $context->id; 00248 } 00249 00250 $draftid_editor = file_get_submitted_draft_itemid($field.'_filemanager'); 00251 file_prepare_draft_area($draftid_editor, $contextid, $component, $filearea, $itemid, $options); 00252 $data->{$field.'_filemanager'} = $draftid_editor; 00253 00254 return $data; 00255 } 00256 00269 function file_postupdate_standard_filemanager($data, $field, array $options, $context, $component, $filearea, $itemid) { 00270 $options = (array)$options; 00271 if (!isset($options['subdirs'])) { 00272 $options['subdirs'] = false; 00273 } 00274 if (!isset($options['maxfiles'])) { 00275 $options['maxfiles'] = -1; // unlimited 00276 } 00277 if (!isset($options['maxbytes'])) { 00278 $options['maxbytes'] = 0; // unlimited 00279 } 00280 00281 if (empty($data->{$field.'_filemanager'})) { 00282 $data->$field = ''; 00283 00284 } else { 00285 file_save_draft_area_files($data->{$field.'_filemanager'}, $context->id, $component, $filearea, $itemid, $options); 00286 $fs = get_file_storage(); 00287 00288 if ($fs->get_area_files($context->id, $component, $filearea, $itemid)) { 00289 $data->$field = '1'; // TODO: this is an ugly hack (skodak) 00290 } else { 00291 $data->$field = ''; 00292 } 00293 } 00294 00295 return $data; 00296 } 00297 00305 function file_get_unused_draft_itemid() { 00306 global $DB, $USER; 00307 00308 if (isguestuser() or !isloggedin()) { 00309 // guests and not-logged-in users can not be allowed to upload anything!!!!!! 00310 print_error('noguest'); 00311 } 00312 00313 $contextid = get_context_instance(CONTEXT_USER, $USER->id)->id; 00314 00315 $fs = get_file_storage(); 00316 $draftitemid = rand(1, 999999999); 00317 while ($files = $fs->get_area_files($contextid, 'user', 'draft', $draftitemid)) { 00318 $draftitemid = rand(1, 999999999); 00319 } 00320 00321 return $draftitemid; 00322 } 00323 00340 function file_prepare_draft_area(&$draftitemid, $contextid, $component, $filearea, $itemid, array $options=null, $text=null) { 00341 global $CFG, $USER, $CFG; 00342 00343 $options = (array)$options; 00344 if (!isset($options['subdirs'])) { 00345 $options['subdirs'] = false; 00346 } 00347 if (!isset($options['forcehttps'])) { 00348 $options['forcehttps'] = false; 00349 } 00350 00351 $usercontext = get_context_instance(CONTEXT_USER, $USER->id); 00352 $fs = get_file_storage(); 00353 00354 if (empty($draftitemid)) { 00355 // create a new area and copy existing files into 00356 $draftitemid = file_get_unused_draft_itemid(); 00357 $file_record = array('contextid'=>$usercontext->id, 'component'=>'user', 'filearea'=>'draft', 'itemid'=>$draftitemid); 00358 if (!is_null($itemid) and $files = $fs->get_area_files($contextid, $component, $filearea, $itemid)) { 00359 foreach ($files as $file) { 00360 if ($file->is_directory() and $file->get_filepath() === '/') { 00361 // we need a way to mark the age of each draft area, 00362 // by not copying the root dir we force it to be created automatically with current timestamp 00363 continue; 00364 } 00365 if (!$options['subdirs'] and ($file->is_directory() or $file->get_filepath() !== '/')) { 00366 continue; 00367 } 00368 $fs->create_file_from_storedfile($file_record, $file); 00369 } 00370 } 00371 if (!is_null($text)) { 00372 // at this point there should not be any draftfile links yet, 00373 // because this is a new text from database that should still contain the @@pluginfile@@ links 00374 // this happens when developers forget to post process the text 00375 $text = str_replace("\"$CFG->httpswwwroot/draftfile.php", "\"$CFG->httpswwwroot/brokenfile.php#", $text); 00376 } 00377 } else { 00378 // nothing to do 00379 } 00380 00381 if (is_null($text)) { 00382 return null; 00383 } 00384 00385 // relink embedded files - editor can not handle @@PLUGINFILE@@ ! 00386 return file_rewrite_pluginfile_urls($text, 'draftfile.php', $usercontext->id, 'user', 'draft', $draftitemid, $options); 00387 } 00388 00402 function file_rewrite_pluginfile_urls($text, $file, $contextid, $component, $filearea, $itemid, array $options=null) { 00403 global $CFG; 00404 00405 $options = (array)$options; 00406 if (!isset($options['forcehttps'])) { 00407 $options['forcehttps'] = false; 00408 } 00409 00410 if (!$CFG->slasharguments) { 00411 $file = $file . '?file='; 00412 } 00413 00414 $baseurl = "$CFG->wwwroot/$file/$contextid/$component/$filearea/"; 00415 00416 if ($itemid !== null) { 00417 $baseurl .= "$itemid/"; 00418 } 00419 00420 if ($options['forcehttps']) { 00421 $baseurl = str_replace('http://', 'https://', $baseurl); 00422 } 00423 00424 return str_replace('@@PLUGINFILE@@/', $baseurl, $text); 00425 } 00426 00437 function file_get_draft_area_info($draftitemid) { 00438 global $CFG, $USER; 00439 00440 $usercontext = get_context_instance(CONTEXT_USER, $USER->id); 00441 $fs = get_file_storage(); 00442 00443 $results = array(); 00444 00445 // The number of files 00446 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id', false); 00447 $results['filecount'] = count($draftfiles); 00448 $results['filesize'] = 0; 00449 foreach ($draftfiles as $file) { 00450 $results['filesize'] += $file->get_filesize(); 00451 } 00452 00453 return $results; 00454 } 00455 00460 function file_get_user_used_space() { 00461 global $DB, $USER; 00462 00463 $usercontext = get_context_instance(CONTEXT_USER, $USER->id); 00464 $sql = "SELECT SUM(files1.filesize) AS totalbytes FROM {files} files1 00465 JOIN (SELECT contenthash, filename, MAX(id) AS id 00466 FROM {files} 00467 WHERE contextid = ? AND component = ? AND filearea != ? 00468 GROUP BY contenthash, filename) files2 ON files1.id = files2.id"; 00469 $params = array('contextid'=>$usercontext->id, 'component'=>'user', 'filearea'=>'draft'); 00470 $record = $DB->get_record_sql($sql, $params); 00471 return (int)$record->totalbytes; 00472 } 00473 00479 function file_correct_filepath($str) { //TODO: what is this? (skodak) 00480 if ($str == '/' or empty($str)) { 00481 return '/'; 00482 } else { 00483 return '/'.trim($str, './@#$ ').'/'; 00484 } 00485 } 00486 00493 function file_get_drafarea_folders($draftitemid, $filepath, &$data) { 00494 global $USER, $OUTPUT, $CFG; 00495 $data->children = array(); 00496 $context = get_context_instance(CONTEXT_USER, $USER->id); 00497 $fs = get_file_storage(); 00498 if ($files = $fs->get_directory_files($context->id, 'user', 'draft', $draftitemid, $filepath, false)) { 00499 foreach ($files as $file) { 00500 if ($file->is_directory()) { 00501 $item = new stdClass(); 00502 $item->sortorder = $file->get_sortorder(); 00503 $item->filepath = $file->get_filepath(); 00504 00505 $foldername = explode('/', trim($item->filepath, '/')); 00506 $item->fullname = trim(array_pop($foldername), '/'); 00507 00508 $item->id = uniqid(); 00509 file_get_drafarea_folders($draftitemid, $item->filepath, $item); 00510 $data->children[] = $item; 00511 } else { 00512 continue; 00513 } 00514 } 00515 } 00516 } 00517 00525 function file_get_drafarea_files($draftitemid, $filepath = '/') { 00526 global $USER, $OUTPUT, $CFG; 00527 00528 $context = get_context_instance(CONTEXT_USER, $USER->id); 00529 $fs = get_file_storage(); 00530 00531 $data = new stdClass(); 00532 $data->path = array(); 00533 $data->path[] = array('name'=>get_string('files'), 'path'=>'/'); 00534 00535 // will be used to build breadcrumb 00536 $trail = ''; 00537 if ($filepath !== '/') { 00538 $filepath = file_correct_filepath($filepath); 00539 $parts = explode('/', $filepath); 00540 foreach ($parts as $part) { 00541 if ($part != '' && $part != null) { 00542 $trail .= ('/'.$part.'/'); 00543 $data->path[] = array('name'=>$part, 'path'=>$trail); 00544 } 00545 } 00546 } 00547 00548 $list = array(); 00549 $maxlength = 12; 00550 if ($files = $fs->get_directory_files($context->id, 'user', 'draft', $draftitemid, $filepath, false)) { 00551 foreach ($files as $file) { 00552 $item = new stdClass(); 00553 $item->filename = $file->get_filename(); 00554 $item->filepath = $file->get_filepath(); 00555 $item->fullname = trim($item->filename, '/'); 00556 $filesize = $file->get_filesize(); 00557 $item->filesize = $filesize ? display_size($filesize) : ''; 00558 00559 $icon = mimeinfo_from_type('icon', $file->get_mimetype()); 00560 $item->icon = $OUTPUT->pix_url('f/' . $icon)->out(); 00561 $item->sortorder = $file->get_sortorder(); 00562 00563 if ($icon == 'zip') { 00564 $item->type = 'zip'; 00565 } else { 00566 $item->type = 'file'; 00567 } 00568 00569 if ($file->is_directory()) { 00570 $item->filesize = 0; 00571 $item->icon = $OUTPUT->pix_url('f/folder')->out(); 00572 $item->type = 'folder'; 00573 $foldername = explode('/', trim($item->filepath, '/')); 00574 $item->fullname = trim(array_pop($foldername), '/'); 00575 } else { 00576 // do NOT use file browser here! 00577 $item->url = moodle_url::make_draftfile_url($draftitemid, $item->filepath, $item->filename)->out(); 00578 } 00579 $list[] = $item; 00580 } 00581 } 00582 $data->itemid = $draftitemid; 00583 $data->list = $list; 00584 return $data; 00585 } 00586 00593 function file_get_submitted_draft_itemid($elname) { 00594 // this is a nasty hack, ideally all new elements should use arrays here or there should be a new parameter 00595 if (!isset($_REQUEST[$elname])) { 00596 return 0; 00597 } 00598 if (is_array($_REQUEST[$elname])) { 00599 $param = optional_param_array($elname, 0, PARAM_INT); 00600 if (!empty($param['itemid'])) { 00601 $param = $param['itemid']; 00602 } else { 00603 debugging('Missing itemid, maybe caused by unset maxfiles option', DEBUG_DEVELOPER); 00604 return false; 00605 } 00606 00607 } else { 00608 $param = optional_param($elname, 0, PARAM_INT); 00609 } 00610 00611 if ($param) { 00612 require_sesskey(); 00613 } 00614 00615 return $param; 00616 } 00617 00636 function file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options=null, $text=null, $forcehttps=false) { 00637 global $USER; 00638 00639 $usercontext = get_context_instance(CONTEXT_USER, $USER->id); 00640 $fs = get_file_storage(); 00641 00642 $options = (array)$options; 00643 if (!isset($options['subdirs'])) { 00644 $options['subdirs'] = false; 00645 } 00646 if (!isset($options['maxfiles'])) { 00647 $options['maxfiles'] = -1; // unlimited 00648 } 00649 if (!isset($options['maxbytes'])) { 00650 $options['maxbytes'] = 0; // unlimited 00651 } 00652 00653 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id'); 00654 $oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id'); 00655 00656 if (count($draftfiles) < 2) { 00657 // means there are no files - one file means root dir only ;-) 00658 $fs->delete_area_files($contextid, $component, $filearea, $itemid); 00659 00660 } else if (count($oldfiles) < 2) { 00661 $filecount = 0; 00662 // there were no files before - one file means root dir only ;-) 00663 $file_record = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid); 00664 foreach ($draftfiles as $file) { 00665 if (!$options['subdirs']) { 00666 if ($file->get_filepath() !== '/' or $file->is_directory()) { 00667 continue; 00668 } 00669 } 00670 if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) { 00671 // oversized file - should not get here at all 00672 continue; 00673 } 00674 if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) { 00675 // more files - should not get here at all 00676 break; 00677 } 00678 if (!$file->is_directory()) { 00679 $filecount++; 00680 } 00681 $fs->create_file_from_storedfile($file_record, $file); 00682 } 00683 00684 } else { 00685 // we have to merge old and new files - we want to keep file ids for files that were not changed 00686 // we change time modified for all new and changed files, we keep time created as is 00687 $file_record = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'timemodified'=>time()); 00688 00689 $newhashes = array(); 00690 foreach ($draftfiles as $file) { 00691 $newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename()); 00692 $newhashes[$newhash] = $file; 00693 } 00694 $filecount = 0; 00695 foreach ($oldfiles as $oldfile) { 00696 $oldhash = $oldfile->get_pathnamehash(); 00697 if (!isset($newhashes[$oldhash])) { 00698 // delete files not needed any more - deleted by user 00699 $oldfile->delete(); 00700 continue; 00701 } 00702 $newfile = $newhashes[$oldhash]; 00703 if ($oldfile->get_contenthash() != $newfile->get_contenthash() or $oldfile->get_sortorder() != $newfile->get_sortorder() 00704 or $oldfile->get_status() != $newfile->get_status() or $oldfile->get_license() != $newfile->get_license() 00705 or $oldfile->get_author() != $newfile->get_author() or $oldfile->get_source() != $newfile->get_source()) { 00706 // file was changed, use updated with new timemodified data 00707 $oldfile->delete(); 00708 continue; 00709 } 00710 // unchanged file or directory - we keep it as is 00711 unset($newhashes[$oldhash]); 00712 if (!$oldfile->is_directory()) { 00713 $filecount++; 00714 } 00715 } 00716 00717 // now add new/changed files 00718 // the size and subdirectory tests are extra safety only, the UI should prevent it 00719 foreach ($newhashes as $file) { 00720 if (!$options['subdirs']) { 00721 if ($file->get_filepath() !== '/' or $file->is_directory()) { 00722 continue; 00723 } 00724 } 00725 if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) { 00726 // oversized file - should not get here at all 00727 continue; 00728 } 00729 if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) { 00730 // more files - should not get here at all 00731 break; 00732 } 00733 if (!$file->is_directory()) { 00734 $filecount++; 00735 } 00736 $fs->create_file_from_storedfile($file_record, $file); 00737 } 00738 } 00739 00740 // note: do not purge the draft area - we clean up areas later in cron, 00741 // the reason is that user might press submit twice and they would loose the files, 00742 // also sometimes we might want to use hacks that save files into two different areas 00743 00744 if (is_null($text)) { 00745 return null; 00746 } else { 00747 return file_rewrite_urls_to_pluginfile($text, $draftitemid, $forcehttps); 00748 } 00749 } 00750 00760 function file_rewrite_urls_to_pluginfile($text, $draftitemid, $forcehttps = false) { 00761 global $CFG, $USER; 00762 00763 $usercontext = get_context_instance(CONTEXT_USER, $USER->id); 00764 00765 $wwwroot = $CFG->wwwroot; 00766 if ($forcehttps) { 00767 $wwwroot = str_replace('http://', 'https://', $wwwroot); 00768 } 00769 00770 // relink embedded files if text submitted - no absolute links allowed in database! 00771 $text = str_ireplace("$wwwroot/draftfile.php/$usercontext->id/user/draft/$draftitemid/", '@@PLUGINFILE@@/', $text); 00772 00773 if (strpos($text, 'draftfile.php?file=') !== false) { 00774 $matches = array(); 00775 preg_match_all("!$wwwroot/draftfile.php\?file=%2F{$usercontext->id}%2Fuser%2Fdraft%2F{$draftitemid}%2F[^'\",&<>|`\s:\\\\]+!iu", $text, $matches); 00776 if ($matches) { 00777 foreach ($matches[0] as $match) { 00778 $replace = str_ireplace('%2F', '/', $match); 00779 $text = str_replace($match, $replace, $text); 00780 } 00781 } 00782 $text = str_ireplace("$wwwroot/draftfile.php?file=/$usercontext->id/user/draft/$draftitemid/", '@@PLUGINFILE@@/', $text); 00783 } 00784 00785 return $text; 00786 } 00787 00800 function file_set_sortorder($contextid, $component, $filearea, $itemid, $filepath, $filename, $sortorder) { 00801 global $DB; 00802 $conditions = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'filepath'=>$filepath, 'filename'=>$filename); 00803 if ($file_record = $DB->get_record('files', $conditions)) { 00804 $sortorder = (int)$sortorder; 00805 $file_record->sortorder = $sortorder; 00806 $DB->update_record('files', $file_record); 00807 return true; 00808 } 00809 return false; 00810 } 00811 00821 function file_reset_sortorder($contextid, $component, $filearea, $itemid=false) { 00822 global $DB; 00823 00824 $conditions = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea); 00825 if ($itemid !== false) { 00826 $conditions['itemid'] = $itemid; 00827 } 00828 00829 $file_records = $DB->get_records('files', $conditions); 00830 foreach ($file_records as $file_record) { 00831 $file_record->sortorder = 0; 00832 $DB->update_record('files', $file_record); 00833 } 00834 return true; 00835 } 00836 00843 function file_get_upload_error($errorcode) { 00844 00845 switch ($errorcode) { 00846 case 0: // UPLOAD_ERR_OK - no error 00847 $errmessage = ''; 00848 break; 00849 00850 case 1: // UPLOAD_ERR_INI_SIZE 00851 $errmessage = get_string('uploadserverlimit'); 00852 break; 00853 00854 case 2: // UPLOAD_ERR_FORM_SIZE 00855 $errmessage = get_string('uploadformlimit'); 00856 break; 00857 00858 case 3: // UPLOAD_ERR_PARTIAL 00859 $errmessage = get_string('uploadpartialfile'); 00860 break; 00861 00862 case 4: // UPLOAD_ERR_NO_FILE 00863 $errmessage = get_string('uploadnofilefound'); 00864 break; 00865 00866 // Note: there is no error with a value of 5 00867 00868 case 6: // UPLOAD_ERR_NO_TMP_DIR 00869 $errmessage = get_string('uploadnotempdir'); 00870 break; 00871 00872 case 7: // UPLOAD_ERR_CANT_WRITE 00873 $errmessage = get_string('uploadcantwrite'); 00874 break; 00875 00876 case 8: // UPLOAD_ERR_EXTENSION 00877 $errmessage = get_string('uploadextension'); 00878 break; 00879 00880 default: 00881 $errmessage = get_string('uploadproblem'); 00882 } 00883 00884 return $errmessage; 00885 } 00886 00894 function format_array_postdata_for_curlcall($arraydata, $currentdata, &$data) { 00895 foreach ($arraydata as $k=>$v) { 00896 $newcurrentdata = $currentdata; 00897 if (is_array($v)) { //the value is an array, call the function recursively 00898 $newcurrentdata = $newcurrentdata.'['.urlencode($k).']'; 00899 format_array_postdata_for_curlcall($v, $newcurrentdata, $data); 00900 } else { //add the POST parameter to the $data array 00901 $data[] = $newcurrentdata.'['.urlencode($k).']='.urlencode($v); 00902 } 00903 } 00904 } 00905 00912 function format_postdata_for_curlcall($postdata) { 00913 $data = array(); 00914 foreach ($postdata as $k=>$v) { 00915 if (is_array($v)) { 00916 $currentdata = urlencode($k); 00917 format_array_postdata_for_curlcall($v, $currentdata, $data); 00918 } else { 00919 $data[] = urlencode($k).'='.urlencode($v); 00920 } 00921 } 00922 $convertedpostdata = implode('&', $data); 00923 return $convertedpostdata; 00924 } 00925 00926 00927 00928 00951 function download_file_content($url, $headers=null, $postdata=null, $fullresponse=false, $timeout=300, $connecttimeout=20, $skipcertverify=false, $tofile=NULL, $calctimeout=false) { 00952 global $CFG; 00953 00954 // some extra security 00955 $newlines = array("\r", "\n"); 00956 if (is_array($headers) ) { 00957 foreach ($headers as $key => $value) { 00958 $headers[$key] = str_replace($newlines, '', $value); 00959 } 00960 } 00961 $url = str_replace($newlines, '', $url); 00962 if (!preg_match('|^https?://|i', $url)) { 00963 if ($fullresponse) { 00964 $response = new stdClass(); 00965 $response->status = 0; 00966 $response->headers = array(); 00967 $response->response_code = 'Invalid protocol specified in url'; 00968 $response->results = ''; 00969 $response->error = 'Invalid protocol specified in url'; 00970 return $response; 00971 } else { 00972 return false; 00973 } 00974 } 00975 00976 // check if proxy (if used) should be bypassed for this url 00977 $proxybypass = is_proxybypass($url); 00978 00979 if (!$ch = curl_init($url)) { 00980 debugging('Can not init curl.'); 00981 return false; 00982 } 00983 00984 // set extra headers 00985 if (is_array($headers) ) { 00986 $headers2 = array(); 00987 foreach ($headers as $key => $value) { 00988 $headers2[] = "$key: $value"; 00989 } 00990 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers2); 00991 } 00992 00993 if ($skipcertverify) { 00994 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 00995 } 00996 00997 // use POST if requested 00998 if (is_array($postdata)) { 00999 $postdata = format_postdata_for_curlcall($postdata); 01000 curl_setopt($ch, CURLOPT_POST, true); 01001 curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); 01002 } 01003 01004 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 01005 curl_setopt($ch, CURLOPT_HEADER, false); 01006 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connecttimeout); 01007 01008 if (!ini_get('open_basedir') and !ini_get('safe_mode')) { 01009 // TODO: add version test for '7.10.5' 01010 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 01011 curl_setopt($ch, CURLOPT_MAXREDIRS, 5); 01012 } 01013 01014 if (!empty($CFG->proxyhost) and !$proxybypass) { 01015 // SOCKS supported in PHP5 only 01016 if (!empty($CFG->proxytype) and ($CFG->proxytype == 'SOCKS5')) { 01017 if (defined('CURLPROXY_SOCKS5')) { 01018 curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); 01019 } else { 01020 curl_close($ch); 01021 if ($fullresponse) { 01022 $response = new stdClass(); 01023 $response->status = '0'; 01024 $response->headers = array(); 01025 $response->response_code = 'SOCKS5 proxy is not supported in PHP4'; 01026 $response->results = ''; 01027 $response->error = 'SOCKS5 proxy is not supported in PHP4'; 01028 return $response; 01029 } else { 01030 debugging("SOCKS5 proxy is not supported in PHP4.", DEBUG_ALL); 01031 return false; 01032 } 01033 } 01034 } 01035 01036 curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false); 01037 01038 if (empty($CFG->proxyport)) { 01039 curl_setopt($ch, CURLOPT_PROXY, $CFG->proxyhost); 01040 } else { 01041 curl_setopt($ch, CURLOPT_PROXY, $CFG->proxyhost.':'.$CFG->proxyport); 01042 } 01043 01044 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) { 01045 curl_setopt($ch, CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword); 01046 if (defined('CURLOPT_PROXYAUTH')) { 01047 // any proxy authentication if PHP 5.1 01048 curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM); 01049 } 01050 } 01051 } 01052 01053 // set up header and content handlers 01054 $received = new stdClass(); 01055 $received->headers = array(); // received headers array 01056 $received->tofile = $tofile; 01057 $received->fh = null; 01058 curl_setopt($ch, CURLOPT_HEADERFUNCTION, partial('download_file_content_header_handler', $received)); 01059 if ($tofile) { 01060 curl_setopt($ch, CURLOPT_WRITEFUNCTION, partial('download_file_content_write_handler', $received)); 01061 } 01062 01063 if (!isset($CFG->curltimeoutkbitrate)) { 01064 //use very slow rate of 56kbps as a timeout speed when not set 01065 $bitrate = 56; 01066 } else { 01067 $bitrate = $CFG->curltimeoutkbitrate; 01068 } 01069 01070 // try to calculate the proper amount for timeout from remote file size. 01071 // if disabled or zero, we won't do any checks nor head requests. 01072 if ($calctimeout && $bitrate > 0) { 01073 //setup header request only options 01074 curl_setopt_array ($ch, array( 01075 CURLOPT_RETURNTRANSFER => false, 01076 CURLOPT_NOBODY => true) 01077 ); 01078 01079 curl_exec($ch); 01080 $info = curl_getinfo($ch); 01081 $err = curl_error($ch); 01082 01083 if ($err === '' && $info['download_content_length'] > 0) { //no curl errors 01084 $timeout = max($timeout, ceil($info['download_content_length'] * 8 / ($bitrate * 1024))); //adjust for large files only - take max timeout. 01085 } 01086 //reinstate affected curl options 01087 curl_setopt_array ($ch, array( 01088 CURLOPT_RETURNTRANSFER => true, 01089 CURLOPT_NOBODY => false) 01090 ); 01091 } 01092 01093 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); 01094 $result = curl_exec($ch); 01095 01096 // try to detect encoding problems 01097 if ((curl_errno($ch) == 23 or curl_errno($ch) == 61) and defined('CURLOPT_ENCODING')) { 01098 curl_setopt($ch, CURLOPT_ENCODING, 'none'); 01099 $result = curl_exec($ch); 01100 } 01101 01102 if ($received->fh) { 01103 fclose($received->fh); 01104 } 01105 01106 if (curl_errno($ch)) { 01107 $error = curl_error($ch); 01108 $error_no = curl_errno($ch); 01109 curl_close($ch); 01110 01111 if ($fullresponse) { 01112 $response = new stdClass(); 01113 if ($error_no == 28) { 01114 $response->status = '-100'; // mimic snoopy 01115 } else { 01116 $response->status = '0'; 01117 } 01118 $response->headers = array(); 01119 $response->response_code = $error; 01120 $response->results = false; 01121 $response->error = $error; 01122 return $response; 01123 } else { 01124 debugging("cURL request for \"$url\" failed with: $error ($error_no)", DEBUG_ALL); 01125 return false; 01126 } 01127 01128 } else { 01129 $info = curl_getinfo($ch); 01130 curl_close($ch); 01131 01132 if (empty($info['http_code'])) { 01133 // for security reasons we support only true http connections (Location: file:// exploit prevention) 01134 $response = new stdClass(); 01135 $response->status = '0'; 01136 $response->headers = array(); 01137 $response->response_code = 'Unknown cURL error'; 01138 $response->results = false; // do NOT change this, we really want to ignore the result! 01139 $response->error = 'Unknown cURL error'; 01140 01141 } else { 01142 $response = new stdClass();; 01143 $response->status = (string)$info['http_code']; 01144 $response->headers = $received->headers; 01145 $response->response_code = $received->headers[0]; 01146 $response->results = $result; 01147 $response->error = ''; 01148 } 01149 01150 if ($fullresponse) { 01151 return $response; 01152 } else if ($info['http_code'] != 200) { 01153 debugging("cURL request for \"$url\" failed, HTTP response code: ".$response->response_code, DEBUG_ALL); 01154 return false; 01155 } else { 01156 return $response->results; 01157 } 01158 } 01159 } 01160 01164 function download_file_content_header_handler($received, $ch, $header) { 01165 $received->headers[] = $header; 01166 return strlen($header); 01167 } 01168 01172 function download_file_content_write_handler($received, $ch, $data) { 01173 if (!$received->fh) { 01174 $received->fh = fopen($received->tofile, 'w'); 01175 if ($received->fh === false) { 01176 // bad luck, file creation or overriding failed 01177 return 0; 01178 } 01179 } 01180 if (fwrite($received->fh, $data) === false) { 01181 // bad luck, write failed, let's abort completely 01182 return 0; 01183 } 01184 return strlen($data); 01185 } 01186 01193 function get_mimetypes_array() { 01194 static $mimearray = array ( 01195 'xxx' => array ('type'=>'document/unknown', 'icon'=>'unknown'), 01196 '3gp' => array ('type'=>'video/quicktime', 'icon'=>'video'), 01197 'aac' => array ('type'=>'audio/aac', 'icon'=>'audio'), 01198 'ai' => array ('type'=>'application/postscript', 'icon'=>'image'), 01199 'aif' => array ('type'=>'audio/x-aiff', 'icon'=>'audio'), 01200 'aiff' => array ('type'=>'audio/x-aiff', 'icon'=>'audio'), 01201 'aifc' => array ('type'=>'audio/x-aiff', 'icon'=>'audio'), 01202 'applescript' => array ('type'=>'text/plain', 'icon'=>'text'), 01203 'asc' => array ('type'=>'text/plain', 'icon'=>'text'), 01204 'asm' => array ('type'=>'text/plain', 'icon'=>'text'), 01205 'au' => array ('type'=>'audio/au', 'icon'=>'audio'), 01206 'avi' => array ('type'=>'video/x-ms-wm', 'icon'=>'avi'), 01207 'bmp' => array ('type'=>'image/bmp', 'icon'=>'image'), 01208 'c' => array ('type'=>'text/plain', 'icon'=>'text'), 01209 'cct' => array ('type'=>'shockwave/director', 'icon'=>'flash'), 01210 'cpp' => array ('type'=>'text/plain', 'icon'=>'text'), 01211 'cs' => array ('type'=>'application/x-csh', 'icon'=>'text'), 01212 'css' => array ('type'=>'text/css', 'icon'=>'text'), 01213 'csv' => array ('type'=>'text/csv', 'icon'=>'excel'), 01214 'dv' => array ('type'=>'video/x-dv', 'icon'=>'video'), 01215 'dmg' => array ('type'=>'application/octet-stream', 'icon'=>'dmg'), 01216 01217 'doc' => array ('type'=>'application/msword', 'icon'=>'word'), 01218 'docx' => array ('type'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'icon'=>'docx'), 01219 'docm' => array ('type'=>'application/vnd.ms-word.document.macroEnabled.12', 'icon'=>'docm'), 01220 'dotx' => array ('type'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'icon'=>'dotx'), 01221 'dotm' => array ('type'=>'application/vnd.ms-word.template.macroEnabled.12', 'icon'=>'dotm'), 01222 01223 'dcr' => array ('type'=>'application/x-director', 'icon'=>'flash'), 01224 'dif' => array ('type'=>'video/x-dv', 'icon'=>'video'), 01225 'dir' => array ('type'=>'application/x-director', 'icon'=>'flash'), 01226 'dxr' => array ('type'=>'application/x-director', 'icon'=>'flash'), 01227 'eps' => array ('type'=>'application/postscript', 'icon'=>'pdf'), 01228 'fdf' => array ('type'=>'application/pdf', 'icon'=>'pdf'), 01229 'flv' => array ('type'=>'video/x-flv', 'icon'=>'video'), 01230 'f4v' => array ('type'=>'video/mp4', 'icon'=>'video'), 01231 'gif' => array ('type'=>'image/gif', 'icon'=>'image'), 01232 'gtar' => array ('type'=>'application/x-gtar', 'icon'=>'zip'), 01233 'tgz' => array ('type'=>'application/g-zip', 'icon'=>'zip'), 01234 'gz' => array ('type'=>'application/g-zip', 'icon'=>'zip'), 01235 'gzip' => array ('type'=>'application/g-zip', 'icon'=>'zip'), 01236 'h' => array ('type'=>'text/plain', 'icon'=>'text'), 01237 'hpp' => array ('type'=>'text/plain', 'icon'=>'text'), 01238 'hqx' => array ('type'=>'application/mac-binhex40', 'icon'=>'zip'), 01239 'htc' => array ('type'=>'text/x-component', 'icon'=>'text'), 01240 'html' => array ('type'=>'text/html', 'icon'=>'html'), 01241 'xhtml'=> array ('type'=>'application/xhtml+xml', 'icon'=>'html'), 01242 'htm' => array ('type'=>'text/html', 'icon'=>'html'), 01243 'ico' => array ('type'=>'image/vnd.microsoft.icon', 'icon'=>'image'), 01244 'ics' => array ('type'=>'text/calendar', 'icon'=>'text'), 01245 'isf' => array ('type'=>'application/inspiration', 'icon'=>'isf'), 01246 'ist' => array ('type'=>'application/inspiration.template', 'icon'=>'isf'), 01247 'java' => array ('type'=>'text/plain', 'icon'=>'text'), 01248 'jcb' => array ('type'=>'text/xml', 'icon'=>'jcb'), 01249 'jcl' => array ('type'=>'text/xml', 'icon'=>'jcl'), 01250 'jcw' => array ('type'=>'text/xml', 'icon'=>'jcw'), 01251 'jmt' => array ('type'=>'text/xml', 'icon'=>'jmt'), 01252 'jmx' => array ('type'=>'text/xml', 'icon'=>'jmx'), 01253 'jpe' => array ('type'=>'image/jpeg', 'icon'=>'image'), 01254 'jpeg' => array ('type'=>'image/jpeg', 'icon'=>'image'), 01255 'jpg' => array ('type'=>'image/jpeg', 'icon'=>'image'), 01256 'jqz' => array ('type'=>'text/xml', 'icon'=>'jqz'), 01257 'js' => array ('type'=>'application/x-javascript', 'icon'=>'text'), 01258 'latex'=> array ('type'=>'application/x-latex', 'icon'=>'text'), 01259 'm' => array ('type'=>'text/plain', 'icon'=>'text'), 01260 'mbz' => array ('type'=>'application/vnd.moodle.backup', 'icon'=>'moodle'), 01261 'mov' => array ('type'=>'video/quicktime', 'icon'=>'video'), 01262 'movie'=> array ('type'=>'video/x-sgi-movie', 'icon'=>'video'), 01263 'm3u' => array ('type'=>'audio/x-mpegurl', 'icon'=>'audio'), 01264 'mp3' => array ('type'=>'audio/mp3', 'icon'=>'audio'), 01265 'mp4' => array ('type'=>'video/mp4', 'icon'=>'video'), 01266 'm4v' => array ('type'=>'video/mp4', 'icon'=>'video'), 01267 'm4a' => array ('type'=>'audio/mp4', 'icon'=>'audio'), 01268 'mpeg' => array ('type'=>'video/mpeg', 'icon'=>'video'), 01269 'mpe' => array ('type'=>'video/mpeg', 'icon'=>'video'), 01270 'mpg' => array ('type'=>'video/mpeg', 'icon'=>'video'), 01271 01272 'odt' => array ('type'=>'application/vnd.oasis.opendocument.text', 'icon'=>'odt'), 01273 'ott' => array ('type'=>'application/vnd.oasis.opendocument.text-template', 'icon'=>'odt'), 01274 'oth' => array ('type'=>'application/vnd.oasis.opendocument.text-web', 'icon'=>'odt'), 01275 'odm' => array ('type'=>'application/vnd.oasis.opendocument.text-master', 'icon'=>'odm'), 01276 'odg' => array ('type'=>'application/vnd.oasis.opendocument.graphics', 'icon'=>'odg'), 01277 'otg' => array ('type'=>'application/vnd.oasis.opendocument.graphics-template', 'icon'=>'odg'), 01278 'odp' => array ('type'=>'application/vnd.oasis.opendocument.presentation', 'icon'=>'odp'), 01279 'otp' => array ('type'=>'application/vnd.oasis.opendocument.presentation-template', 'icon'=>'odp'), 01280 'ods' => array ('type'=>'application/vnd.oasis.opendocument.spreadsheet', 'icon'=>'ods'), 01281 'ots' => array ('type'=>'application/vnd.oasis.opendocument.spreadsheet-template', 'icon'=>'ods'), 01282 'odc' => array ('type'=>'application/vnd.oasis.opendocument.chart', 'icon'=>'odc'), 01283 'odf' => array ('type'=>'application/vnd.oasis.opendocument.formula', 'icon'=>'odf'), 01284 'odb' => array ('type'=>'application/vnd.oasis.opendocument.database', 'icon'=>'odb'), 01285 'odi' => array ('type'=>'application/vnd.oasis.opendocument.image', 'icon'=>'odi'), 01286 'oga' => array ('type'=>'audio/ogg', 'icon'=>'audio'), 01287 'ogg' => array ('type'=>'audio/ogg', 'icon'=>'audio'), 01288 'ogv' => array ('type'=>'video/ogg', 'icon'=>'video'), 01289 01290 'pct' => array ('type'=>'image/pict', 'icon'=>'image'), 01291 'pdf' => array ('type'=>'application/pdf', 'icon'=>'pdf'), 01292 'php' => array ('type'=>'text/plain', 'icon'=>'text'), 01293 'pic' => array ('type'=>'image/pict', 'icon'=>'image'), 01294 'pict' => array ('type'=>'image/pict', 'icon'=>'image'), 01295 'png' => array ('type'=>'image/png', 'icon'=>'image'), 01296 01297 'pps' => array ('type'=>'application/vnd.ms-powerpoint', 'icon'=>'powerpoint'), 01298 'ppt' => array ('type'=>'application/vnd.ms-powerpoint', 'icon'=>'powerpoint'), 01299 'pptx' => array ('type'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'icon'=>'pptx'), 01300 'pptm' => array ('type'=>'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 'icon'=>'pptm'), 01301 'potx' => array ('type'=>'application/vnd.openxmlformats-officedocument.presentationml.template', 'icon'=>'potx'), 01302 'potm' => array ('type'=>'application/vnd.ms-powerpoint.template.macroEnabled.12', 'icon'=>'potm'), 01303 'ppam' => array ('type'=>'application/vnd.ms-powerpoint.addin.macroEnabled.12', 'icon'=>'ppam'), 01304 'ppsx' => array ('type'=>'application/vnd.openxmlformats-officedocument.presentationml.slideshow', 'icon'=>'ppsx'), 01305 'ppsm' => array ('type'=>'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', 'icon'=>'ppsm'), 01306 01307 'ps' => array ('type'=>'application/postscript', 'icon'=>'pdf'), 01308 'qt' => array ('type'=>'video/quicktime', 'icon'=>'video'), 01309 'ra' => array ('type'=>'audio/x-realaudio-plugin', 'icon'=>'audio'), 01310 'ram' => array ('type'=>'audio/x-pn-realaudio-plugin', 'icon'=>'audio'), 01311 'rhb' => array ('type'=>'text/xml', 'icon'=>'xml'), 01312 'rm' => array ('type'=>'audio/x-pn-realaudio-plugin', 'icon'=>'audio'), 01313 'rmvb' => array ('type'=>'application/vnd.rn-realmedia-vbr', 'icon'=>'video'), 01314 'rtf' => array ('type'=>'text/rtf', 'icon'=>'text'), 01315 'rtx' => array ('type'=>'text/richtext', 'icon'=>'text'), 01316 'rv' => array ('type'=>'audio/x-pn-realaudio-plugin', 'icon'=>'video'), 01317 'sh' => array ('type'=>'application/x-sh', 'icon'=>'text'), 01318 'sit' => array ('type'=>'application/x-stuffit', 'icon'=>'zip'), 01319 'smi' => array ('type'=>'application/smil', 'icon'=>'text'), 01320 'smil' => array ('type'=>'application/smil', 'icon'=>'text'), 01321 'sqt' => array ('type'=>'text/xml', 'icon'=>'xml'), 01322 'svg' => array ('type'=>'image/svg+xml', 'icon'=>'image'), 01323 'svgz' => array ('type'=>'image/svg+xml', 'icon'=>'image'), 01324 'swa' => array ('type'=>'application/x-director', 'icon'=>'flash'), 01325 'swf' => array ('type'=>'application/x-shockwave-flash', 'icon'=>'flash'), 01326 'swfl' => array ('type'=>'application/x-shockwave-flash', 'icon'=>'flash'), 01327 01328 'sxw' => array ('type'=>'application/vnd.sun.xml.writer', 'icon'=>'odt'), 01329 'stw' => array ('type'=>'application/vnd.sun.xml.writer.template', 'icon'=>'odt'), 01330 'sxc' => array ('type'=>'application/vnd.sun.xml.calc', 'icon'=>'odt'), 01331 'stc' => array ('type'=>'application/vnd.sun.xml.calc.template', 'icon'=>'odt'), 01332 'sxd' => array ('type'=>'application/vnd.sun.xml.draw', 'icon'=>'odt'), 01333 'std' => array ('type'=>'application/vnd.sun.xml.draw.template', 'icon'=>'odt'), 01334 'sxi' => array ('type'=>'application/vnd.sun.xml.impress', 'icon'=>'odt'), 01335 'sti' => array ('type'=>'application/vnd.sun.xml.impress.template', 'icon'=>'odt'), 01336 'sxg' => array ('type'=>'application/vnd.sun.xml.writer.global', 'icon'=>'odt'), 01337 'sxm' => array ('type'=>'application/vnd.sun.xml.math', 'icon'=>'odt'), 01338 01339 'tar' => array ('type'=>'application/x-tar', 'icon'=>'zip'), 01340 'tif' => array ('type'=>'image/tiff', 'icon'=>'image'), 01341 'tiff' => array ('type'=>'image/tiff', 'icon'=>'image'), 01342 'tex' => array ('type'=>'application/x-tex', 'icon'=>'text'), 01343 'texi' => array ('type'=>'application/x-texinfo', 'icon'=>'text'), 01344 'texinfo' => array ('type'=>'application/x-texinfo', 'icon'=>'text'), 01345 'tsv' => array ('type'=>'text/tab-separated-values', 'icon'=>'text'), 01346 'txt' => array ('type'=>'text/plain', 'icon'=>'text'), 01347 'wav' => array ('type'=>'audio/wav', 'icon'=>'audio'), 01348 'webm' => array ('type'=>'video/webm', 'icon'=>'video'), 01349 'wmv' => array ('type'=>'video/x-ms-wmv', 'icon'=>'avi'), 01350 'asf' => array ('type'=>'video/x-ms-asf', 'icon'=>'avi'), 01351 'xdp' => array ('type'=>'application/pdf', 'icon'=>'pdf'), 01352 'xfd' => array ('type'=>'application/pdf', 'icon'=>'pdf'), 01353 'xfdf' => array ('type'=>'application/pdf', 'icon'=>'pdf'), 01354 01355 'xls' => array ('type'=>'application/vnd.ms-excel', 'icon'=>'excel'), 01356 'xlsx' => array ('type'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'icon'=>'xlsx'), 01357 'xlsm' => array ('type'=>'application/vnd.ms-excel.sheet.macroEnabled.12', 'icon'=>'xlsm'), 01358 'xltx' => array ('type'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'icon'=>'xltx'), 01359 'xltm' => array ('type'=>'application/vnd.ms-excel.template.macroEnabled.12', 'icon'=>'xltm'), 01360 'xlsb' => array ('type'=>'application/vnd.ms-excel.sheet.binary.macroEnabled.12', 'icon'=>'xlsb'), 01361 'xlam' => array ('type'=>'application/vnd.ms-excel.addin.macroEnabled.12', 'icon'=>'xlam'), 01362 01363 'xml' => array ('type'=>'application/xml', 'icon'=>'xml'), 01364 'xsl' => array ('type'=>'text/xml', 'icon'=>'xml'), 01365 'zip' => array ('type'=>'application/zip', 'icon'=>'zip') 01366 ); 01367 return $mimearray; 01368 } 01369 01380 function mimeinfo($element, $filename) { 01381 global $CFG; 01382 $mimeinfo = get_mimetypes_array(); 01383 01384 if (preg_match('/\.([a-z0-9]+)$/i', $filename, $match)) { 01385 if (isset($mimeinfo[strtolower($match[1])][$element])) { 01386 return $mimeinfo[strtolower($match[1])][$element]; 01387 } else { 01388 if ($element == 'icon32') { 01389 if (isset($mimeinfo[strtolower($match[1])]['icon'])) { 01390 $filename = $mimeinfo[strtolower($match[1])]['icon']; 01391 } else { 01392 $filename = 'unknown'; 01393 } 01394 $filename .= '-32'; 01395 if (file_exists($CFG->dirroot.'/pix/f/'.$filename.'.png') or file_exists($CFG->dirroot.'/pix/f/'.$filename.'.gif')) { 01396 return $filename; 01397 } else { 01398 return 'unknown-32'; 01399 } 01400 } else { 01401 return $mimeinfo['xxx'][$element]; // By default 01402 } 01403 } 01404 } else { 01405 if ($element == 'icon32') { 01406 return 'unknown-32'; 01407 } 01408 return $mimeinfo['xxx'][$element]; // By default 01409 } 01410 } 01411 01420 function mimeinfo_from_type($element, $mimetype) { 01421 $mimeinfo = get_mimetypes_array(); 01422 01423 foreach($mimeinfo as $values) { 01424 if ($values['type']==$mimetype) { 01425 if (isset($values[$element])) { 01426 return $values[$element]; 01427 } 01428 break; 01429 } 01430 } 01431 return $mimeinfo['xxx'][$element]; // Default 01432 } 01433 01442 function mimeinfo_from_icon($element, $icon, $all=false) { 01443 $mimeinfo = get_mimetypes_array(); 01444 01445 if (preg_match("/\/(.*)/", $icon, $matches)) { 01446 $icon = $matches[1]; 01447 } 01448 // Try to get the extension 01449 $extension = ''; 01450 if (($cutat = strrpos($icon, '.')) !== false && $cutat < strlen($icon)-1) { 01451 $extension = substr($icon, $cutat + 1); 01452 } 01453 $info = array($mimeinfo['xxx'][$element]); // Default 01454 foreach($mimeinfo as $key => $values) { 01455 if ($values['icon']==$icon) { 01456 if (isset($values[$element])) { 01457 $info[$key] = $values[$element]; 01458 } 01459 //No break, for example for 'excel' we don't want 'csv'! 01460 } 01461 } 01462 if ($all) { 01463 if (count($info) > 1) { 01464 array_shift($info); // take off document/unknown if we have better options 01465 } 01466 return array_values($info); // Keep keys out when requesting all 01467 } 01468 01469 // Requested only one, try to get the best by extension coincidence, else return the last 01470 if ($extension && isset($info[$extension])) { 01471 return $info[$extension]; 01472 } 01473 01474 return array_pop($info); // Return last match (mimicking behaviour/comment inside foreach loop) 01475 } 01476 01496 function file_mimetype_icon($mimetype, $size = NULL) { 01497 global $CFG; 01498 01499 $icon = mimeinfo_from_type('icon', $mimetype); 01500 if ($size) { 01501 if (file_exists("$CFG->dirroot/pix/f/$icon-$size.png") or file_exists("$CFG->dirroot/pix/f/$icon-$size.gif")) { 01502 $icon = "$icon-$size"; 01503 } 01504 } 01505 return 'f/'.$icon; 01506 } 01507 01528 function file_extension_icon($filename, $size = NULL) { 01529 global $CFG; 01530 01531 $icon = mimeinfo('icon', $filename); 01532 if ($size) { 01533 if (file_exists("$CFG->dirroot/pix/f/$icon-$size.png") or file_exists("$CFG->dirroot/pix/f/$icon-$size.gif")) { 01534 $icon = "$icon-$size"; 01535 } 01536 } 01537 return 'f/'.$icon; 01538 } 01539 01548 function get_mimetype_description($mimetype, $capitalise=false) { 01549 if (get_string_manager()->string_exists($mimetype, 'mimetypes')) { 01550 $result = get_string($mimetype, 'mimetypes'); 01551 } else { 01552 $result = get_string('document/unknown','mimetypes'); 01553 } 01554 if ($capitalise) { 01555 $result=ucfirst($result); 01556 } 01557 return $result; 01558 } 01559 01565 function send_file_not_found() { 01566 global $CFG, $COURSE; 01567 header('HTTP/1.0 404 not found'); 01568 print_error('filenotfound', 'error', $CFG->wwwroot.'/course/view.php?id='.$COURSE->id); //this is not displayed on IIS?? 01569 } 01570 01578 function prepare_file_content_sending() { 01579 // We needed to be able to send headers up until now 01580 if (headers_sent()) { 01581 throw new file_serving_exception('Headers already sent, can not serve file.'); 01582 } 01583 01584 $olddebug = error_reporting(0); 01585 01586 // IE compatibility HACK - it does not like zlib compression much 01587 // there is also a problem with the length header in older PHP versions 01588 if (ini_get_bool('zlib.output_compression')) { 01589 ini_set('zlib.output_compression', 'Off'); 01590 } 01591 01592 // flush and close all buffers if possible 01593 while(ob_get_level()) { 01594 if (!ob_end_flush()) { 01595 // prevent infinite loop when buffer can not be closed 01596 break; 01597 } 01598 } 01599 01600 error_reporting($olddebug); 01601 01602 //NOTE: we can not reliable test headers_sent() here because 01603 // the headers might be sent which trying to close the buffers, 01604 // this happens especially if browser does not support gzip or deflate 01605 } 01606 01616 function send_temp_file($path, $filename, $pathisstring=false) { 01617 global $CFG; 01618 01619 // close session - not needed anymore 01620 @session_get_instance()->write_close(); 01621 01622 if (!$pathisstring) { 01623 if (!file_exists($path)) { 01624 header('HTTP/1.0 404 not found'); 01625 print_error('filenotfound', 'error', $CFG->wwwroot.'/'); 01626 } 01627 // executed after normal finish or abort 01628 @register_shutdown_function('send_temp_file_finished', $path); 01629 } 01630 01631 // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup 01632 if (check_browser_version('MSIE')) { 01633 $filename = urlencode($filename); 01634 } 01635 01636 $filesize = $pathisstring ? strlen($path) : filesize($path); 01637 01638 header('Content-Disposition: attachment; filename='.$filename); 01639 header('Content-Length: '.$filesize); 01640 if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431 01641 header('Cache-Control: max-age=10'); 01642 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 01643 header('Pragma: '); 01644 } else { //normal http - prevent caching at all cost 01645 header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0'); 01646 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 01647 header('Pragma: no-cache'); 01648 } 01649 header('Accept-Ranges: none'); // Do not allow byteserving 01650 01651 //flush the buffers - save memory and disable sid rewrite 01652 // this also disables zlib compression 01653 prepare_file_content_sending(); 01654 01655 // send the contents 01656 if ($pathisstring) { 01657 echo $path; 01658 } else { 01659 @readfile($path); 01660 } 01661 01662 die; //no more chars to output 01663 } 01664 01668 function send_temp_file_finished($path) { 01669 if (file_exists($path)) { 01670 @unlink($path); 01671 } 01672 } 01673 01694 function send_file($path, $filename, $lifetime = 'default' , $filter=0, $pathisstring=false, $forcedownload=false, $mimetype='', $dontdie=false) { 01695 global $CFG, $COURSE, $SESSION; 01696 01697 if ($dontdie) { 01698 ignore_user_abort(true); 01699 } 01700 01701 // MDL-11789, apply $CFG->filelifetime here 01702 if ($lifetime === 'default') { 01703 if (!empty($CFG->filelifetime)) { 01704 $lifetime = $CFG->filelifetime; 01705 } else { 01706 $lifetime = 86400; 01707 } 01708 } 01709 01710 session_get_instance()->write_close(); // unlock session during fileserving 01711 01712 // Use given MIME type if specified, otherwise guess it using mimeinfo. 01713 // IE, Konqueror and Opera open html file directly in browser from web even when directed to save it to disk :-O 01714 // only Firefox saves all files locally before opening when content-disposition: attachment stated 01715 $isFF = check_browser_version('Firefox', '1.5'); // only FF > 1.5 properly tested 01716 $mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' : 01717 ($mimetype ? $mimetype : mimeinfo('type', $filename)); 01718 01719 $lastmodified = $pathisstring ? time() : filemtime($path); 01720 $filesize = $pathisstring ? strlen($path) : filesize($path); 01721 01722 /* - MDL-13949 01723 //Adobe Acrobat Reader XSS prevention 01724 if ($mimetype=='application/pdf' or mimeinfo('type', $filename)=='application/pdf') { 01725 //please note that it prevents opening of pdfs in browser when http referer disabled 01726 //or file linked from another site; browser caching of pdfs is now disabled too 01727 if (!empty($_SERVER['HTTP_RANGE'])) { 01728 //already byteserving 01729 $lifetime = 1; // >0 needed for byteserving 01730 } else if (empty($_SERVER['HTTP_REFERER']) or strpos($_SERVER['HTTP_REFERER'], $CFG->wwwroot)!==0) { 01731 $mimetype = 'application/x-forcedownload'; 01732 $forcedownload = true; 01733 $lifetime = 0; 01734 } else { 01735 $lifetime = 1; // >0 needed for byteserving 01736 } 01737 } 01738 */ 01739 01740 if ($lifetime > 0 && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 01741 // get unixtime of request header; clip extra junk off first 01742 $since = strtotime(preg_replace('/;.*$/','',$_SERVER["HTTP_IF_MODIFIED_SINCE"])); 01743 if ($since && $since >= $lastmodified) { 01744 header('HTTP/1.1 304 Not Modified'); 01745 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 01746 header('Cache-Control: max-age='.$lifetime); 01747 header('Content-Type: '.$mimetype); 01748 if ($dontdie) { 01749 return; 01750 } 01751 die; 01752 } 01753 } 01754 01755 //do not put '@' before the next header to detect incorrect moodle configurations, 01756 //error should be better than "weird" empty lines for admins/users 01757 header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT'); 01758 01759 // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup 01760 if (check_browser_version('MSIE')) { 01761 $filename = rawurlencode($filename); 01762 } 01763 01764 if ($forcedownload) { 01765 header('Content-Disposition: attachment; filename="'.$filename.'"'); 01766 } else { 01767 header('Content-Disposition: inline; filename="'.$filename.'"'); 01768 } 01769 01770 if ($lifetime > 0) { 01771 header('Cache-Control: max-age='.$lifetime); 01772 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 01773 header('Pragma: '); 01774 01775 if (empty($CFG->disablebyteserving) && !$pathisstring && $mimetype != 'text/plain' && $mimetype != 'text/html') { 01776 01777 header('Accept-Ranges: bytes'); 01778 01779 if (!empty($_SERVER['HTTP_RANGE']) && strpos($_SERVER['HTTP_RANGE'],'bytes=') !== FALSE) { 01780 // byteserving stuff - for acrobat reader and download accelerators 01781 // see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 01782 // inspired by: http://www.coneural.org/florian/papers/04_byteserving.php 01783 $ranges = false; 01784 if (preg_match_all('/(\d*)-(\d*)/', $_SERVER['HTTP_RANGE'], $ranges, PREG_SET_ORDER)) { 01785 foreach ($ranges as $key=>$value) { 01786 if ($ranges[$key][1] == '') { 01787 //suffix case 01788 $ranges[$key][1] = $filesize - $ranges[$key][2]; 01789 $ranges[$key][2] = $filesize - 1; 01790 } else if ($ranges[$key][2] == '' || $ranges[$key][2] > $filesize - 1) { 01791 //fix range length 01792 $ranges[$key][2] = $filesize - 1; 01793 } 01794 if ($ranges[$key][2] != '' && $ranges[$key][2] < $ranges[$key][1]) { 01795 //invalid byte-range ==> ignore header 01796 $ranges = false; 01797 break; 01798 } 01799 //prepare multipart header 01800 $ranges[$key][0] = "\r\n--".BYTESERVING_BOUNDARY."\r\nContent-Type: $mimetype\r\n"; 01801 $ranges[$key][0] .= "Content-Range: bytes {$ranges[$key][1]}-{$ranges[$key][2]}/$filesize\r\n\r\n"; 01802 } 01803 } else { 01804 $ranges = false; 01805 } 01806 if ($ranges) { 01807 $handle = fopen($path, 'rb'); 01808 byteserving_send_file($handle, $mimetype, $ranges, $filesize); 01809 } 01810 } 01811 } else { 01813 header('Accept-Ranges: none'); 01814 } 01815 } else { // Do not cache files in proxies and browsers 01816 if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431 01817 header('Cache-Control: max-age=10'); 01818 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 01819 header('Pragma: '); 01820 } else { //normal http - prevent caching at all cost 01821 header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0'); 01822 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 01823 header('Pragma: no-cache'); 01824 } 01825 header('Accept-Ranges: none'); // Do not allow byteserving when caching disabled 01826 } 01827 01828 if (empty($filter)) { 01829 if ($mimetype == 'text/plain') { 01830 header('Content-Type: Text/plain; charset=utf-8'); //add encoding 01831 } else { 01832 header('Content-Type: '.$mimetype); 01833 } 01834 header('Content-Length: '.$filesize); 01835 01836 //flush the buffers - save memory and disable sid rewrite 01837 //this also disables zlib compression 01838 prepare_file_content_sending(); 01839 01840 // send the contents 01841 if ($pathisstring) { 01842 echo $path; 01843 } else { 01844 @readfile($path); 01845 } 01846 01847 } else { // Try to put the file through filters 01848 if ($mimetype == 'text/html') { 01849 $options = new stdClass(); 01850 $options->noclean = true; 01851 $options->nocache = true; // temporary workaround for MDL-5136 01852 $text = $pathisstring ? $path : implode('', file($path)); 01853 01854 $text = file_modify_html_header($text); 01855 $output = format_text($text, FORMAT_HTML, $options, $COURSE->id); 01856 01857 header('Content-Length: '.strlen($output)); 01858 header('Content-Type: text/html'); 01859 01860 //flush the buffers - save memory and disable sid rewrite 01861 //this also disables zlib compression 01862 prepare_file_content_sending(); 01863 01864 // send the contents 01865 echo $output; 01866 // only filter text if filter all files is selected 01867 } else if (($mimetype == 'text/plain') and ($filter == 1)) { 01868 $options = new stdClass(); 01869 $options->newlines = false; 01870 $options->noclean = true; 01871 $text = htmlentities($pathisstring ? $path : implode('', file($path))); 01872 $output = '<pre>'. format_text($text, FORMAT_MOODLE, $options, $COURSE->id) .'</pre>'; 01873 01874 header('Content-Length: '.strlen($output)); 01875 header('Content-Type: text/html; charset=utf-8'); //add encoding 01876 01877 //flush the buffers - save memory and disable sid rewrite 01878 //this also disables zlib compression 01879 prepare_file_content_sending(); 01880 01881 // send the contents 01882 echo $output; 01883 01884 } else { // Just send it out raw 01885 header('Content-Length: '.$filesize); 01886 header('Content-Type: '.$mimetype); 01887 01888 //flush the buffers - save memory and disable sid rewrite 01889 //this also disables zlib compression 01890 prepare_file_content_sending(); 01891 01892 // send the contents 01893 if ($pathisstring) { 01894 echo $path; 01895 }else { 01896 @readfile($path); 01897 } 01898 } 01899 } 01900 if ($dontdie) { 01901 return; 01902 } 01903 die; //no more chars to output!!! 01904 } 01905 01924 function send_stored_file($stored_file, $lifetime=86400 , $filter=0, $forcedownload=false, $filename=null, $dontdie=false) { 01925 global $CFG, $COURSE, $SESSION; 01926 01927 if (!$stored_file or $stored_file->is_directory()) { 01928 // nothing to serve 01929 if ($dontdie) { 01930 return; 01931 } 01932 die; 01933 } 01934 01935 if ($dontdie) { 01936 ignore_user_abort(true); 01937 } 01938 01939 session_get_instance()->write_close(); // unlock session during fileserving 01940 01941 // Use given MIME type if specified, otherwise guess it using mimeinfo. 01942 // IE, Konqueror and Opera open html file directly in browser from web even when directed to save it to disk :-O 01943 // only Firefox saves all files locally before opening when content-disposition: attachment stated 01944 $filename = is_null($filename) ? $stored_file->get_filename() : $filename; 01945 $isFF = check_browser_version('Firefox', '1.5'); // only FF > 1.5 properly tested 01946 $mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' : 01947 ($stored_file->get_mimetype() ? $stored_file->get_mimetype() : mimeinfo('type', $filename)); 01948 01949 $lastmodified = $stored_file->get_timemodified(); 01950 $filesize = $stored_file->get_filesize(); 01951 01952 if ($lifetime > 0 && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 01953 // get unixtime of request header; clip extra junk off first 01954 $since = strtotime(preg_replace('/;.*$/','',$_SERVER["HTTP_IF_MODIFIED_SINCE"])); 01955 if ($since && $since >= $lastmodified) { 01956 header('HTTP/1.1 304 Not Modified'); 01957 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 01958 header('Cache-Control: max-age='.$lifetime); 01959 header('Content-Type: '.$mimetype); 01960 if ($dontdie) { 01961 return; 01962 } 01963 die; 01964 } 01965 } 01966 01967 //do not put '@' before the next header to detect incorrect moodle configurations, 01968 //error should be better than "weird" empty lines for admins/users 01969 header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT'); 01970 01971 // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup 01972 if (check_browser_version('MSIE')) { 01973 $filename = rawurlencode($filename); 01974 } 01975 01976 if ($forcedownload) { 01977 header('Content-Disposition: attachment; filename="'.$filename.'"'); 01978 } else { 01979 header('Content-Disposition: inline; filename="'.$filename.'"'); 01980 } 01981 01982 if ($lifetime > 0) { 01983 header('Cache-Control: max-age='.$lifetime); 01984 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); 01985 header('Pragma: '); 01986 01987 if (empty($CFG->disablebyteserving) && $mimetype != 'text/plain' && $mimetype != 'text/html') { 01988 01989 header('Accept-Ranges: bytes'); 01990 01991 if (!empty($_SERVER['HTTP_RANGE']) && strpos($_SERVER['HTTP_RANGE'],'bytes=') !== FALSE) { 01992 // byteserving stuff - for acrobat reader and download accelerators 01993 // see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 01994 // inspired by: http://www.coneural.org/florian/papers/04_byteserving.php 01995 $ranges = false; 01996 if (preg_match_all('/(\d*)-(\d*)/', $_SERVER['HTTP_RANGE'], $ranges, PREG_SET_ORDER)) { 01997 foreach ($ranges as $key=>$value) { 01998 if ($ranges[$key][1] == '') { 01999 //suffix case 02000 $ranges[$key][1] = $filesize - $ranges[$key][2]; 02001 $ranges[$key][2] = $filesize - 1; 02002 } else if ($ranges[$key][2] == '' || $ranges[$key][2] > $filesize - 1) { 02003 //fix range length 02004 $ranges[$key][2] = $filesize - 1; 02005 } 02006 if ($ranges[$key][2] != '' && $ranges[$key][2] < $ranges[$key][1]) { 02007 //invalid byte-range ==> ignore header 02008 $ranges = false; 02009 break; 02010 } 02011 //prepare multipart header 02012 $ranges[$key][0] = "\r\n--".BYTESERVING_BOUNDARY."\r\nContent-Type: $mimetype\r\n"; 02013 $ranges[$key][0] .= "Content-Range: bytes {$ranges[$key][1]}-{$ranges[$key][2]}/$filesize\r\n\r\n"; 02014 } 02015 } else { 02016 $ranges = false; 02017 } 02018 if ($ranges) { 02019 byteserving_send_file($stored_file->get_content_file_handle(), $mimetype, $ranges, $filesize); 02020 } 02021 } 02022 } else { 02024 header('Accept-Ranges: none'); 02025 } 02026 } else { // Do not cache files in proxies and browsers 02027 if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431 02028 header('Cache-Control: max-age=10'); 02029 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 02030 header('Pragma: '); 02031 } else { //normal http - prevent caching at all cost 02032 header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0'); 02033 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 02034 header('Pragma: no-cache'); 02035 } 02036 header('Accept-Ranges: none'); // Do not allow byteserving when caching disabled 02037 } 02038 02039 if (empty($filter)) { 02040 if ($mimetype == 'text/plain') { 02041 header('Content-Type: Text/plain; charset=utf-8'); //add encoding 02042 } else { 02043 header('Content-Type: '.$mimetype); 02044 } 02045 header('Content-Length: '.$filesize); 02046 02047 //flush the buffers - save memory and disable sid rewrite 02048 //this also disables zlib compression 02049 prepare_file_content_sending(); 02050 02051 // send the contents 02052 $stored_file->readfile(); 02053 02054 } else { // Try to put the file through filters 02055 if ($mimetype == 'text/html') { 02056 $options = new stdClass(); 02057 $options->noclean = true; 02058 $options->nocache = true; // temporary workaround for MDL-5136 02059 $text = $stored_file->get_content(); 02060 $text = file_modify_html_header($text); 02061 $output = format_text($text, FORMAT_HTML, $options, $COURSE->id); 02062 02063 header('Content-Length: '.strlen($output)); 02064 header('Content-Type: text/html'); 02065 02066 //flush the buffers - save memory and disable sid rewrite 02067 //this also disables zlib compression 02068 prepare_file_content_sending(); 02069 02070 // send the contents 02071 echo $output; 02072 02073 } else if (($mimetype == 'text/plain') and ($filter == 1)) { 02074 // only filter text if filter all files is selected 02075 $options = new stdClass(); 02076 $options->newlines = false; 02077 $options->noclean = true; 02078 $text = $stored_file->get_content(); 02079 $output = '<pre>'. format_text($text, FORMAT_MOODLE, $options, $COURSE->id) .'</pre>'; 02080 02081 header('Content-Length: '.strlen($output)); 02082 header('Content-Type: text/html; charset=utf-8'); //add encoding 02083 02084 //flush the buffers - save memory and disable sid rewrite 02085 //this also disables zlib compression 02086 prepare_file_content_sending(); 02087 02088 // send the contents 02089 echo $output; 02090 02091 } else { // Just send it out raw 02092 header('Content-Length: '.$filesize); 02093 header('Content-Type: '.$mimetype); 02094 02095 //flush the buffers - save memory and disable sid rewrite 02096 //this also disables zlib compression 02097 prepare_file_content_sending(); 02098 02099 // send the contents 02100 $stored_file->readfile(); 02101 } 02102 } 02103 if ($dontdie) { 02104 return; 02105 } 02106 die; //no more chars to output!!! 02107 } 02108 02119 function get_records_csv($file, $table) { 02120 global $CFG, $DB; 02121 02122 if (!$metacolumns = $DB->get_columns($table)) { 02123 return false; 02124 } 02125 02126 if(!($handle = @fopen($file, 'r'))) { 02127 print_error('get_records_csv failed to open '.$file); 02128 } 02129 02130 $fieldnames = fgetcsv($handle, 4096); 02131 if(empty($fieldnames)) { 02132 fclose($handle); 02133 return false; 02134 } 02135 02136 $columns = array(); 02137 02138 foreach($metacolumns as $metacolumn) { 02139 $ord = array_search($metacolumn->name, $fieldnames); 02140 if(is_int($ord)) { 02141 $columns[$metacolumn->name] = $ord; 02142 } 02143 } 02144 02145 $rows = array(); 02146 02147 while (($data = fgetcsv($handle, 4096)) !== false) { 02148 $item = new stdClass; 02149 foreach($columns as $name => $ord) { 02150 $item->$name = $data[$ord]; 02151 } 02152 $rows[] = $item; 02153 } 02154 02155 fclose($handle); 02156 return $rows; 02157 } 02158 02168 function put_records_csv($file, $records, $table = NULL) { 02169 global $CFG, $DB; 02170 02171 if (empty($records)) { 02172 return true; 02173 } 02174 02175 $metacolumns = NULL; 02176 if ($table !== NULL && !$metacolumns = $DB->get_columns($table)) { 02177 return false; 02178 } 02179 02180 echo "x"; 02181 02182 if(!($fp = @fopen($CFG->tempdir.'/'.$file, 'w'))) { 02183 print_error('put_records_csv failed to open '.$file); 02184 } 02185 02186 $proto = reset($records); 02187 if(is_object($proto)) { 02188 $fields_records = array_keys(get_object_vars($proto)); 02189 } 02190 else if(is_array($proto)) { 02191 $fields_records = array_keys($proto); 02192 } 02193 else { 02194 return false; 02195 } 02196 echo "x"; 02197 02198 if(!empty($metacolumns)) { 02199 $fields_table = array_map(create_function('$a', 'return $a->name;'), $metacolumns); 02200 $fields = array_intersect($fields_records, $fields_table); 02201 } 02202 else { 02203 $fields = $fields_records; 02204 } 02205 02206 fwrite($fp, implode(',', $fields)); 02207 fwrite($fp, "\r\n"); 02208 02209 foreach($records as $record) { 02210 $array = (array)$record; 02211 $values = array(); 02212 foreach($fields as $field) { 02213 if(strpos($array[$field], ',')) { 02214 $values[] = '"'.str_replace('"', '\"', $array[$field]).'"'; 02215 } 02216 else { 02217 $values[] = $array[$field]; 02218 } 02219 } 02220 fwrite($fp, implode(',', $values)."\r\n"); 02221 } 02222 02223 fclose($fp); 02224 return true; 02225 } 02226 02227 02237 function fulldelete($location) { 02238 if (empty($location)) { 02239 // extra safety against wrong param 02240 return false; 02241 } 02242 if (is_dir($location)) { 02243 $currdir = opendir($location); 02244 while (false !== ($file = readdir($currdir))) { 02245 if ($file <> ".." && $file <> ".") { 02246 $fullfile = $location."/".$file; 02247 if (is_dir($fullfile)) { 02248 if (!fulldelete($fullfile)) { 02249 return false; 02250 } 02251 } else { 02252 if (!unlink($fullfile)) { 02253 return false; 02254 } 02255 } 02256 } 02257 } 02258 closedir($currdir); 02259 if (! rmdir($location)) { 02260 return false; 02261 } 02262 02263 } else if (file_exists($location)) { 02264 if (!unlink($location)) { 02265 return false; 02266 } 02267 } 02268 return true; 02269 } 02270 02279 function byteserving_send_file($handle, $mimetype, $ranges, $filesize) { 02280 $chunksize = 1*(1024*1024); // 1MB chunks - must be less than 2MB! 02281 if ($handle === false) { 02282 die; 02283 } 02284 if (count($ranges) == 1) { //only one range requested 02285 $length = $ranges[0][2] - $ranges[0][1] + 1; 02286 header('HTTP/1.1 206 Partial content'); 02287 header('Content-Length: '.$length); 02288 header('Content-Range: bytes '.$ranges[0][1].'-'.$ranges[0][2].'/'.$filesize); 02289 header('Content-Type: '.$mimetype); 02290 02291 //flush the buffers - save memory and disable sid rewrite 02292 //this also disables zlib compression 02293 prepare_file_content_sending(); 02294 02295 $buffer = ''; 02296 fseek($handle, $ranges[0][1]); 02297 while (!feof($handle) && $length > 0) { 02298 @set_time_limit(60*60); //reset time limit to 60 min - should be enough for 1 MB chunk 02299 $buffer = fread($handle, ($chunksize < $length ? $chunksize : $length)); 02300 echo $buffer; 02301 flush(); 02302 $length -= strlen($buffer); 02303 } 02304 fclose($handle); 02305 die; 02306 } else { // multiple ranges requested - not tested much 02307 $totallength = 0; 02308 foreach($ranges as $range) { 02309 $totallength += strlen($range[0]) + $range[2] - $range[1] + 1; 02310 } 02311 $totallength += strlen("\r\n--".BYTESERVING_BOUNDARY."--\r\n"); 02312 header('HTTP/1.1 206 Partial content'); 02313 header('Content-Length: '.$totallength); 02314 header('Content-Type: multipart/byteranges; boundary='.BYTESERVING_BOUNDARY); 02315 //TODO: check if "multipart/x-byteranges" is more compatible with current readers/browsers/servers 02316 02317 //flush the buffers - save memory and disable sid rewrite 02318 //this also disables zlib compression 02319 prepare_file_content_sending(); 02320 02321 foreach($ranges as $range) { 02322 $length = $range[2] - $range[1] + 1; 02323 echo $range[0]; 02324 $buffer = ''; 02325 fseek($handle, $range[1]); 02326 while (!feof($handle) && $length > 0) { 02327 @set_time_limit(60*60); //reset time limit to 60 min - should be enough for 1 MB chunk 02328 $buffer = fread($handle, ($chunksize < $length ? $chunksize : $length)); 02329 echo $buffer; 02330 flush(); 02331 $length -= strlen($buffer); 02332 } 02333 } 02334 echo "\r\n--".BYTESERVING_BOUNDARY."--\r\n"; 02335 fclose($handle); 02336 die; 02337 } 02338 } 02339 02348 function file_modify_html_header($text) { 02349 // first look for <head> tag 02350 global $CFG; 02351 02352 $stylesheetshtml = ''; 02353 /* foreach ($CFG->stylesheets as $stylesheet) { 02354 //TODO: MDL-21120 02355 $stylesheetshtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n"; 02356 }*/ 02357 02358 $ufo = ''; 02359 if (filter_is_enabled('filter/mediaplugin')) { 02360 // this script is needed by most media filter plugins. 02361 $attributes = array('type'=>'text/javascript', 'src'=>$CFG->httpswwwroot . '/lib/ufo.js'); 02362 $ufo = html_writer::tag('script', '', $attributes) . "\n"; 02363 } 02364 02365 preg_match('/<head>|<HEAD>/', $text, $matches); 02366 if ($matches) { 02367 $replacement = '<head>'.$ufo.$stylesheetshtml; 02368 $text = preg_replace('/<head>|<HEAD>/', $replacement, $text, 1); 02369 return $text; 02370 } 02371 02372 // if not, look for <html> tag, and stick <head> right after 02373 preg_match('/<html>|<HTML>/', $text, $matches); 02374 if ($matches) { 02375 // replace <html> tag with <html><head>includes</head> 02376 $replacement = '<html>'."\n".'<head>'.$ufo.$stylesheetshtml.'</head>'; 02377 $text = preg_replace('/<html>|<HTML>/', $replacement, $text, 1); 02378 return $text; 02379 } 02380 02381 // if not, look for <body> tag, and stick <head> before body 02382 preg_match('/<body>|<BODY>/', $text, $matches); 02383 if ($matches) { 02384 $replacement = '<head>'.$ufo.$stylesheetshtml.'</head>'."\n".'<body>'; 02385 $text = preg_replace('/<body>|<BODY>/', $replacement, $text, 1); 02386 return $text; 02387 } 02388 02389 // if not, just stick a <head> tag at the beginning 02390 $text = '<head>'.$ufo.$stylesheetshtml.'</head>'."\n".$text; 02391 return $text; 02392 } 02393 02421 class curl { 02423 public $cache = false; 02424 public $proxy = false; 02426 public $version = '0.4 dev'; 02428 public $response = array(); 02429 public $header = array(); 02431 public $info; 02432 public $error; 02433 02435 private $options; 02437 private $proxy_host = ''; 02438 private $proxy_auth = ''; 02439 private $proxy_type = ''; 02441 private $debug = false; 02442 private $cookie = false; 02443 02448 public function __construct($options = array()){ 02449 global $CFG; 02450 if (!function_exists('curl_init')) { 02451 $this->error = 'cURL module must be enabled!'; 02452 trigger_error($this->error, E_USER_ERROR); 02453 return false; 02454 } 02455 // the options of curl should be init here. 02456 $this->resetopt(); 02457 if (!empty($options['debug'])) { 02458 $this->debug = true; 02459 } 02460 if(!empty($options['cookie'])) { 02461 if($options['cookie'] === true) { 02462 $this->cookie = $CFG->dataroot.'/curl_cookie.txt'; 02463 } else { 02464 $this->cookie = $options['cookie']; 02465 } 02466 } 02467 if (!empty($options['cache'])) { 02468 if (class_exists('curl_cache')) { 02469 if (!empty($options['module_cache'])) { 02470 $this->cache = new curl_cache($options['module_cache']); 02471 } else { 02472 $this->cache = new curl_cache('misc'); 02473 } 02474 } 02475 } 02476 if (!empty($CFG->proxyhost)) { 02477 if (empty($CFG->proxyport)) { 02478 $this->proxy_host = $CFG->proxyhost; 02479 } else { 02480 $this->proxy_host = $CFG->proxyhost.':'.$CFG->proxyport; 02481 } 02482 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) { 02483 $this->proxy_auth = $CFG->proxyuser.':'.$CFG->proxypassword; 02484 $this->setopt(array( 02485 'proxyauth'=> CURLAUTH_BASIC | CURLAUTH_NTLM, 02486 'proxyuserpwd'=>$this->proxy_auth)); 02487 } 02488 if (!empty($CFG->proxytype)) { 02489 if ($CFG->proxytype == 'SOCKS5') { 02490 $this->proxy_type = CURLPROXY_SOCKS5; 02491 } else { 02492 $this->proxy_type = CURLPROXY_HTTP; 02493 $this->setopt(array('httpproxytunnel'=>false)); 02494 } 02495 $this->setopt(array('proxytype'=>$this->proxy_type)); 02496 } 02497 } 02498 if (!empty($this->proxy_host)) { 02499 $this->proxy = array('proxy'=>$this->proxy_host); 02500 } 02501 } 02505 public function resetopt(){ 02506 $this->options = array(); 02507 $this->options['CURLOPT_USERAGENT'] = 'MoodleBot/1.0'; 02508 // True to include the header in the output 02509 $this->options['CURLOPT_HEADER'] = 0; 02510 // True to Exclude the body from the output 02511 $this->options['CURLOPT_NOBODY'] = 0; 02512 // TRUE to follow any "Location: " header that the server 02513 // sends as part of the HTTP header (note this is recursive, 02514 // PHP will follow as many "Location: " headers that it is sent, 02515 // unless CURLOPT_MAXREDIRS is set). 02516 //$this->options['CURLOPT_FOLLOWLOCATION'] = 1; 02517 $this->options['CURLOPT_MAXREDIRS'] = 10; 02518 $this->options['CURLOPT_ENCODING'] = ''; 02519 // TRUE to return the transfer as a string of the return 02520 // value of curl_exec() instead of outputting it out directly. 02521 $this->options['CURLOPT_RETURNTRANSFER'] = 1; 02522 $this->options['CURLOPT_BINARYTRANSFER'] = 0; 02523 $this->options['CURLOPT_SSL_VERIFYPEER'] = 0; 02524 $this->options['CURLOPT_SSL_VERIFYHOST'] = 2; 02525 $this->options['CURLOPT_CONNECTTIMEOUT'] = 30; 02526 } 02527 02531 public function resetcookie() { 02532 if (!empty($this->cookie)) { 02533 if (is_file($this->cookie)) { 02534 $fp = fopen($this->cookie, 'w'); 02535 if (!empty($fp)) { 02536 fwrite($fp, ''); 02537 fclose($fp); 02538 } 02539 } 02540 } 02541 } 02542 02550 public function setopt($options = array()) { 02551 if (is_array($options)) { 02552 foreach($options as $name => $val){ 02553 if (stripos($name, 'CURLOPT_') === false) { 02554 $name = strtoupper('CURLOPT_'.$name); 02555 } 02556 $this->options[$name] = $val; 02557 } 02558 } 02559 } 02564 public function cleanopt(){ 02565 unset($this->options['CURLOPT_HTTPGET']); 02566 unset($this->options['CURLOPT_POST']); 02567 unset($this->options['CURLOPT_POSTFIELDS']); 02568 unset($this->options['CURLOPT_PUT']); 02569 unset($this->options['CURLOPT_INFILE']); 02570 unset($this->options['CURLOPT_INFILESIZE']); 02571 unset($this->options['CURLOPT_CUSTOMREQUEST']); 02572 } 02573 02580 public function setHeader($header) { 02581 if (is_array($header)){ 02582 foreach ($header as $v) { 02583 $this->setHeader($v); 02584 } 02585 } else { 02586 $this->header[] = $header; 02587 } 02588 } 02593 public function getResponse(){ 02594 return $this->response; 02595 } 02604 private function formatHeader($ch, $header) 02605 { 02606 $this->count++; 02607 if (strlen($header) > 2) { 02608 list($key, $value) = explode(" ", rtrim($header, "\r\n"), 2); 02609 $key = rtrim($key, ':'); 02610 if (!empty($this->response[$key])) { 02611 if (is_array($this->response[$key])){ 02612 $this->response[$key][] = $value; 02613 } else { 02614 $tmp = $this->response[$key]; 02615 $this->response[$key] = array(); 02616 $this->response[$key][] = $tmp; 02617 $this->response[$key][] = $value; 02618 02619 } 02620 } else { 02621 $this->response[$key] = $value; 02622 } 02623 } 02624 return strlen($header); 02625 } 02626 02634 private function apply_opt($curl, $options) { 02635 // Clean up 02636 $this->cleanopt(); 02637 // set cookie 02638 if (!empty($this->cookie) || !empty($options['cookie'])) { 02639 $this->setopt(array('cookiejar'=>$this->cookie, 02640 'cookiefile'=>$this->cookie 02641 )); 02642 } 02643 02644 // set proxy 02645 if (!empty($this->proxy) || !empty($options['proxy'])) { 02646 $this->setopt($this->proxy); 02647 } 02648 $this->setopt($options); 02649 // reset before set options 02650 curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this,'formatHeader')); 02651 // set headers 02652 if (empty($this->header)){ 02653 $this->setHeader(array( 02654 'User-Agent: MoodleBot/1.0', 02655 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7', 02656 'Connection: keep-alive' 02657 )); 02658 } 02659 curl_setopt($curl, CURLOPT_HTTPHEADER, $this->header); 02660 02661 if ($this->debug){ 02662 echo '<h1>Options</h1>'; 02663 var_dump($this->options); 02664 echo '<h1>Header</h1>'; 02665 var_dump($this->header); 02666 } 02667 02668 // set options 02669 foreach($this->options as $name => $val) { 02670 if (is_string($name)) { 02671 $name = constant(strtoupper($name)); 02672 } 02673 curl_setopt($curl, $name, $val); 02674 } 02675 return $curl; 02676 } 02694 public function download($requests, $options = array()) { 02695 $options['CURLOPT_BINARYTRANSFER'] = 1; 02696 $options['RETURNTRANSFER'] = false; 02697 return $this->multi($requests, $options); 02698 } 02699 /* 02700 * Mulit HTTP Requests 02701 * This function could run multi-requests in parallel. 02702 * 02703 * @param array $requests An array of files to request 02704 * @param array $options An array of options to set 02705 * @return array An array of results 02706 */ 02707 protected function multi($requests, $options = array()) { 02708 $count = count($requests); 02709 $handles = array(); 02710 $results = array(); 02711 $main = curl_multi_init(); 02712 for ($i = 0; $i < $count; $i++) { 02713 $url = $requests[$i]; 02714 foreach($url as $n=>$v){ 02715 $options[$n] = $url[$n]; 02716 } 02717 $handles[$i] = curl_init($url['url']); 02718 $this->apply_opt($handles[$i], $options); 02719 curl_multi_add_handle($main, $handles[$i]); 02720 } 02721 $running = 0; 02722 do { 02723 curl_multi_exec($main, $running); 02724 } while($running > 0); 02725 for ($i = 0; $i < $count; $i++) { 02726 if (!empty($options['CURLOPT_RETURNTRANSFER'])) { 02727 $results[] = true; 02728 } else { 02729 $results[] = curl_multi_getcontent($handles[$i]); 02730 } 02731 curl_multi_remove_handle($main, $handles[$i]); 02732 } 02733 curl_multi_close($main); 02734 return $results; 02735 } 02743 protected function request($url, $options = array()){ 02744 // create curl instance 02745 $curl = curl_init($url); 02746 $options['url'] = $url; 02747 $this->apply_opt($curl, $options); 02748 if ($this->cache && $ret = $this->cache->get($this->options)) { 02749 return $ret; 02750 } else { 02751 $ret = curl_exec($curl); 02752 if ($this->cache) { 02753 $this->cache->set($this->options, $ret); 02754 } 02755 } 02756 02757 $this->info = curl_getinfo($curl); 02758 $this->error = curl_error($curl); 02759 02760 if ($this->debug){ 02761 echo '<h1>Return Data</h1>'; 02762 var_dump($ret); 02763 echo '<h1>Info</h1>'; 02764 var_dump($this->info); 02765 echo '<h1>Error</h1>'; 02766 var_dump($this->error); 02767 } 02768 02769 curl_close($curl); 02770 02771 if (empty($this->error)){ 02772 return $ret; 02773 } else { 02774 return $this->error; 02775 // exception is not ajax friendly 02776 //throw new moodle_exception($this->error, 'curl'); 02777 } 02778 } 02779 02789 public function head($url, $options = array()){ 02790 $options['CURLOPT_HTTPGET'] = 0; 02791 $options['CURLOPT_HEADER'] = 1; 02792 $options['CURLOPT_NOBODY'] = 1; 02793 return $this->request($url, $options); 02794 } 02795 02804 public function post($url, $params = '', $options = array()){ 02805 $options['CURLOPT_POST'] = 1; 02806 if (is_array($params)) { 02807 $this->_tmp_file_post_params = array(); 02808 foreach ($params as $key => $value) { 02809 if ($value instanceof stored_file) { 02810 $value->add_to_curl_request($this, $key); 02811 } else { 02812 $this->_tmp_file_post_params[$key] = $value; 02813 } 02814 } 02815 $options['CURLOPT_POSTFIELDS'] = $this->_tmp_file_post_params; 02816 unset($this->_tmp_file_post_params); 02817 } else { 02818 // $params is the raw post data 02819 $options['CURLOPT_POSTFIELDS'] = $params; 02820 } 02821 return $this->request($url, $options); 02822 } 02823 02832 public function get($url, $params = array(), $options = array()){ 02833 $options['CURLOPT_HTTPGET'] = 1; 02834 02835 if (!empty($params)){ 02836 $url .= (stripos($url, '?') !== false) ? '&' : '?'; 02837 $url .= http_build_query($params, '', '&'); 02838 } 02839 return $this->request($url, $options); 02840 } 02841 02850 public function put($url, $params = array(), $options = array()){ 02851 $file = $params['file']; 02852 if (!is_file($file)){ 02853 return null; 02854 } 02855 $fp = fopen($file, 'r'); 02856 $size = filesize($file); 02857 $options['CURLOPT_PUT'] = 1; 02858 $options['CURLOPT_INFILESIZE'] = $size; 02859 $options['CURLOPT_INFILE'] = $fp; 02860 if (!isset($this->options['CURLOPT_USERPWD'])){ 02861 $this->setopt(array('CURLOPT_USERPWD'=>'anonymous: noreply@moodle.org')); 02862 } 02863 $ret = $this->request($url, $options); 02864 fclose($fp); 02865 return $ret; 02866 } 02867 02876 public function delete($url, $param = array(), $options = array()){ 02877 $options['CURLOPT_CUSTOMREQUEST'] = 'DELETE'; 02878 if (!isset($options['CURLOPT_USERPWD'])) { 02879 $options['CURLOPT_USERPWD'] = 'anonymous: noreply@moodle.org'; 02880 } 02881 $ret = $this->request($url, $options); 02882 return $ret; 02883 } 02891 public function trace($url, $options = array()){ 02892 $options['CURLOPT_CUSTOMREQUEST'] = 'TRACE'; 02893 $ret = $this->request($url, $options); 02894 return $ret; 02895 } 02903 public function options($url, $options = array()){ 02904 $options['CURLOPT_CUSTOMREQUEST'] = 'OPTIONS'; 02905 $ret = $this->request($url, $options); 02906 return $ret; 02907 } 02908 public function get_info() { 02909 return $this->info; 02910 } 02911 } 02912 02929 class curl_cache { 02931 public $dir = ''; 02938 function __construct($module = 'repository'){ 02939 global $CFG; 02940 if (!empty($module)) { 02941 $this->dir = $CFG->cachedir.'/'.$module.'/'; 02942 } else { 02943 $this->dir = $CFG->cachedir.'/misc/'; 02944 } 02945 if (!file_exists($this->dir)) { 02946 mkdir($this->dir, $CFG->directorypermissions, true); 02947 } 02948 if ($module == 'repository') { 02949 if (empty($CFG->repositorycacheexpire)) { 02950 $CFG->repositorycacheexpire = 120; 02951 } 02952 $this->ttl = $CFG->repositorycacheexpire; 02953 } else { 02954 if (empty($CFG->curlcache)) { 02955 $CFG->curlcache = 120; 02956 } 02957 $this->ttl = $CFG->curlcache; 02958 } 02959 } 02960 02969 public function get($param){ 02970 global $CFG, $USER; 02971 $this->cleanup($this->ttl); 02972 $filename = 'u'.$USER->id.'_'.md5(serialize($param)); 02973 if(file_exists($this->dir.$filename)) { 02974 $lasttime = filemtime($this->dir.$filename); 02975 if(time()-$lasttime > $this->ttl) 02976 { 02977 return false; 02978 } else { 02979 $fp = fopen($this->dir.$filename, 'r'); 02980 $size = filesize($this->dir.$filename); 02981 $content = fread($fp, $size); 02982 return unserialize($content); 02983 } 02984 } 02985 return false; 02986 } 02987 02996 public function set($param, $val){ 02997 global $CFG, $USER; 02998 $filename = 'u'.$USER->id.'_'.md5(serialize($param)); 02999 $fp = fopen($this->dir.$filename, 'w'); 03000 fwrite($fp, serialize($val)); 03001 fclose($fp); 03002 } 03003 03009 public function cleanup($expire){ 03010 if($dir = opendir($this->dir)){ 03011 while (false !== ($file = readdir($dir))) { 03012 if(!is_dir($file) && $file != '.' && $file != '..') { 03013 $lasttime = @filemtime($this->dir.$file); 03014 if(time() - $lasttime > $expire){ 03015 @unlink($this->dir.$file); 03016 } 03017 } 03018 } 03019 } 03020 } 03027 public function refresh(){ 03028 global $CFG, $USER; 03029 if($dir = opendir($this->dir)){ 03030 while (false !== ($file = readdir($dir))) { 03031 if(!is_dir($file) && $file != '.' && $file != '..') { 03032 if(strpos($file, 'u'.$USER->id.'_')!==false){ 03033 @unlink($this->dir.$file); 03034 } 03035 } 03036 } 03037 } 03038 } 03039 } 03040 03051 class filetype_parser { 03058 public function __construct($file = '') { 03059 global $CFG; 03060 if (empty($file)) { 03061 $this->file = $CFG->libdir.'/filestorage/file_types.mm'; 03062 } else { 03063 $this->file = $file; 03064 } 03065 $this->tree = array(); 03066 $this->result = array(); 03067 } 03068 03075 private function _browse_nodes($parent, $types) { 03076 $key = (string)$parent['TEXT']; 03077 if(isset($parent->node)) { 03078 $this->tree[$key] = array(); 03079 if (in_array((string)$parent['TEXT'], $types)) { 03080 $this->_select_nodes($parent, $this->result); 03081 } else { 03082 foreach($parent->node as $v){ 03083 $this->_browse_nodes($v, $types); 03084 } 03085 } 03086 } else { 03087 $this->tree[] = $key; 03088 } 03089 } 03090 03096 private function _select_nodes($parent){ 03097 if(isset($parent->node)) { 03098 foreach($parent->node as $v){ 03099 $this->_select_nodes($v, $this->result); 03100 } 03101 } else { 03102 $this->result[] = (string)$parent['TEXT']; 03103 } 03104 } 03105 03106 03113 public function get_extensions($types) { 03114 if (!is_array($types)) { 03115 $types = array($types); 03116 } 03117 $this->result = array(); 03118 if ((is_array($types) && in_array('*', $types)) || 03119 $types == '*' || empty($types)) { 03120 return array('*'); 03121 } 03122 foreach ($types as $key=>$value){ 03123 if (strpos($value, '.') !== false) { 03124 $this->result[] = $value; 03125 unset($types[$key]); 03126 } 03127 } 03128 if (file_exists($this->file)) { 03129 $xml = simplexml_load_file($this->file); 03130 foreach($xml->node->node as $v){ 03131 if (in_array((string)$v['TEXT'], $types)) { 03132 $this->_select_nodes($v); 03133 } else { 03134 $this->_browse_nodes($v, $types); 03135 } 03136 } 03137 } else { 03138 exit('Failed to open file lib/filestorage/file_types.mm'); 03139 } 03140 return $this->result; 03141 } 03142 } 03143 03155 function file_pluginfile($relativepath, $forcedownload) { 03156 global $DB, $CFG, $USER; 03157 // relative path must start with '/' 03158 if (!$relativepath) { 03159 print_error('invalidargorconf'); 03160 } else if ($relativepath[0] != '/') { 03161 print_error('pathdoesnotstartslash'); 03162 } 03163 03164 // extract relative path components 03165 $args = explode('/', ltrim($relativepath, '/')); 03166 03167 if (count($args) < 3) { // always at least context, component and filearea 03168 print_error('invalidarguments'); 03169 } 03170 03171 $contextid = (int)array_shift($args); 03172 $component = clean_param(array_shift($args), PARAM_COMPONENT); 03173 $filearea = clean_param(array_shift($args), PARAM_AREA); 03174 03175 list($context, $course, $cm) = get_context_info_array($contextid); 03176 03177 $fs = get_file_storage(); 03178 03179 // ======================================================================================================================== 03180 if ($component === 'blog') { 03181 // Blog file serving 03182 if ($context->contextlevel != CONTEXT_SYSTEM) { 03183 send_file_not_found(); 03184 } 03185 if ($filearea !== 'attachment' and $filearea !== 'post') { 03186 send_file_not_found(); 03187 } 03188 03189 if (empty($CFG->bloglevel)) { 03190 print_error('siteblogdisable', 'blog'); 03191 } 03192 03193 $entryid = (int)array_shift($args); 03194 if (!$entry = $DB->get_record('post', array('module'=>'blog', 'id'=>$entryid))) { 03195 send_file_not_found(); 03196 } 03197 if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) { 03198 require_login(); 03199 if (isguestuser()) { 03200 print_error('noguest'); 03201 } 03202 if ($CFG->bloglevel == BLOG_USER_LEVEL) { 03203 if ($USER->id != $entry->userid) { 03204 send_file_not_found(); 03205 } 03206 } 03207 } 03208 03209 if ('publishstate' === 'public') { 03210 if ($CFG->forcelogin) { 03211 require_login(); 03212 } 03213 03214 } else if ('publishstate' === 'site') { 03215 require_login(); 03216 //ok 03217 } else if ('publishstate' === 'draft') { 03218 require_login(); 03219 if ($USER->id != $entry->userid) { 03220 send_file_not_found(); 03221 } 03222 } 03223 03224 $filename = array_pop($args); 03225 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03226 03227 if (!$file = $fs->get_file($context->id, $component, $filearea, $entryid, $filepath, $filename) or $file->is_directory()) { 03228 send_file_not_found(); 03229 } 03230 03231 send_stored_file($file, 10*60, 0, true); // download MUST be forced - security! 03232 03233 // ======================================================================================================================== 03234 } else if ($component === 'grade') { 03235 if (($filearea === 'outcome' or $filearea === 'scale') and $context->contextlevel == CONTEXT_SYSTEM) { 03236 // Global gradebook files 03237 if ($CFG->forcelogin) { 03238 require_login(); 03239 } 03240 03241 $fullpath = "/$context->id/$component/$filearea/".implode('/', $args); 03242 03243 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 03244 send_file_not_found(); 03245 } 03246 03247 session_get_instance()->write_close(); // unlock session during fileserving 03248 send_stored_file($file, 60*60, 0, $forcedownload); 03249 03250 } else if ($filearea === 'feedback' and $context->contextlevel == CONTEXT_COURSE) { 03251 //TODO: nobody implemented this yet in grade edit form!! 03252 send_file_not_found(); 03253 03254 if ($CFG->forcelogin || $course->id != SITEID) { 03255 require_login($course); 03256 } 03257 03258 $fullpath = "/$context->id/$component/$filearea/".implode('/', $args); 03259 03260 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 03261 send_file_not_found(); 03262 } 03263 03264 session_get_instance()->write_close(); // unlock session during fileserving 03265 send_stored_file($file, 60*60, 0, $forcedownload); 03266 } else { 03267 send_file_not_found(); 03268 } 03269 03270 // ======================================================================================================================== 03271 } else if ($component === 'tag') { 03272 if ($filearea === 'description' and $context->contextlevel == CONTEXT_SYSTEM) { 03273 03274 // All tag descriptions are going to be public but we still need to respect forcelogin 03275 if ($CFG->forcelogin) { 03276 require_login(); 03277 } 03278 03279 $fullpath = "/$context->id/tag/description/".implode('/', $args); 03280 03281 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 03282 send_file_not_found(); 03283 } 03284 03285 session_get_instance()->write_close(); // unlock session during fileserving 03286 send_stored_file($file, 60*60, 0, true); 03287 03288 } else { 03289 send_file_not_found(); 03290 } 03291 03292 // ======================================================================================================================== 03293 } else if ($component === 'calendar') { 03294 if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_SYSTEM) { 03295 03296 // All events here are public the one requirement is that we respect forcelogin 03297 if ($CFG->forcelogin) { 03298 require_login(); 03299 } 03300 03301 // Get the event if from the args array 03302 $eventid = array_shift($args); 03303 03304 // Load the event from the database 03305 if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'eventtype'=>'site'))) { 03306 send_file_not_found(); 03307 } 03308 // Check that we got an event and that it's userid is that of the user 03309 03310 // Get the file and serve if successful 03311 $filename = array_pop($args); 03312 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03313 if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) { 03314 send_file_not_found(); 03315 } 03316 03317 session_get_instance()->write_close(); // unlock session during fileserving 03318 send_stored_file($file, 60*60, 0, $forcedownload); 03319 03320 } else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_USER) { 03321 03322 // Must be logged in, if they are not then they obviously can't be this user 03323 require_login(); 03324 03325 // Don't want guests here, potentially saves a DB call 03326 if (isguestuser()) { 03327 send_file_not_found(); 03328 } 03329 03330 // Get the event if from the args array 03331 $eventid = array_shift($args); 03332 03333 // Load the event from the database - user id must match 03334 if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'userid'=>$USER->id, 'eventtype'=>'user'))) { 03335 send_file_not_found(); 03336 } 03337 03338 // Get the file and serve if successful 03339 $filename = array_pop($args); 03340 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03341 if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) { 03342 send_file_not_found(); 03343 } 03344 03345 session_get_instance()->write_close(); // unlock session during fileserving 03346 send_stored_file($file, 60*60, 0, $forcedownload); 03347 03348 } else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_COURSE) { 03349 03350 // Respect forcelogin and require login unless this is the site.... it probably 03351 // should NEVER be the site 03352 if ($CFG->forcelogin || $course->id != SITEID) { 03353 require_login($course); 03354 } 03355 03356 // Must be able to at least view the course 03357 if (!is_enrolled($context) and !is_viewing($context)) { 03358 //TODO: hmm, do we really want to block guests here? 03359 send_file_not_found(); 03360 } 03361 03362 // Get the event id 03363 $eventid = array_shift($args); 03364 03365 // Load the event from the database we need to check whether it is 03366 // a) valid course event 03367 // b) a group event 03368 // Group events use the course context (there is no group context) 03369 if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'courseid'=>$course->id))) { 03370 send_file_not_found(); 03371 } 03372 03373 // If its a group event require either membership of view all groups capability 03374 if ($event->eventtype === 'group') { 03375 if (!has_capability('moodle/site:accessallgroups', $context) && !groups_is_member($event->groupid, $USER->id)) { 03376 send_file_not_found(); 03377 } 03378 } else if ($event->eventtype === 'course') { 03379 //ok 03380 } else { 03381 // some other type 03382 send_file_not_found(); 03383 } 03384 03385 // If we get this far we can serve the file 03386 $filename = array_pop($args); 03387 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03388 if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) { 03389 send_file_not_found(); 03390 } 03391 03392 session_get_instance()->write_close(); // unlock session during fileserving 03393 send_stored_file($file, 60*60, 0, $forcedownload); 03394 03395 } else { 03396 send_file_not_found(); 03397 } 03398 03399 // ======================================================================================================================== 03400 } else if ($component === 'user') { 03401 if ($filearea === 'icon' and $context->contextlevel == CONTEXT_USER) { 03402 $redirect = false; 03403 if (count($args) == 1) { 03404 $themename = theme_config::DEFAULT_THEME; 03405 $filename = array_shift($args); 03406 } else { 03407 $themename = array_shift($args); 03408 $filename = array_shift($args); 03409 } 03410 if ((!empty($CFG->forcelogin) and !isloggedin()) || 03411 (!empty($CFG->forceloginforprofileimage) && (!isloggedin() || isguestuser()))) { 03412 // protect images if login required and not logged in; 03413 // also if login is required for profile images and is not logged in or guest 03414 // do not use require_login() because it is expensive and not suitable here anyway 03415 $redirect = true; 03416 } 03417 if (!$redirect and ($filename !== 'f1' and $filename !== 'f2')) { 03418 $filename = 'f1'; 03419 $redirect = true; 03420 } 03421 if (!$redirect && !$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.png')) { 03422 if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg')) { 03423 $redirect = true; 03424 } 03425 } 03426 if ($redirect) { 03427 $theme = theme_config::load($themename); 03428 redirect($theme->pix_url('u/'.$filename, 'moodle')); 03429 } 03430 send_stored_file($file, 60*60*24); // enable long caching, there are many images on each page 03431 03432 } else if ($filearea === 'private' and $context->contextlevel == CONTEXT_USER) { 03433 require_login(); 03434 03435 if (isguestuser()) { 03436 send_file_not_found(); 03437 } 03438 03439 if ($USER->id !== $context->instanceid) { 03440 send_file_not_found(); 03441 } 03442 03443 $filename = array_pop($args); 03444 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03445 if (!$file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename) or $file->is_directory()) { 03446 send_file_not_found(); 03447 } 03448 03449 session_get_instance()->write_close(); // unlock session during fileserving 03450 send_stored_file($file, 0, 0, true); // must force download - security! 03451 03452 } else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_USER) { 03453 03454 if ($CFG->forcelogin) { 03455 require_login(); 03456 } 03457 03458 $userid = $context->instanceid; 03459 03460 if ($USER->id == $userid) { 03461 // always can access own 03462 03463 } else if (!empty($CFG->forceloginforprofiles)) { 03464 require_login(); 03465 03466 if (isguestuser()) { 03467 send_file_not_found(); 03468 } 03469 03470 // we allow access to site profile of all course contacts (usually teachers) 03471 if (!has_coursecontact_role($userid) && !has_capability('moodle/user:viewdetails', $context)) { 03472 send_file_not_found(); 03473 } 03474 03475 $canview = false; 03476 if (has_capability('moodle/user:viewdetails', $context)) { 03477 $canview = true; 03478 } else { 03479 $courses = enrol_get_my_courses(); 03480 } 03481 03482 while (!$canview && count($courses) > 0) { 03483 $course = array_shift($courses); 03484 if (has_capability('moodle/user:viewdetails', get_context_instance(CONTEXT_COURSE, $course->id))) { 03485 $canview = true; 03486 } 03487 } 03488 } 03489 03490 $filename = array_pop($args); 03491 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03492 if (!$file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename) or $file->is_directory()) { 03493 send_file_not_found(); 03494 } 03495 03496 session_get_instance()->write_close(); // unlock session during fileserving 03497 send_stored_file($file, 0, 0, true); // must force download - security! 03498 03499 } else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_COURSE) { 03500 $userid = (int)array_shift($args); 03501 $usercontext = get_context_instance(CONTEXT_USER, $userid); 03502 03503 if ($CFG->forcelogin) { 03504 require_login(); 03505 } 03506 03507 if (!empty($CFG->forceloginforprofiles)) { 03508 require_login(); 03509 if (isguestuser()) { 03510 print_error('noguest'); 03511 } 03512 03513 //TODO: review this logic of user profile access prevention 03514 if (!has_coursecontact_role($userid) and !has_capability('moodle/user:viewdetails', $usercontext)) { 03515 print_error('usernotavailable'); 03516 } 03517 if (!has_capability('moodle/user:viewdetails', $context) && !has_capability('moodle/user:viewdetails', $usercontext)) { 03518 print_error('cannotviewprofile'); 03519 } 03520 if (!is_enrolled($context, $userid)) { 03521 print_error('notenrolledprofile'); 03522 } 03523 if (groups_get_course_groupmode($course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 03524 print_error('groupnotamember'); 03525 } 03526 } 03527 03528 $filename = array_pop($args); 03529 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03530 if (!$file = $fs->get_file($usercontext->id, 'user', 'profile', 0, $filepath, $filename) or $file->is_directory()) { 03531 send_file_not_found(); 03532 } 03533 03534 session_get_instance()->write_close(); // unlock session during fileserving 03535 send_stored_file($file, 0, 0, true); // must force download - security! 03536 03537 } else if ($filearea === 'backup' and $context->contextlevel == CONTEXT_USER) { 03538 require_login(); 03539 03540 if (isguestuser()) { 03541 send_file_not_found(); 03542 } 03543 $userid = $context->instanceid; 03544 03545 if ($USER->id != $userid) { 03546 send_file_not_found(); 03547 } 03548 03549 $filename = array_pop($args); 03550 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03551 if (!$file = $fs->get_file($context->id, 'user', 'backup', 0, $filepath, $filename) or $file->is_directory()) { 03552 send_file_not_found(); 03553 } 03554 03555 session_get_instance()->write_close(); // unlock session during fileserving 03556 send_stored_file($file, 0, 0, true); // must force download - security! 03557 03558 } else { 03559 send_file_not_found(); 03560 } 03561 03562 // ======================================================================================================================== 03563 } else if ($component === 'coursecat') { 03564 if ($context->contextlevel != CONTEXT_COURSECAT) { 03565 send_file_not_found(); 03566 } 03567 03568 if ($filearea === 'description') { 03569 if ($CFG->forcelogin) { 03570 // no login necessary - unless login forced everywhere 03571 require_login(); 03572 } 03573 03574 $filename = array_pop($args); 03575 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03576 if (!$file = $fs->get_file($context->id, 'coursecat', 'description', 0, $filepath, $filename) or $file->is_directory()) { 03577 send_file_not_found(); 03578 } 03579 03580 session_get_instance()->write_close(); // unlock session during fileserving 03581 send_stored_file($file, 60*60, 0, $forcedownload); 03582 } else { 03583 send_file_not_found(); 03584 } 03585 03586 // ======================================================================================================================== 03587 } else if ($component === 'course') { 03588 if ($context->contextlevel != CONTEXT_COURSE) { 03589 send_file_not_found(); 03590 } 03591 03592 if ($filearea === 'summary') { 03593 if ($CFG->forcelogin) { 03594 require_login(); 03595 } 03596 03597 $filename = array_pop($args); 03598 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03599 if (!$file = $fs->get_file($context->id, 'course', 'summary', 0, $filepath, $filename) or $file->is_directory()) { 03600 send_file_not_found(); 03601 } 03602 03603 session_get_instance()->write_close(); // unlock session during fileserving 03604 send_stored_file($file, 60*60, 0, $forcedownload); 03605 03606 } else if ($filearea === 'section') { 03607 if ($CFG->forcelogin) { 03608 require_login($course); 03609 } else if ($course->id != SITEID) { 03610 require_login($course); 03611 } 03612 03613 $sectionid = (int)array_shift($args); 03614 03615 if (!$section = $DB->get_record('course_sections', array('id'=>$sectionid, 'course'=>$course->id))) { 03616 send_file_not_found(); 03617 } 03618 03619 if ($course->numsections < $section->section) { 03620 if (!has_capability('moodle/course:update', $context)) { 03621 // block access to unavailable sections if can not edit course 03622 send_file_not_found(); 03623 } 03624 } 03625 03626 $filename = array_pop($args); 03627 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03628 if (!$file = $fs->get_file($context->id, 'course', 'section', $sectionid, $filepath, $filename) or $file->is_directory()) { 03629 send_file_not_found(); 03630 } 03631 03632 session_get_instance()->write_close(); // unlock session during fileserving 03633 send_stored_file($file, 60*60, 0, $forcedownload); 03634 03635 } else { 03636 send_file_not_found(); 03637 } 03638 03639 } else if ($component === 'group') { 03640 if ($context->contextlevel != CONTEXT_COURSE) { 03641 send_file_not_found(); 03642 } 03643 03644 require_course_login($course, true, null, false); 03645 03646 $groupid = (int)array_shift($args); 03647 03648 $group = $DB->get_record('groups', array('id'=>$groupid, 'courseid'=>$course->id), '*', MUST_EXIST); 03649 if (($course->groupmodeforce and $course->groupmode == SEPARATEGROUPS) and !has_capability('moodle/site:accessallgroups', $context) and !groups_is_member($group->id, $USER->id)) { 03650 // do not allow access to separate group info if not member or teacher 03651 send_file_not_found(); 03652 } 03653 03654 if ($filearea === 'description') { 03655 03656 require_login($course); 03657 03658 $filename = array_pop($args); 03659 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03660 if (!$file = $fs->get_file($context->id, 'group', 'description', $group->id, $filepath, $filename) or $file->is_directory()) { 03661 send_file_not_found(); 03662 } 03663 03664 session_get_instance()->write_close(); // unlock session during fileserving 03665 send_stored_file($file, 60*60, 0, $forcedownload); 03666 03667 } else if ($filearea === 'icon') { 03668 $filename = array_pop($args); 03669 03670 if ($filename !== 'f1' and $filename !== 'f2') { 03671 send_file_not_found(); 03672 } 03673 if (!$file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename.'.png')) { 03674 if (!$file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename.'.jpg')) { 03675 send_file_not_found(); 03676 } 03677 } 03678 03679 session_get_instance()->write_close(); // unlock session during fileserving 03680 send_stored_file($file, 60*60); 03681 03682 } else { 03683 send_file_not_found(); 03684 } 03685 03686 } else if ($component === 'grouping') { 03687 if ($context->contextlevel != CONTEXT_COURSE) { 03688 send_file_not_found(); 03689 } 03690 03691 require_login($course); 03692 03693 $groupingid = (int)array_shift($args); 03694 03695 // note: everybody has access to grouping desc images for now 03696 if ($filearea === 'description') { 03697 03698 $filename = array_pop($args); 03699 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03700 if (!$file = $fs->get_file($context->id, 'grouping', 'description', $groupingid, $filepath, $filename) or $file->is_directory()) { 03701 send_file_not_found(); 03702 } 03703 03704 session_get_instance()->write_close(); // unlock session during fileserving 03705 send_stored_file($file, 60*60, 0, $forcedownload); 03706 03707 } else { 03708 send_file_not_found(); 03709 } 03710 03711 // ======================================================================================================================== 03712 } else if ($component === 'backup') { 03713 if ($filearea === 'course' and $context->contextlevel == CONTEXT_COURSE) { 03714 require_login($course); 03715 require_capability('moodle/backup:downloadfile', $context); 03716 03717 $filename = array_pop($args); 03718 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03719 if (!$file = $fs->get_file($context->id, 'backup', 'course', 0, $filepath, $filename) or $file->is_directory()) { 03720 send_file_not_found(); 03721 } 03722 03723 session_get_instance()->write_close(); // unlock session during fileserving 03724 send_stored_file($file, 0, 0, $forcedownload); 03725 03726 } else if ($filearea === 'section' and $context->contextlevel == CONTEXT_COURSE) { 03727 require_login($course); 03728 require_capability('moodle/backup:downloadfile', $context); 03729 03730 $sectionid = (int)array_shift($args); 03731 03732 $filename = array_pop($args); 03733 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03734 if (!$file = $fs->get_file($context->id, 'backup', 'section', $sectionid, $filepath, $filename) or $file->is_directory()) { 03735 send_file_not_found(); 03736 } 03737 03738 session_get_instance()->write_close(); 03739 send_stored_file($file, 60*60, 0, $forcedownload); 03740 03741 } else if ($filearea === 'activity' and $context->contextlevel == CONTEXT_MODULE) { 03742 require_login($course, false, $cm); 03743 require_capability('moodle/backup:downloadfile', $context); 03744 03745 $filename = array_pop($args); 03746 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03747 if (!$file = $fs->get_file($context->id, 'backup', 'activity', 0, $filepath, $filename) or $file->is_directory()) { 03748 send_file_not_found(); 03749 } 03750 03751 session_get_instance()->write_close(); 03752 send_stored_file($file, 60*60, 0, $forcedownload); 03753 03754 } else if ($filearea === 'automated' and $context->contextlevel == CONTEXT_COURSE) { 03755 // Backup files that were generated by the automated backup systems. 03756 03757 require_login($course); 03758 require_capability('moodle/site:config', $context); 03759 03760 $filename = array_pop($args); 03761 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03762 if (!$file = $fs->get_file($context->id, 'backup', 'automated', 0, $filepath, $filename) or $file->is_directory()) { 03763 send_file_not_found(); 03764 } 03765 03766 session_get_instance()->write_close(); // unlock session during fileserving 03767 send_stored_file($file, 0, 0, $forcedownload); 03768 03769 } else { 03770 send_file_not_found(); 03771 } 03772 03773 // ======================================================================================================================== 03774 } else if ($component === 'question') { 03775 require_once($CFG->libdir . '/questionlib.php'); 03776 question_pluginfile($course, $context, 'question', $filearea, $args, $forcedownload); 03777 send_file_not_found(); 03778 03779 // ======================================================================================================================== 03780 } else if ($component === 'grading') { 03781 if ($filearea === 'description') { 03782 // files embedded into the form definition description 03783 03784 if ($context->contextlevel == CONTEXT_SYSTEM) { 03785 require_login(); 03786 03787 } else if ($context->contextlevel >= CONTEXT_COURSE) { 03788 require_login($course, false, $cm); 03789 03790 } else { 03791 send_file_not_found(); 03792 } 03793 03794 $formid = (int)array_shift($args); 03795 03796 $sql = "SELECT ga.id 03797 FROM {grading_areas} ga 03798 JOIN {grading_definitions} gd ON (gd.areaid = ga.id) 03799 WHERE gd.id = ? AND ga.contextid = ?"; 03800 $areaid = $DB->get_field_sql($sql, array($formid, $context->id), IGNORE_MISSING); 03801 03802 if (!$areaid) { 03803 send_file_not_found(); 03804 } 03805 03806 $fullpath = "/$context->id/$component/$filearea/$formid/".implode('/', $args); 03807 03808 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 03809 send_file_not_found(); 03810 } 03811 03812 session_get_instance()->write_close(); // unlock session during fileserving 03813 send_stored_file($file, 60*60, 0, $forcedownload); 03814 } 03815 03816 // ======================================================================================================================== 03817 } else if (strpos($component, 'mod_') === 0) { 03818 $modname = substr($component, 4); 03819 if (!file_exists("$CFG->dirroot/mod/$modname/lib.php")) { 03820 send_file_not_found(); 03821 } 03822 require_once("$CFG->dirroot/mod/$modname/lib.php"); 03823 03824 if ($context->contextlevel == CONTEXT_MODULE) { 03825 if ($cm->modname !== $modname) { 03826 // somebody tries to gain illegal access, cm type must match the component! 03827 send_file_not_found(); 03828 } 03829 } 03830 03831 if ($filearea === 'intro') { 03832 if (!plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)) { 03833 send_file_not_found(); 03834 } 03835 require_course_login($course, true, $cm); 03836 03837 // all users may access it 03838 $filename = array_pop($args); 03839 $filepath = $args ? '/'.implode('/', $args).'/' : '/'; 03840 if (!$file = $fs->get_file($context->id, 'mod_'.$modname, 'intro', 0, $filepath, $filename) or $file->is_directory()) { 03841 send_file_not_found(); 03842 } 03843 03844 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400; 03845 03846 // finally send the file 03847 send_stored_file($file, $lifetime, 0); 03848 } 03849 03850 $filefunction = $component.'_pluginfile'; 03851 $filefunctionold = $modname.'_pluginfile'; 03852 if (function_exists($filefunction)) { 03853 // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" 03854 $filefunction($course, $cm, $context, $filearea, $args, $forcedownload); 03855 } else if (function_exists($filefunctionold)) { 03856 // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" 03857 $filefunctionold($course, $cm, $context, $filearea, $args, $forcedownload); 03858 } 03859 03860 send_file_not_found(); 03861 03862 // ======================================================================================================================== 03863 } else if (strpos($component, 'block_') === 0) { 03864 $blockname = substr($component, 6); 03865 // note: no more class methods in blocks please, that is .... 03866 if (!file_exists("$CFG->dirroot/blocks/$blockname/lib.php")) { 03867 send_file_not_found(); 03868 } 03869 require_once("$CFG->dirroot/blocks/$blockname/lib.php"); 03870 03871 if ($context->contextlevel == CONTEXT_BLOCK) { 03872 $birecord = $DB->get_record('block_instances', array('id'=>$context->instanceid), '*',MUST_EXIST); 03873 if ($birecord->blockname !== $blockname) { 03874 // somebody tries to gain illegal access, cm type must match the component! 03875 send_file_not_found(); 03876 } 03877 } else { 03878 $birecord = null; 03879 } 03880 03881 $filefunction = $component.'_pluginfile'; 03882 if (function_exists($filefunction)) { 03883 // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" 03884 $filefunction($course, $birecord, $context, $filearea, $args, $forcedownload); 03885 } 03886 03887 send_file_not_found(); 03888 03889 } else if (strpos($component, '_') === false) { 03890 // all core subsystems have to be specified above, no more guessing here! 03891 send_file_not_found(); 03892 03893 } else { 03894 // try to serve general plugin file in arbitrary context 03895 $dir = get_component_directory($component); 03896 if (!file_exists("$dir/lib.php")) { 03897 send_file_not_found(); 03898 } 03899 include_once("$dir/lib.php"); 03900 03901 $filefunction = $component.'_pluginfile'; 03902 if (function_exists($filefunction)) { 03903 // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found" 03904 $filefunction($course, $cm, $context, $filearea, $args, $forcedownload); 03905 } 03906 03907 send_file_not_found(); 03908 } 03909 03910 }