/** * 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; }
/** * Check if the given file is capable of being imported by this plugin. * As {@link file_storage::mimetype()} now uses finfo PHP extension if available, * the value returned by $file->get_mimetype for a .dat file is not the same on all servers. * So we must made 2 checks to verify if the plugin can import the file. * @param stored_file $file the file to check * @return bool whether this plugin can import the file */ public function can_import_file($file) { $mimetypes = array( mimeinfo('type', '.dat'), mimeinfo('type', '.zip') ); return in_array($file->get_mimetype(), $mimetypes) || in_array(mimeinfo('type', $file->get_filename()), $mimetypes); }
/** * Given a stored file, get its file name, but make * sure that it does not conflict with any other * attachments in the file pool. * * @param \stored_file $file * @return string */ protected function resolve_file_name(\stored_file $file) { $filename = $file->get_filename(); $pathinfo = pathinfo($filename); $count = 1; while (array_key_exists('attachments/' . $filename, $this->archivefiles)) { $filename = $pathinfo['filename'] . '_' . $count . '.' . $pathinfo['extension']; $count++; } return $filename; }
/** * 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; }
/** * Get the URL of a file that belongs to a response variable of this * question_attempt. * @param stored_file $file the file to link to. * @return string the URL of that file. */ public function get_response_file_url(stored_file $file) { return file_encode_url(new moodle_url('/pluginfile.php'), '/' . implode('/', array($file->get_contextid(), $file->get_component(), $file->get_filearea(), $this->usageid, $this->slot, $file->get_itemid())) . $file->get_filepath() . $file->get_filename(), true); }
/** * Make url based on file for theme_snap components only. * * @param stored_file $file * @return \moodle_url | bool */ private static function snap_pluginfile_url($file) { if (!$file) { return false; } else { return \moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_timemodified(), $file->get_filepath(), $file->get_filename()); } }
/** * Resize the image, if required, then generate an img tag and, if required, a link to the full-size image * @param stored_file $file the image file to process * @param int $maxwidth the maximum width allowed for the image * @param int $maxheight the maximum height allowed for the image * @return string HTML fragment to add to the label */ function label_generate_resized_image(stored_file $file, $maxwidth, $maxheight) { global $CFG; $fullurl = moodle_url::make_draftfile_url($file->get_itemid(), $file->get_filepath(), $file->get_filename()); $link = null; $attrib = array('alt' => $file->get_filename(), 'src' => $fullurl); if ($imginfo = $file->get_imageinfo()) { // Work out the new width / height, bounded by maxwidth / maxheight $width = $imginfo['width']; $height = $imginfo['height']; if (!empty($maxwidth) && $width > $maxwidth) { $height *= (double) $maxwidth / $width; $width = $maxwidth; } if (!empty($maxheight) && $height > $maxheight) { $width *= (double) $maxheight / $height; $height = $maxheight; } $attrib['width'] = $width; $attrib['height'] = $height; // If the size has changed and the image is of a suitable mime type, generate a smaller version if ($width != $imginfo['width']) { $mimetype = $file->get_mimetype(); if ($mimetype === 'image/gif' or $mimetype === 'image/jpeg' or $mimetype === 'image/png') { require_once $CFG->libdir . '/gdlib.php'; $tmproot = make_temp_directory('mod_label'); $tmpfilepath = $tmproot . '/' . $file->get_contenthash(); $file->copy_content_to($tmpfilepath); $data = generate_image_thumbnail($tmpfilepath, $width, $height); unlink($tmpfilepath); if (!empty($data)) { $fs = get_file_storage(); $record = array('contextid' => $file->get_contextid(), 'component' => $file->get_component(), 'filearea' => $file->get_filearea(), 'itemid' => $file->get_itemid(), 'filepath' => '/', 'filename' => 's_' . $file->get_filename()); $smallfile = $fs->create_file_from_string($record, $data); // Replace the image 'src' with the resized file and link to the original $attrib['src'] = moodle_url::make_draftfile_url($smallfile->get_itemid(), $smallfile->get_filepath(), $smallfile->get_filename()); $link = $fullurl; } } } } else { // Assume this is an image type that get_imageinfo cannot handle (e.g. SVG) $attrib['width'] = $maxwidth; } $img = html_writer::empty_tag('img', $attrib); if ($link) { return html_writer::link($link, $img); } else { return $img; } }
/** * Export the data for the given file in relation to this document. * * @param \stored_file $file The stored file we are talking about. * @return array */ public function export_file_for_engine($file) { $data = $this->export_for_engine(); // Content is index in the main document. unset($data['content']); unset($data['description1']); unset($data['description2']); // Going to append the fileid to give it a unique id. $data['id'] = $data['id'] . '-solrfile' . $file->get_id(); $data['type'] = \core_search\manager::TYPE_FILE; $data['solr_fileid'] = $file->get_id(); $data['solr_filecontenthash'] = $file->get_contenthash(); $data['solr_fileindexstatus'] = self::INDEXED_FILE_TRUE; $data['title'] = $file->get_filename(); $data['modified'] = self::format_time_for_engine($file->get_timemodified()); return $data; }
/** * Repository method to serve the referenced file * * @see send_stored_file * * @param stored_file $storedfile the file that contains the reference * @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 array $options additional options affecting the file serving */ public function send_file($storedfile, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) { $reference = $storedfile->get_reference(); if ($reference{0} == '/') { $file = $this->root_path.substr($reference, 1, strlen($reference)-1); } else { $file = $this->root_path.$reference; } if (is_readable($file)) { $filename = $storedfile->get_filename(); if ($options && isset($options['filename'])) { $filename = $options['filename']; } $dontdie = ($options && isset($options['dontdie'])); send_file($file, $filename, $lifetime , $filter, false, $forcedownload, '', $dontdie); } else { send_file_not_found(); } }
/** * Utility function for getting a file URL * * @param stored_file $file * @return string file url */ private function util_get_file_url($file) { return moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename(), false); }
/** * Repository method to serve the referenced file * * This method is ivoked from {@link send_stored_file()}. * Dropbox repository first caches the file by reading it into temporary folder and then * serves from there. * * @param stored_file $storedfile the file that contains the reference * @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 array $options additional options affecting the file serving */ public function send_file($storedfile, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) { $fileinfo = $this->get_file_by_reference((object)array('reference' => $storedfile->get_reference())); if ($fileinfo && !empty($fileinfo->filepath) && is_readable($fileinfo->filepath)) { $filename = $storedfile->get_filename(); if ($options && isset($options['filename'])) { $filename = $options['filename']; } $dontdie = ($options && isset($options['dontdie'])); send_file($fileinfo->filepath, $filename, $lifetime , $filter, false, $forcedownload, '', $dontdie); } else { send_file_not_found(); } }
static function ensure_pdf_compatible(stored_file $file) { global $CFG; $fp = $file->get_content_file_handle(); $ident = fread($fp, 10); if (substr_compare('%PDF-', $ident, 0, 5) !== 0) { return false; // This is not a PDF file at all } $ident = substr($ident, 5); // Remove the '%PDF-' part $ident = explode('\\x0A', $ident); // Truncate to first '0a' character list($major, $minor) = explode('.', $ident[0]); // Split the major / minor version $major = intval($major); $minor = intval($minor); if ($major == 0 || $minor == 0) { return false; // Not a valid PDF version number } if ($major = 1 && $minor <= 4) { return true; // We can handle this version - nothing else to do } $temparea = $CFG->dataroot . '/temp/uploadpdf'; $hash = $file->get_contenthash(); $tempsrc = $temparea . "/src-{$hash}.pdf"; $tempdst = $temparea . "/dst-{$hash}.pdf"; if (!file_exists($temparea)) { if (!mkdir($temparea, 0777, true)) { die("Unable to create temporary folder {$temparea}"); } } $file->copy_content_to($tempsrc); // Copy the file $gsexec = $CFG->gs_path; $command = "{$gsexec} -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=\"{$tempdst}\" \"{$tempsrc}\" 2>&1"; $result = exec($command); if (!file_exists($tempdst)) { return false; // Something has gone wrong in the conversion } $file->delete(); // Delete the original file $fs = get_file_storage(); $fileinfo = array('contextid' => $file->get_contextid(), 'component' => $file->get_component(), 'filearea' => $file->get_filearea(), 'itemid' => $file->get_itemid(), 'filename' => $file->get_filename(), 'filepath' => $file->get_filepath()); $fs->create_file_from_pathname($fileinfo, $tempdst); // Create replacement file @unlink($tempsrc); // Delete the temporary files @unlink($tempdst); return true; }
/** * Downloads the file from external repository and saves it in moodle filepool. * This function is different from {@link repository::sync_reference()} because it has * bigger request timeout and always downloads the content. * * This function is invoked when we try to unlink the file from the source and convert * a reference into a true copy. * * @throws exception when file could not be imported * * @param stored_file $file * @param int $maxbytes throw an exception if file size is bigger than $maxbytes (0 means no limit) */ public function import_external_file_contents(stored_file $file, $maxbytes = 0) { if (!$file->is_external_file()) { // nothing to import if the file is not a reference return; } else { if ($file->get_repository_id() != $this->id) { // error debugging('Repository instance id does not match'); return; } else { if ($this->has_moodle_files()) { // files that are references to local files are already in moodle filepool // just validate the size if ($maxbytes > 0 && $file->get_filesize() > $maxbytes) { $maxbytesdisplay = display_size($maxbytes); throw new file_exception('maxbytesfile', (object) array('file' => $file->get_filename(), 'size' => $maxbytesdisplay)); } return; } else { if ($maxbytes > 0 && $file->get_filesize() > $maxbytes) { // note that stored_file::get_filesize() also calls synchronisation $maxbytesdisplay = display_size($maxbytes); throw new file_exception('maxbytesfile', (object) array('file' => $file->get_filename(), 'size' => $maxbytesdisplay)); } $fs = get_file_storage(); $contentexists = $fs->content_exists($file->get_contenthash()); if ($contentexists && $file->get_filesize() && $file->get_contenthash() === sha1('')) { // even when 'file_storage::content_exists()' returns true this may be an empty // content for the file that was not actually downloaded $contentexists = false; } if (!$file->get_status() && $contentexists) { // we already have the content in moodle filepool and it was synchronised recently. // Repositories may overwrite it if they want to force synchronisation anyway! return; } else { // attempt to get a file try { $fileinfo = $this->get_file($file->get_reference()); if (isset($fileinfo['path'])) { list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($fileinfo['path']); // set this file and other similar aliases synchronised $file->set_synchronized($contenthash, $filesize); } else { throw new moodle_exception('errorwhiledownload', 'repository', '', ''); } } catch (Exception $e) { if ($contentexists) { // better something than nothing. We have a copy of file. It's sync time // has expired but it is still very likely that it is the last version } else { throw $e; } } } } } } }
/** * Repository method to serve file * * @param stored_file $storedfile * @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 array $options additional options affecting the file serving */ public function send_file($storedfile, $lifetime = 86400, $filter = 0, $forcedownload = false, array $options = null) { $reference = unserialize($storedfile->get_reference()); $cachedfilepath = cache_file::get($reference, array('ttl' => $this->cachedfilettl)); if ($cachedfilepath === false) { // Cache the file. $this->set_access_key($reference->access_key); $this->set_access_secret($reference->access_secret); $path = $this->get_file($reference->path); $cachedfilepath = cache_file::create_from_file($reference, $path['path']); } send_file($cachedfilepath, $storedfile->get_filename(), 'default', $filter, false, $forcedownload); }
/** * 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!!! }
/** * 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); } }
/** * Synchronize the references. * * @param stored_file $file Stored file. * @return boolean */ public function sync_reference(stored_file $file) { if ($file->get_referencelastsync() + DAYSECS > time()) { // Synchronise not more often than once a day. return false; } $c = new curl(); $reference = unserialize(self::convert_to_valid_reference($file->get_reference())); $url = $reference->downloadurl; if (file_extension_in_typegroup($file->get_filename(), 'web_image')) { $path = $this->prepare_file(''); $result = $c->download_one($url, null, array('filepath' => $path, 'timeout' => $CFG->repositorysyncimagetimeout)); $info = $c->get_info(); if ($result === true && isset($info['http_code']) && $info['http_code'] == 200) { $fs = get_file_storage(); list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($path); $file->set_synchronized($contenthash, $filesize); return true; } } $c->get($url, null, array('timeout' => $CFG->repositorysyncimagetimeout, 'followlocation' => true, 'nobody' => true)); $info = $c->get_info(); if (isset($info['http_code']) && $info['http_code'] == 200 && array_key_exists('download_content_length', $info) && $info['download_content_length'] >= 0) { $filesize = (int) $info['download_content_length']; $file->set_synchronized(null, $filesize); return true; } $file->set_missingsource(); return true; }
/** * Updates all files that are referencing this file with the new contenthash * and filesize * * @param stored_file $storedfile */ public function update_references_to_storedfile(stored_file $storedfile) { global $CFG, $DB; $params = array(); $params['contextid'] = $storedfile->get_contextid(); $params['component'] = $storedfile->get_component(); $params['filearea'] = $storedfile->get_filearea(); $params['itemid'] = $storedfile->get_itemid(); $params['filename'] = $storedfile->get_filename(); $params['filepath'] = $storedfile->get_filepath(); $reference = self::pack_reference($params); $referencehash = sha1($reference); $sql = "SELECT repositoryid, id FROM {files_reference}\n WHERE referencehash = ? and reference = ?"; $rs = $DB->get_recordset_sql($sql, array($referencehash, $reference)); $now = time(); foreach ($rs as $record) { require_once $CFG->dirroot . '/repository/lib.php'; $repo = repository::get_instance($record->repositoryid); $lifetime = $repo->get_reference_file_lifetime($reference); $this->update_references($record->id, $now, $lifetime, $storedfile->get_contenthash(), $storedfile->get_filesize(), 0); } $rs->close(); }
/** * Returns the number of aliases that link to the given stored_file * * Aliases in user draft areas are not counted. * * @param stored_file $storedfile * @return int */ public function get_references_count_by_storedfile(stored_file $storedfile) { global $DB; $params = array(); $params['contextid'] = $storedfile->get_contextid(); $params['component'] = $storedfile->get_component(); $params['filearea'] = $storedfile->get_filearea(); $params['itemid'] = $storedfile->get_itemid(); $params['filename'] = $storedfile->get_filename(); $params['filepath'] = $storedfile->get_filepath(); return $this->search_references_count(self::pack_reference($params)); }
public static function create_from_archive(gallery $gallery, \stored_file $storedfile, $formdata = array()) { global $DB; $context = $gallery->get_collection()->context; $maxitems = $gallery->get_collection()->maxitems; $count = $DB->count_records('mediagallery_item', array('galleryid' => $gallery->id)); if ($maxitems != 0 && $count >= $maxitems) { return; } $fs = get_file_storage(); $packer = get_file_packer('application/zip'); $fs->delete_area_files($context->id, 'mod_mediagallery', 'unpacktemp', 0); $storedfile->extract_to_storage($packer, $context->id, 'mod_mediagallery', 'unpacktemp', 0, '/'); $itemfiles = $fs->get_area_files($context->id, 'mod_mediagallery', 'unpacktemp', 0); $storedfile->delete(); foreach ($itemfiles as $storedfile) { if ($storedfile->get_filesize() == 0 || preg_match('#^/.DS_Store|__MACOSX/#', $storedfile->get_filepath())) { continue; } if ($maxitems != 0 && $count >= $maxitems) { break; } $filename = $storedfile->get_filename(); // Create an item. $data = new \stdClass(); $data->caption = $filename; $data->description = ''; $data->display = 1; $metafields = array('moralrights' => 1, 'originalauthor' => '', 'productiondate' => 0, 'medium' => '', 'publisher' => '', 'broadcaster' => '', 'reference' => ''); foreach ($metafields as $field => $default) { $data->{$field} = isset($formdata->{$field}) ? $formdata->{$field} : $default; } $data->galleryid = $gallery->id; if (!$count) { $data->thumbnail = 1; $count = 0; } $item = self::create($data); // Copy the file into the correct area. $fileinfo = array('contextid' => $context->id, 'component' => 'mod_mediagallery', 'filearea' => 'item', 'itemid' => $item->id, 'filepath' => '/', 'filename' => $filename); if (!$fs->get_file($context->id, 'mod_mediagallery', 'item', $item->id, '/', $filename)) { $storedfile = $fs->create_file_from_storedfile($fileinfo, $storedfile); } $item->generate_image_by_type('lowres'); $item->generate_image_by_type('thumbnail'); $count++; } $fs->delete_area_files($context->id, 'mod_mediagallery', 'unpacktemp', 0); }
/** * Copies a file from somewhere else in moodle * to the portfolio temporary working directory * associated with this export * * @param stored_file $oldfile existing stored file object * @return stored_file|bool new file object */ public function copy_existing_file($oldfile) { if (array_key_exists($oldfile->get_contenthash(), $this->newfilehashes)) { return $this->newfilehashes[$oldfile->get_contenthash()]; } $fs = get_file_storage(); $file_record = $this->new_file_record_base($oldfile->get_filename()); if ($dir = $this->get('format')->get_file_directory()) { $file_record->filepath = '/' . $dir . '/'; } try { $newfile = $fs->create_file_from_storedfile($file_record, $oldfile->get_id()); $this->newfilehashes[$newfile->get_contenthash()] = $newfile; return $newfile; } catch (file_exception $e) { return false; } }
function emarking_create_anonymous_page_from_storedfile(stored_file $file, $student) { if (!$file) { throw new Exception('Stored file does not exist'); } // Get file storage and copy file to temp folder. $fs = get_file_storage(); $tmppath = $file->copy_content_to_temp('emarking', 'anonymous'); // Treat the file as an image, get its size and draw a white rectangle. $size = getimagesize($tmppath, $info); $imagemime = exif_imagetype($tmppath); if ($imagemime == IMAGETYPE_PNG) { $image = imagecreatefrompng($tmppath); } elseif ($imagemime == IMAGETYPE_JPEG) { $image = imagecreatefromjpeg($tmppath); } else { throw new Exception('Unsupported file type for pages'); } if (!$image) { throw new Exception('Could not read image from ' . $info[0] . ' ' . $tmppath); } $white = imagecolorallocate($image, 255, 255, 255); $y2 = round($size[1] / 10, 0); imagefilledrectangle($image, 0, 0, $size[0], $y2, $white); // Save the new image to replace the file. if ($imagemime == IMAGETYPE_PNG) { if (!imagepng($image, $tmppath)) { throw new Exception('Could not save image as PNG to ' . $tmppath); } } elseif ($imagemime == IMAGETYPE_JPEG) { if (!imagejpeg($image, $tmppath, 100)) { throw new Exception('Could not save image as JPEG to ' . $tmppath); } } else { throw new Exception('Unsupported file type for saving page'); } clearstatcache(); $filenameanonymous = emarking_get_anonymous_filename($file->get_filename()); // Copy file from temp folder to Moodle's filesystem. $filerecordanonymous = array('contextid' => $file->get_contextid(), 'component' => 'mod_emarking', 'filearea' => 'pages', 'itemid' => $file->get_itemid(), 'filepath' => '/', 'filename' => $filenameanonymous, 'timecreated' => $file->get_timecreated(), 'timemodified' => time(), 'userid' => $student->id, 'author' => $student->firstname . ' ' . $student->lastname, 'license' => 'allrightsreserved'); $previousfile = $fs->get_file($file->get_contextid(), 'mod_emarking', 'pages', $file->get_itemid(), '/', $filenameanonymous); if ($previousfile) { $previousfile->delete(); } $fileinfo = $fs->create_file_from_pathname($filerecordanonymous, $tmppath); if (!$fileinfo) { throw new Exception('Could not create anonymous version of a stored file'); } return $fileinfo; }
/** * Print resource info and workaround link when JS not available. * @param object $resource * @param object $cm * @param object $course * @param stored_file $file main file * @return does not return */ function resource_print_workaround($resource, $cm, $course, $file) { global $CFG, $OUTPUT; resource_print_header($resource, $cm, $course); resource_print_heading($resource, $cm, $course, true); resource_print_intro($resource, $cm, $course, true); $resource->mainfile = $file->get_filename(); echo '<div class="resourceworkaround">'; switch (resource_get_final_display_type($resource)) { case RESOURCELIB_DISPLAY_POPUP: $path = '/' . $file->get_contextid() . '/mod_resource/content/' . $resource->revision . $file->get_filepath() . $file->get_filename(); $fullurl = file_encode_url($CFG->wwwroot . '/pluginfile.php', $path, false); $options = empty($resource->displayoptions) ? array() : unserialize($resource->displayoptions); $width = empty($options['popupwidth']) ? 620 : $options['popupwidth']; $height = empty($options['popupheight']) ? 450 : $options['popupheight']; $wh = "width={$width},height={$height},toolbar=no,location=no,menubar=no,copyhistory=no,status=no,directories=no,scrollbars=yes,resizable=yes"; $extra = "onclick=\"window.open('{$fullurl}', '', '{$wh}'); return false;\""; echo resource_get_clicktoopen($file, $resource->revision, $extra); break; case RESOURCELIB_DISPLAY_NEW: $extra = 'onclick="this.target=\'_blank\'"'; echo resource_get_clicktoopen($file, $resource->revision, $extra); break; case RESOURCELIB_DISPLAY_DOWNLOAD: echo resource_get_clicktodownload($file, $resource->revision); break; case RESOURCELIB_DISPLAY_OPEN: default: echo resource_get_clicktoopen($file, $resource->revision); break; } echo '</div>'; echo $OUTPUT->footer(); die; }
/** * Return the link to a file * * @param stored_file $file information for existing file * @param array $options array of options to pass. can contain: * attributes => hash of existing html attributes (eg title, height, width, etc) * @return string */ public static function file_output($file, $options = null) { $id = ''; if (!is_array($options)) { $options = array(); } if (!array_key_exists('entry', $options)) { $options['entry'] = true; } if (!empty($options['entry'])) { $path = 'portfolio:' . self::file_id_prefix() . $file->get_id(); } else { $path = self::get_file_directory() . $file->get_filename(); } $attributes = array(); if (!empty($options['attributes']) && is_array($options['attributes'])) { $attributes = $options['attributes']; } $attributes['rel'] = 'enclosure'; return self::make_tag($file, $path, $attributes); }
/** * Updates all files that are referencing this file with the new contenthash * and filesize * * @param stored_file $storedfile */ public function update_references_to_storedfile(stored_file $storedfile) { global $CFG, $DB; $params = array(); $params['contextid'] = $storedfile->get_contextid(); $params['component'] = $storedfile->get_component(); $params['filearea'] = $storedfile->get_filearea(); $params['itemid'] = $storedfile->get_itemid(); $params['filename'] = $storedfile->get_filename(); $params['filepath'] = $storedfile->get_filepath(); $reference = self::pack_reference($params); $referencehash = sha1($reference); $sql = "SELECT repositoryid, id FROM {files_reference}\n WHERE referencehash = ?"; $rs = $DB->get_recordset_sql($sql, array($referencehash)); $now = time(); foreach ($rs as $record) { $this->update_references($record->id, $now, null, $storedfile->get_contenthash(), $storedfile->get_filesize(), 0, $storedfile->get_timemodified()); } $rs->close(); }
/** * Gets a file relative to this file in the repository and sends it to the browser. * * @param stored_file $mainfile The main file we are trying to access relative files for. * @param string $relativepath the relative path to the file we are trying to access. */ public function send_relative_file(stored_file $mainfile, $relativepath) { global $CFG; // Check if this repository is allowed to use relative linking. $allowlinks = $this->supports_relative_file(); if (!empty($allowlinks)) { // Get path to the mainfile. $mainfilepath = $mainfile->get_source(); // Strip out filename from the path. $filename = $mainfile->get_filename(); $basepath = strstr($mainfilepath, $filename, true); $fullrelativefilepath = realpath($this->get_rootpath() . $basepath . $relativepath); // Sanity check to make sure this path is inside this repository and the file exists. if (strpos($fullrelativefilepath, realpath($this->get_rootpath())) === 0 && file_exists($fullrelativefilepath)) { send_file($fullrelativefilepath, basename($relativepath), null, 0); } } send_file_not_found(); }
/** * Gets the file data * * @param stored_file $file * @param int $entryid Attachment entry id */ public function __construct($file, $entryid) { global $CFG; $this->file = $file; $this->filename = $file->get_filename(); $this->url = file_encode_url($CFG->wwwroot . '/pluginfile.php', '/' . SYSCONTEXTID . '/blog/attachment/' . $entryid . '/' . $this->filename); }
/** * Return the count files referring to provided stored_file instance * This won't work for draft files * * @param stored_file $storedfile * @return int */ public function get_references_count_by_storedfile($storedfile) { global $DB; $params = array(); $params['contextid'] = $storedfile->get_contextid(); $params['component'] = $storedfile->get_component(); $params['filearea'] = $storedfile->get_filearea(); $params['itemid'] = $storedfile->get_itemid(); $params['filename'] = $storedfile->get_filename(); $params['filepath'] = $storedfile->get_filepath(); $params['userid'] = $storedfile->get_userid(); $reference = self::pack_reference($params); $sql = "SELECT COUNT(f.id)\n FROM {files} f\n LEFT JOIN {files_reference} r\n ON f.referencefileid = r.id\n WHERE " . $DB->sql_compare_text('r.reference') . ' = ' . $DB->sql_compare_text('?') . "\n AND (f.component <> ? OR f.filearea <> ?)"; $count = $DB->count_records_sql($sql, array($reference, 'user', 'draft')); return $count; }
/** * Repository method to serve the referenced file * * @see send_stored_file * * @param stored_file $storedfile the file that contains the reference * @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime) * @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 array $options additional options affecting the file serving */ public function send_file($storedfile, $lifetime = null, $filter = 0, $forcedownload = false, array $options = null) { if ($this->has_moodle_files()) { $fs = get_file_storage(); $params = file_storage::unpack_reference($storedfile->get_reference(), true); $srcfile = null; if (is_array($params)) { $srcfile = $fs->get_file($params['contextid'], $params['component'], $params['filearea'], $params['itemid'], $params['filepath'], $params['filename']); } if (empty($options)) { $options = array(); } if (!isset($options['filename'])) { $options['filename'] = $storedfile->get_filename(); } if (!$srcfile) { send_file_not_found(); } else { send_stored_file($srcfile, $lifetime, $filter, $forcedownload, $options); } } else { throw new coding_exception("Repository plugin must implement send_file() method."); } }
/** * Shame that this was nicked from gdlib.php and that there isn't a function I could have used from there. * Creates a resized version of image and stores copy in file area * * @param context $context * @param string $component * @param string filearea * @param int $itemid * @param stored_file $originalfile * @param int $newwidth; * @param int $newheight; * @return stored_file */ public static function resize(\stored_file $originalfile, $resizefilename = false, $newwidth = false, $newheight = false, $jpgquality = 90) { if ($resizefilename === false) { $resizefilename = $originalfile->get_filename(); } if (!$newwidth && !$newheight) { return false; } $contextid = $originalfile->get_contextid(); $component = $originalfile->get_component(); $filearea = $originalfile->get_filearea(); $itemid = $originalfile->get_itemid(); $imageinfo = (object) $originalfile->get_imageinfo(); $imagefnc = ''; if (empty($imageinfo)) { return false; } // Create temporary image for processing. $tmpimage = tempnam(sys_get_temp_dir(), 'tmpimg'); \file_put_contents($tmpimage, $originalfile->get_content()); if (!$newheight) { $m = $imageinfo->height / $imageinfo->width; // Multiplier to work out $newheight. $newheight = $newwidth * $m; } else { if (!$newwidth) { $m = $imageinfo->width / $imageinfo->height; // Multiplier to work out $newwidth. $newwidth = $newheight * $m; } } $t = null; switch ($imageinfo->mimetype) { case 'image/gif': if (\function_exists('imagecreatefromgif')) { $im = \imagecreatefromgif($tmpimage); } else { \debugging('GIF not supported on this server'); unlink($tmpimage); return false; } // Guess transparent colour from GIF. $transparent = \imagecolortransparent($im); if ($transparent != -1) { $t = \imagecolorsforindex($im, $transparent); } break; case 'image/jpeg': if (\function_exists('imagecreatefromjpeg')) { $im = \imagecreatefromjpeg($tmpimage); } else { \debugging('JPEG not supported on this server'); unlink($tmpimage); return false; } // If the user uploads a jpeg them we should process as a jpeg if possible. if (\function_exists('imagejpeg')) { $imagefnc = 'imagejpeg'; $filters = null; // Not used. $quality = $jpgquality; } else { if (\function_exists('imagepng')) { $imagefnc = 'imagepng'; $filters = PNG_NO_FILTER; $quality = 1; } else { \debugging('Jpeg and png not supported on this server, please fix server configuration'); unlink($tmpimage); return false; } } break; case 'image/png': if (\function_exists('imagecreatefrompng')) { $im = \imagecreatefrompng($tmpimage); } else { \debugging('PNG not supported on this server'); unlink($tmpimage); return false; } break; default: unlink($tmpimage); return false; } unlink($tmpimage); // The default for all images other than jpegs is to try imagepng first. if (empty($imagefnc)) { if (\function_exists('imagepng')) { $imagefnc = 'imagepng'; $filters = PNG_NO_FILTER; $quality = 1; } else { if (\function_exists('imagejpeg')) { $imagefnc = 'imagejpeg'; $filters = null; // Not used. $quality = $jpgquality; } else { \debugging('Jpeg and png not supported on this server, please fix server configuration'); return false; } } } if (\function_exists('imagecreatetruecolor')) { $newimage = \imagecreatetruecolor($newwidth, $newheight); if ($imageinfo->mimetype != 'image/jpeg' and $imagefnc === 'imagepng') { if ($t) { // Transparent GIF hacking... $transparentcolour = \imagecolorallocate($newimage, $t['red'], $t['green'], $t['blue']); \imagecolortransparent($newimage, $transparentcolour); } \imagealphablending($newimage, false); $color = \imagecolorallocatealpha($newimage, 0, 0, 0, 127); \imagefill($newimage, 0, 0, $color); \imagesavealpha($newimage, true); } } else { $newimage = \imagecreate($newwidth, $newheight); } \imagecopybicubic($newimage, $im, 0, 0, 0, 0, $newwidth, $newheight, $imageinfo->width, $imageinfo->height); $fs = \get_file_storage(); $newimageparams = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid, 'filepath' => '/'); \ob_start(); if (!$imagefnc($newimage, null, $quality, $filters)) { return false; } $data = \ob_get_clean(); \imagedestroy($newimage); $newimageparams['filename'] = $resizefilename; if ($resizefilename == $originalfile->get_filename()) { $originalfile->delete(); } $file1 = $fs->create_file_from_string($newimageparams, $data); return $file1; }