Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/filelib.php
Go to the documentation of this file.
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 .= '&amp;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 }
 All Data Structures Namespaces Files Functions Variables Enumerations