/** * Is this filename valid (contains a unique participant ID) for import? * * @param sepl $seplment - The seplment instance * @param stored_file $fileinfo - The fileinfo * @param array $participants - A list of valid participants for this module indexed by unique_id * @param stdClass $user - Set to the user that matches by participant id * @param sepl_plugin $plugin - Set to the plugin that exported the file * @param string $filename - Set to truncated filename (prefix stripped) * @return true If the participant Id can be extracted and this is a valid user */ public function is_valid_filename_for_import($seplment, $fileinfo, $participants, &$user, &$plugin, &$filename) { if ($fileinfo->is_directory()) { return false; } // Ignore hidden files. if (strpos($fileinfo->get_filename(), '.') === 0) { return false; } // Ignore hidden files. if (strpos($fileinfo->get_filename(), '~') === 0) { return false; } $info = explode('_', $fileinfo->get_filename(), 5); if (count($info) < 5) { return false; } $participantid = $info[1]; $filename = $info[4]; $plugin = $seplment->get_plugin_by_type($info[2], $info[3]); if (!is_numeric($participantid)) { return false; } if (!$plugin) { return false; } // Convert to int. $participantid += 0; if (empty($participants[$participantid])) { return false; } $user = $participants[$participantid]; return true; }
/** * Perform archiving file from stored file. * * @param zip_archive $ziparch zip archive instance * @param string $archivepath file path to archive * @param stored_file $file stored_file object * @param file_progress $progress Progress indicator callback or null if not required * @return bool success */ private function archive_stored($ziparch, $archivepath, $file, file_progress $progress = null) { $result = $file->archive_file($ziparch, $archivepath); if (!$result) { return false; } if (!$file->is_directory()) { return true; } $baselength = strlen($file->get_filepath()); $fs = get_file_storage(); $files = $fs->get_directory_files($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), true, true); foreach ($files as $file) { // Record progress for each file. if ($progress) { $progress->progress(); } $path = $file->get_filepath(); $path = substr($path, $baselength); $path = $archivepath . '/' . $path; if (!$file->is_directory()) { $path = $path . $file->get_filename(); } // Ignore result here, partial zipping is ok for now. $file->archive_file($ziparch, $path); } return true; }
/** * xmldb_hotpot_move_file * * move a file or folder (within the same context) * if $file is a directory, then all subfolders and files will also be moved * if the destination file/folder already exists, then $file will be deleted * * @param stored_file $file * @param string $new_filepath * @param string $new_filename (optional, default='') * @return void, but may update filearea */ function xmldb_hotpot_move_file($file, $new_filepath, $new_filename = '') { $fs = get_file_storage(); $contextid = $file->get_contextid(); $component = $file->get_component(); $filearea = $file->get_filearea(); $itemid = $file->get_itemid(); $old_filepath = $file->get_filepath(); $old_filename = $file->get_filename(); if ($file->is_directory()) { $children = $fs->get_directory_files($contextid, $component, $filearea, $itemid, $old_filepath); $old_filepath = '/^' . preg_quote($old_filepath, '/') . '/'; foreach ($children as $child) { xmldb_hotpot_move_file($child, preg_replace($old_filepath, $new_filepath, $child->get_filepath(), 1)); } } if ($new_filename == '') { $new_filename = $old_filename; } if ($fs->file_exists($contextid, $component, $filearea, $itemid, $new_filepath, $new_filename)) { $file->delete(); // new file already exists } else { $file->rename($new_filepath, $new_filename); } }
/** * Based on a stored_file objects, adds either that file (if it's a file) or * all its children (if it's a directory) into the list of files to * archive. * * If a progress indicator is supplied and if this corresponds to a * directory, then it will be repeatedly called with the same values. This * allows the progress handler to respond in some way to avoid timeouts * if required. * * @param array $expandedfiles List of all files to archive (output) * @param string $archivepath Current path within archive * @param stored_file $file File object */ protected function list_files_stored(array &$expandedfiles, $archivepath, stored_file $file) { if ($file->is_directory()) { // Add a directory-creation record. $expandedfiles[$archivepath . '/'] = null; // Loop through directory contents (this is a recursive collection // of all children not just one directory). $fs = get_file_storage(); $baselength = strlen($file->get_filepath()); $files = $fs->get_directory_files($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), true, true); foreach ($files as $childfile) { // Get full pathname after original part. $path = $childfile->get_filepath(); $path = substr($path, $baselength); $path = $archivepath . '/' . $path; if ($childfile->is_directory()) { $childfile = null; } else { $path .= $childfile->get_filename(); } $expandedfiles[$path] = $childfile; } } else { // Just add it to list. $expandedfiles[$archivepath] = $file; } }
/** * Handles the sending of file data to the user's browser, including support for * byteranges etc. * * @category files * @global stdClass $CFG * @global stdClass $COURSE * @global moodle_session $SESSION * @param stored_file $stored_file local file object * @param int $lifetime Number of seconds before the file should expire from caches (default 24 hours) * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin * @param string $filename Override filename * @param bool $dontdie - return control to caller afterwards. this is not recommended and only used for cleanup tasks. * if this is passed as true, ignore_user_abort is called. if you don't want your processing to continue on cancel, * you must detect this case when control is returned using connection_aborted. Please not that session is closed * and should not be reopened. * @return null script execution stopped unless $dontdie is true */ function send_stored_file($stored_file, $lifetime = 86400, $filter = 0, $forcedownload = false, $filename = null, $dontdie = false) { global $CFG, $COURSE, $SESSION; if (!$stored_file or $stored_file->is_directory()) { // nothing to serve if ($dontdie) { return; } die; } if ($dontdie) { ignore_user_abort(true); } session_get_instance()->write_close(); // unlock session during fileserving // Use given MIME type if specified, otherwise guess it using mimeinfo. // IE, Konqueror and Opera open html file directly in browser from web even when directed to save it to disk :-O // only Firefox saves all files locally before opening when content-disposition: attachment stated $filename = is_null($filename) ? $stored_file->get_filename() : $filename; $isFF = check_browser_version('Firefox', '1.5'); // only FF > 1.5 properly tested $mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' : ($stored_file->get_mimetype() ? $stored_file->get_mimetype() : mimeinfo('type', $filename)); $lastmodified = $stored_file->get_timemodified(); $filesize = $stored_file->get_filesize(); if ($lifetime > 0 && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { // get unixtime of request header; clip extra junk off first $since = strtotime(preg_replace('/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"])); if ($since && $since >= $lastmodified) { header('HTTP/1.1 304 Not Modified'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); header('Cache-Control: max-age=' . $lifetime); header('Content-Type: ' . $mimetype); if ($dontdie) { return; } die; } } //do not put '@' before the next header to detect incorrect moodle configurations, //error should be better than "weird" empty lines for admins/users header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastmodified) . ' GMT'); // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup if (check_browser_version('MSIE')) { $filename = rawurlencode($filename); } if ($forcedownload) { header('Content-Disposition: attachment; filename="' . $filename . '"'); } else { header('Content-Disposition: inline; filename="' . $filename . '"'); } if ($lifetime > 0) { header('Cache-Control: max-age=' . $lifetime); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); header('Pragma: '); if (empty($CFG->disablebyteserving) && $mimetype != 'text/plain' && $mimetype != 'text/html') { header('Accept-Ranges: bytes'); if (!empty($_SERVER['HTTP_RANGE']) && strpos($_SERVER['HTTP_RANGE'], 'bytes=') !== FALSE) { // byteserving stuff - for acrobat reader and download accelerators // see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 // inspired by: http://www.coneural.org/florian/papers/04_byteserving.php $ranges = false; if (preg_match_all('/(\\d*)-(\\d*)/', $_SERVER['HTTP_RANGE'], $ranges, PREG_SET_ORDER)) { foreach ($ranges as $key => $value) { if ($ranges[$key][1] == '') { //suffix case $ranges[$key][1] = $filesize - $ranges[$key][2]; $ranges[$key][2] = $filesize - 1; } else { if ($ranges[$key][2] == '' || $ranges[$key][2] > $filesize - 1) { //fix range length $ranges[$key][2] = $filesize - 1; } } if ($ranges[$key][2] != '' && $ranges[$key][2] < $ranges[$key][1]) { //invalid byte-range ==> ignore header $ranges = false; break; } //prepare multipart header $ranges[$key][0] = "\r\n--" . BYTESERVING_BOUNDARY . "\r\nContent-Type: {$mimetype}\r\n"; $ranges[$key][0] .= "Content-Range: bytes {$ranges[$key][1]}-{$ranges[$key][2]}/{$filesize}\r\n\r\n"; } } else { $ranges = false; } if ($ranges) { byteserving_send_file($stored_file->get_content_file_handle(), $mimetype, $ranges, $filesize); } } } else { /// Do not byteserve (disabled, strings, text and html files). header('Accept-Ranges: none'); } } else { // Do not cache files in proxies and browsers if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431 header('Cache-Control: max-age=10'); header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT'); header('Pragma: '); } else { //normal http - prevent caching at all cost header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0'); header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT'); header('Pragma: no-cache'); } header('Accept-Ranges: none'); // Do not allow byteserving when caching disabled } if (empty($filter)) { if ($mimetype == 'text/plain') { header('Content-Type: Text/plain; charset=utf-8'); //add encoding } else { header('Content-Type: ' . $mimetype); } header('Content-Length: ' . $filesize); //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents $stored_file->readfile(); } else { // Try to put the file through filters if ($mimetype == 'text/html') { $options = new stdClass(); $options->noclean = true; $options->nocache = true; // temporary workaround for MDL-5136 $text = $stored_file->get_content(); $text = file_modify_html_header($text); $output = format_text($text, FORMAT_HTML, $options, $COURSE->id); header('Content-Length: ' . strlen($output)); header('Content-Type: text/html'); //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents echo $output; } else { if ($mimetype == 'text/plain' and $filter == 1) { // only filter text if filter all files is selected $options = new stdClass(); $options->newlines = false; $options->noclean = true; $text = $stored_file->get_content(); $output = '<pre>' . format_text($text, FORMAT_MOODLE, $options, $COURSE->id) . '</pre>'; header('Content-Length: ' . strlen($output)); header('Content-Type: text/html; charset=utf-8'); //add encoding //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents echo $output; } else { // Just send it out raw header('Content-Length: ' . $filesize); header('Content-Type: ' . $mimetype); //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents $stored_file->readfile(); } } } if ($dontdie) { return; } die; //no more chars to output!!! }
/** * Perform archiving file from stored file * * @param zip_archive $ziparch zip archive instance * @param string $archivepath file path to archive * @param stored_file $file stored_file object */ private function archive_stored($ziparch, $archivepath, $file) { $file->archive_file($ziparch, $archivepath); if (!$file->is_directory()) { return; } $baselength = strlen($file->get_filepath()); $fs = get_file_storage(); $files = $fs->get_directory_files($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), true, true); foreach ($files as $file) { $path = $file->get_filepath(); $path = substr($path, $baselength); $path = $archivepath . '/' . $path; if (!$file->is_directory()) { $path = $path . $file->get_filename(); } $file->archive_file($ziparch, $path); } }