/** * Validate incoming data. * * @param array $data * @param array $files * @return array */ public function validation($data, $files) { $errors = array(); $draftitemid = $data['files_filemanager']; if (file_is_draft_area_limit_reached($draftitemid, $this->_customdata['options']['areamaxbytes'])) { $errors['files_filemanager'] = get_string('userquotalimit', 'error'); } return $errors; }
function validation($data, $files) { $errors = []; $draftitemid = $data['files_filemanager']; if (file_is_draft_area_limit_reached($draftitemid, $this->_customdata['options']['areamaxbytes'])) { $errors['files_filemanager'] = get_string('userquotalimit', 'error'); } if (!trim($data['cliptitle'])) { $errors['cliptitle'] = get_string('video_title_mandatory', 'opencast'); } return $errors; }
/** * Do the actual processing of the uploaded file * @param string $saveas_filename name to give to the file * @param int $maxbytes maximum file size * @param mixed $types optional array of file extensions that are allowed or '*' for all * @param string $savepath optional path to save the file to * @param int $itemid optional the ID for this item within the file area * @param string $license optional the license to use for this file * @param string $author optional the name of the author of this file * @param bool $overwriteexisting optional user has asked to overwrite the existing file * @param int $areamaxbytes maximum size of the file area. * @return object containing details of the file uploaded */ public function process_upload($saveas_filename, $maxbytes, $types = '*', $savepath = '/', $itemid = 0, $license = null, $author = '', $overwriteexisting = false, $areamaxbytes = FILE_AREA_MAX_BYTES_UNLIMITED) { global $USER, $CFG; if (is_array($types) and in_array('*', $types) or $types == '*') { $this->mimetypes = '*'; } else { foreach ($types as $type) { $this->mimetypes[] = mimeinfo('type', $type); } } if ($license == null) { $license = $CFG->sitedefaultlicense; } $record = new stdClass(); $record->filearea = 'draft'; $record->component = 'user'; $record->filepath = $savepath; $record->itemid = $itemid; $record->license = $license; $record->author = $author; $context = context_user::instance($USER->id); $elname = 'repo_upload_file'; $fs = get_file_storage(); $sm = get_string_manager(); if ($record->filepath !== '/') { $record->filepath = file_correct_filepath($record->filepath); } if (!isset($_FILES[$elname])) { throw new moodle_exception('nofile'); } if (!empty($_FILES[$elname]['error'])) { switch ($_FILES[$elname]['error']) { case UPLOAD_ERR_INI_SIZE: throw new moodle_exception('upload_error_ini_size', 'repository_upload'); break; case UPLOAD_ERR_FORM_SIZE: throw new moodle_exception('upload_error_form_size', 'repository_upload'); break; case UPLOAD_ERR_PARTIAL: throw new moodle_exception('upload_error_partial', 'repository_upload'); break; case UPLOAD_ERR_NO_FILE: throw new moodle_exception('upload_error_no_file', 'repository_upload'); break; case UPLOAD_ERR_NO_TMP_DIR: throw new moodle_exception('upload_error_no_tmp_dir', 'repository_upload'); break; case UPLOAD_ERR_CANT_WRITE: throw new moodle_exception('upload_error_cant_write', 'repository_upload'); break; case UPLOAD_ERR_EXTENSION: throw new moodle_exception('upload_error_extension', 'repository_upload'); break; default: throw new moodle_exception('nofile'); } } \core\antivirus\manager::scan_file($_FILES[$elname]['tmp_name'], $_FILES[$elname]['name'], true); // {@link repository::build_source_field()} $sourcefield = $this->get_file_source_info($_FILES[$elname]['name']); $record->source = self::build_source_field($sourcefield); if (empty($saveas_filename)) { $record->filename = clean_param($_FILES[$elname]['name'], PARAM_FILE); } else { $ext = ''; $match = array(); $filename = clean_param($_FILES[$elname]['name'], PARAM_FILE); if (strpos($filename, '.') === false) { // File has no extension at all - do not add a dot. $record->filename = $saveas_filename; } else { if (preg_match('/\\.([a-z0-9]+)$/i', $filename, $match)) { if (isset($match[1])) { $ext = $match[1]; } } $ext = !empty($ext) ? $ext : ''; if (preg_match('#\\.(' . $ext . ')$#i', $saveas_filename)) { // saveas filename contains file extension already $record->filename = $saveas_filename; } else { $record->filename = $saveas_filename . '.' . $ext; } } } // Check the file has some non-null contents - usually an indication that a user has // tried to upload a folder by mistake if (!$this->check_valid_contents($_FILES[$elname]['tmp_name'])) { throw new moodle_exception('upload_error_invalid_file', 'repository_upload', '', $record->filename); } if ($this->mimetypes != '*') { // check filetype $filemimetype = file_storage::mimetype($_FILES[$elname]['tmp_name'], $record->filename); if (!in_array($filemimetype, $this->mimetypes)) { throw new moodle_exception('invalidfiletype', 'repository', '', get_mimetype_description(array('filename' => $_FILES[$elname]['name']))); } } if (empty($record->itemid)) { $record->itemid = 0; } if ($maxbytes !== -1 && filesize($_FILES[$elname]['tmp_name']) > $maxbytes) { $maxbytesdisplay = display_size($maxbytes); throw new file_exception('maxbytesfile', (object) array('file' => $record->filename, 'size' => $maxbytesdisplay)); } if (file_is_draft_area_limit_reached($record->itemid, $areamaxbytes, filesize($_FILES[$elname]['tmp_name']))) { throw new file_exception('maxareabytes'); } $record->contextid = $context->id; $record->userid = $USER->id; if (repository::draftfile_exists($record->itemid, $record->filepath, $record->filename)) { $existingfilename = $record->filename; $unused_filename = repository::get_unused_filename($record->itemid, $record->filepath, $record->filename); $record->filename = $unused_filename; $stored_file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']); if ($overwriteexisting) { repository::overwrite_existing_draftfile($record->itemid, $record->filepath, $existingfilename, $record->filepath, $record->filename); $record->filename = $existingfilename; } else { $event = array(); $event['event'] = 'fileexists'; $event['newfile'] = new stdClass(); $event['newfile']->filepath = $record->filepath; $event['newfile']->filename = $unused_filename; $event['newfile']->url = moodle_url::make_draftfile_url($record->itemid, $record->filepath, $unused_filename)->out(false); $event['existingfile'] = new stdClass(); $event['existingfile']->filepath = $record->filepath; $event['existingfile']->filename = $existingfilename; $event['existingfile']->url = moodle_url::make_draftfile_url($record->itemid, $record->filepath, $existingfilename)->out(false); return $event; } } else { $stored_file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']); } return array('url' => moodle_url::make_draftfile_url($record->itemid, $record->filepath, $record->filename)->out(false), 'id' => $record->itemid, 'file' => $record->filename); }
/** * This function is used to copy a moodle file to draft area. * * It DOES NOT check if the user is allowed to access this file because the actual file * can be located in the area where user does not have access to but there is an alias * to this file in the area where user CAN access it. * {@link file_is_accessible} should be called for alias location before calling this function. * * @param string $source The metainfo of file, it is base64 encoded php serialized data * @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other * attributes of the new file * @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds * the limit, the file_exception is thrown. * @param int $areamaxbytes the maximum size of the area. A file_exception is thrown if the * new file will reach the limit. * @return array The information about the created file */ public function copy_to_area($source, $filerecord, $maxbytes = -1, $areamaxbytes = FILE_AREA_MAX_BYTES_UNLIMITED) { global $USER; $fs = get_file_storage(); if ($this->has_moodle_files() == false) { throw new coding_exception('Only repository used to browse moodle files can use repository::copy_to_area()'); } $user_context = context_user::instance($USER->id); $filerecord = (array) $filerecord; // make sure the new file will be created in user draft area $filerecord['component'] = 'user'; $filerecord['filearea'] = 'draft'; $filerecord['contextid'] = $user_context->id; $draftitemid = $filerecord['itemid']; $new_filepath = $filerecord['filepath']; $new_filename = $filerecord['filename']; // the file needs to copied to draft area $stored_file = self::get_moodle_file($source); if ($maxbytes != -1 && $stored_file->get_filesize() > $maxbytes) { throw new file_exception('maxbytes'); } // Validate the size of the draft area. if (file_is_draft_area_limit_reached($draftitemid, $areamaxbytes, $stored_file->get_filesize())) { throw new file_exception('maxareabytes'); } if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) { // create new file $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename); $filerecord['filename'] = $unused_filename; $fs->create_file_from_storedfile($filerecord, $stored_file); $event = array(); $event['event'] = 'fileexists'; $event['newfile'] = new stdClass(); $event['newfile']->filepath = $new_filepath; $event['newfile']->filename = $unused_filename; $event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $unused_filename)->out(); $event['existingfile'] = new stdClass(); $event['existingfile']->filepath = $new_filepath; $event['existingfile']->filename = $new_filename; $event['existingfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out(); return $event; } else { $fs->create_file_from_storedfile($filerecord, $stored_file); $info = array(); $info['itemid'] = $draftitemid; $info['file'] = $new_filename; $info['title'] = $new_filename; $info['contextid'] = $user_context->id; $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out(); $info['filesize'] = $stored_file->get_filesize(); return $info; } }
/** * Saves files from a draft file area to a real one (merging the list of files). * Can rewrite URLs in some content at the same time if desired. * * @category files * @global stdClass $USER * @param int $draftitemid the id of the draft area to use. Normally obtained * from file_get_submitted_draft_itemid('elementname') or similar. * @param int $contextid This parameter and the next two identify the file area to save to. * @param string $component * @param string $filearea indentifies the file area. * @param int $itemid helps identifies the file area. * @param array $options area options (subdirs=>false, maxfiles=-1, maxbytes=0) * @param string $text some html content that needs to have embedded links rewritten * to the @@PLUGINFILE@@ form for saving in the database. * @param bool $forcehttps force https urls. * @return string|null if $text was passed in, the rewritten $text is returned. Otherwise NULL. */ function file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options = null, $text = null, $forcehttps = false) { global $USER; $usercontext = context_user::instance($USER->id); $fs = get_file_storage(); $options = (array) $options; if (!isset($options['subdirs'])) { $options['subdirs'] = false; } if (!isset($options['maxfiles'])) { $options['maxfiles'] = -1; // unlimited } if (!isset($options['maxbytes']) || $options['maxbytes'] == USER_CAN_IGNORE_FILE_SIZE_LIMITS) { $options['maxbytes'] = 0; // unlimited } if (!isset($options['areamaxbytes'])) { $options['areamaxbytes'] = FILE_AREA_MAX_BYTES_UNLIMITED; // Unlimited. } $allowreferences = true; if (isset($options['return_types']) && !($options['return_types'] & FILE_REFERENCE)) { // we assume that if $options['return_types'] is NOT specified, we DO allow references. // this is not exactly right. BUT there are many places in code where filemanager options // are not passed to file_save_draft_area_files() $allowreferences = false; } // Check if the draft area has exceeded the authorised limit. This should never happen as validation // should have taken place before, unless the user is doing something nauthly. If so, let's just not save // anything at all in the next area. if (file_is_draft_area_limit_reached($draftitemid, $options['areamaxbytes'])) { return null; } $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id'); $oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id'); // One file in filearea means it is empty (it has only top-level directory '.'). if (count($draftfiles) > 1 || count($oldfiles) > 1) { // we have to merge old and new files - we want to keep file ids for files that were not changed // we change time modified for all new and changed files, we keep time created as is $newhashes = array(); $filecount = 0; foreach ($draftfiles as $file) { if (!$options['subdirs'] && $file->get_filepath() !== '/') { continue; } if (!$allowreferences && $file->is_external_file()) { continue; } if (!$file->is_directory()) { if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) { // oversized file - should not get here at all continue; } if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) { // more files - should not get here at all continue; } $filecount++; } $newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename()); $newhashes[$newhash] = $file; } // Loop through oldfiles and decide which we need to delete and which to update. // After this cycle the array $newhashes will only contain the files that need to be added. foreach ($oldfiles as $oldfile) { $oldhash = $oldfile->get_pathnamehash(); if (!isset($newhashes[$oldhash])) { // delete files not needed any more - deleted by user $oldfile->delete(); continue; } $newfile = $newhashes[$oldhash]; // Now we know that we have $oldfile and $newfile for the same path. // Let's check if we can update this file or we need to delete and create. if ($newfile->is_directory()) { // Directories are always ok to just update. } else { if (($source = @unserialize($newfile->get_source())) && isset($source->original)) { // File has the 'original' - we need to update the file (it may even have not been changed at all). $original = file_storage::unpack_reference($source->original); if ($original['filename'] !== $oldfile->get_filename() || $original['filepath'] !== $oldfile->get_filepath()) { // Very odd, original points to another file. Delete and create file. $oldfile->delete(); continue; } } else { // The same file name but absence of 'original' means that file was deteled and uploaded again. // By deleting and creating new file we properly manage all existing references. $oldfile->delete(); continue; } } // status changed, we delete old file, and create a new one if ($oldfile->get_status() != $newfile->get_status()) { // file was changed, use updated with new timemodified data $oldfile->delete(); // This file will be added later continue; } // Updated author if ($oldfile->get_author() != $newfile->get_author()) { $oldfile->set_author($newfile->get_author()); } // Updated license if ($oldfile->get_license() != $newfile->get_license()) { $oldfile->set_license($newfile->get_license()); } // Updated file source // Field files.source for draftarea files contains serialised object with source and original information. // We only store the source part of it for non-draft file area. $newsource = $newfile->get_source(); if ($source = @unserialize($newfile->get_source())) { $newsource = $source->source; } if ($oldfile->get_source() !== $newsource) { $oldfile->set_source($newsource); } // Updated sort order if ($oldfile->get_sortorder() != $newfile->get_sortorder()) { $oldfile->set_sortorder($newfile->get_sortorder()); } // Update file timemodified if ($oldfile->get_timemodified() != $newfile->get_timemodified()) { $oldfile->set_timemodified($newfile->get_timemodified()); } // Replaced file content if (!$oldfile->is_directory() && ($oldfile->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize() || $oldfile->get_referencefileid() != $newfile->get_referencefileid() || $oldfile->get_userid() != $newfile->get_userid())) { $oldfile->replace_file_with($newfile); } // unchanged file or directory - we keep it as is unset($newhashes[$oldhash]); } // Add fresh file or the file which has changed status // the size and subdirectory tests are extra safety only, the UI should prevent it foreach ($newhashes as $file) { $file_record = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid, 'timemodified' => time()); if ($source = @unserialize($file->get_source())) { // Field files.source for draftarea files contains serialised object with source and original information. // We only store the source part of it for non-draft file area. $file_record['source'] = $source->source; } if ($file->is_external_file()) { $repoid = $file->get_repository_id(); if (!empty($repoid)) { $file_record['repositoryid'] = $repoid; $file_record['reference'] = $file->get_reference(); } } $fs->create_file_from_storedfile($file_record, $file); } } // note: do not purge the draft area - we clean up areas later in cron, // the reason is that user might press submit twice and they would loose the files, // also sometimes we might want to use hacks that save files into two different areas if (is_null($text)) { return null; } else { return file_rewrite_urls_to_pluginfile($text, $draftitemid, $forcehttps); } }
$fileinfo = $repo->copy_to_area($reference, $record, $maxbytes, $areamaxbytes); echo json_encode($fileinfo); die; } else { // Download file to moodle. $downloadedfile = $repo->get_file($reference, $saveas_filename); if (empty($downloadedfile['path'])) { $err->error = get_string('cannotdownload', 'repository'); die(json_encode($err)); } // Check if exceed maxbytes. if ($maxbytes != -1 && filesize($downloadedfile['path']) > $maxbytes) { throw new file_exception('maxbytes'); } // Check if we exceed the max bytes of the area. if (file_is_draft_area_limit_reached($itemid, $areamaxbytes, filesize($downloadedfile['path']))) { throw new file_exception('maxareabytes'); } $info = repository::move_to_filepool($downloadedfile['path'], $record); if (empty($info)) { $info['e'] = get_string('error', 'moodle'); } } } echo json_encode($info); die; } break; case 'upload': $result = $repo->upload($saveas_filename, $maxbytes); echo json_encode($result);
/** * Process a message received and validated by the Inbound Message processor. * * @throws \core\message\inbound\processing_failed_exception * @param \stdClass $record The Inbound Message record * @param \stdClass $data The message data packet * @return bool Whether the message was successfully processed. */ public function process_message(\stdClass $record, \stdClass $data) { global $USER, $CFG; $context = \context_user::instance($USER->id); if (!has_capability('moodle/user:manageownfiles', $context)) { throw new \core\message\inbound\processing_failed_exception('emailtoprivatefilesdenied', 'moodle', $data); } // Initial setup. $component = 'user'; $filearea = 'private'; $itemid = 0; $license = $CFG->sitedefaultlicense; $author = fullname($USER); // Determine the quota space for this user. $maxbytes = $CFG->userquota; if (has_capability('moodle/user:ignoreuserquota', $context)) { $maxbytes = USER_CAN_IGNORE_FILE_SIZE_LIMITS; } // Keep track of files which were uploaded, and which were skipped. $skippedfiles = array(); $uploadedfiles = array(); $failedfiles = array(); $fs = get_file_storage(); foreach ($data->attachments as $attachmenttype => $attachments) { foreach ($attachments as $attachment) { mtrace("--- Processing attachment '{$attachment->filename}'"); if (file_is_draft_area_limit_reached($itemid, $maxbytes, $attachment->filesize)) { // The user quota will be exceeded if this file is included. $skippedfiles[] = $attachment; mtrace("---- Skipping attacment. User will be over quota."); continue; } // Create a new record for this file. $record = new \stdClass(); $record->filearea = $filearea; $record->component = $component; $record->filepath = '/'; $record->itemid = $itemid; $record->license = $license; $record->author = $author; $record->contextid = $context->id; $record->userid = $USER->id; $record->filename = $fs->get_unused_filename($context->id, $record->component, $record->filearea, $record->itemid, $record->filepath, $attachment->filename); mtrace("--> Attaching {$record->filename} to " . "/{$record->contextid}/{$record->component}/{$record->filearea}/" . "{$record->itemid}{$record->filepath}{$record->filename}"); if ($fs->create_file_from_string($record, $attachment->content)) { // File created successfully. mtrace("---- File uploaded successfully as {$record->filename}."); $uploadedfiles[] = $attachment; } else { mtrace("---- Skipping attacment. Unknown failure during creation."); $failedfiles[] = $attachment; } } } // TODO send the user a confirmation e-mail. // Note, some files may have failed because the user has been pushed over quota. This does not constitute a failure. return true; }
$record->userid = $USER->id; $record->contextid = $user_context->id; $record->sortorder = 0; if ($repo->has_moodle_files()) { $fileinfo = $repo->copy_to_area($reference, $record, $maxbytes, $areamaxbytes); redirect($home_url, get_string('downloadsucc', 'repository')); } else { $thefile = $repo->get_file($reference, $filename); if (!empty($thefile['path'])) { $filesize = filesize($thefile['path']); if ($maxbytes != -1 && $filesize > $maxbytes) { unlink($thefile['path']); print_error('maxbytes'); } // Ensure the file will not make the area exceed its size limit. if (file_is_draft_area_limit_reached($record->itemid, $areamaxbytes, $filesize)) { unlink($thefile['path']); print_error('maxareabytes'); } try { $info = repository::move_to_filepool($thefile['path'], $record); redirect($home_url, get_string('downloadsucc', 'repository')); } catch (moodle_exception $e) { // inject target URL $e->link = $PAGE->url->out(); echo $OUTPUT->header(); // hack: we need the embedded header here, standard error printing would not use it throw $e; } } else { print_error('cannotdownload', 'repository');
/** * Saves files from a draft file area to a real one (merging the list of files). * Can rewrite URLs in some content at the same time if desired. * * @category files * @global stdClass $USER * @param int $draftitemid the id of the draft area to use. Normally obtained * from file_get_submitted_draft_itemid('elementname') or similar. * @param int $contextid This parameter and the next two identify the file area to save to. * @param string $component * @param string $filearea indentifies the file area. * @param int $itemid helps identifies the file area. * @param array $options area options (subdirs=>false, maxfiles=-1, maxbytes=0) * @param string $text some html content that needs to have embedded links rewritten * to the @@PLUGINFILE@@ form for saving in the database. * @param bool $forcehttps force https urls. * @return string|null if $text was passed in, the rewritten $text is returned. Otherwise NULL. */ function file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options = null, $text = null, $forcehttps = false) { global $USER; $usercontext = context_user::instance($USER->id); $fs = get_file_storage(); $options = (array) $options; if (!isset($options['subdirs'])) { $options['subdirs'] = false; } if (!isset($options['maxfiles'])) { $options['maxfiles'] = -1; // unlimited } if (!isset($options['maxbytes']) || $options['maxbytes'] == USER_CAN_IGNORE_FILE_SIZE_LIMITS) { $options['maxbytes'] = 0; // unlimited } if (!isset($options['areamaxbytes'])) { $options['areamaxbytes'] = FILE_AREA_MAX_BYTES_UNLIMITED; // Unlimited. } $allowreferences = true; if (isset($options['return_types']) && !($options['return_types'] & FILE_REFERENCE)) { // we assume that if $options['return_types'] is NOT specified, we DO allow references. // this is not exactly right. BUT there are many places in code where filemanager options // are not passed to file_save_draft_area_files() $allowreferences = false; } // Check if the draft area has exceeded the authorised limit. This should never happen as validation // should have taken place before, unless the user is doing something nauthly. If so, let's just not save // anything at all in the next area. if (file_is_draft_area_limit_reached($draftitemid, $options['areamaxbytes'])) { return null; } $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id'); $oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id'); if (count($draftfiles) < 2) { // means there are no files - one file means root dir only ;-) $fs->delete_area_files($contextid, $component, $filearea, $itemid); } else { if (count($oldfiles) < 2) { $filecount = 0; // there were no files before - one file means root dir only ;-) foreach ($draftfiles as $file) { $file_record = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid); if (!$options['subdirs']) { if ($file->get_filepath() !== '/' or $file->is_directory()) { continue; } } if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) { // oversized file - should not get here at all continue; } if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) { // more files - should not get here at all break; } if (!$file->is_directory()) { $filecount++; } if ($file->is_external_file()) { if (!$allowreferences) { continue; } $repoid = $file->get_repository_id(); if (!empty($repoid)) { $file_record['repositoryid'] = $repoid; $file_record['reference'] = $file->get_reference(); } } file_restore_source_field_from_draft_file($file); $fs->create_file_from_storedfile($file_record, $file); } } else { // we have to merge old and new files - we want to keep file ids for files that were not changed // we change time modified for all new and changed files, we keep time created as is $newhashes = array(); foreach ($draftfiles as $file) { $newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename()); file_restore_source_field_from_draft_file($file); $newhashes[$newhash] = $file; } $filecount = 0; foreach ($oldfiles as $oldfile) { $oldhash = $oldfile->get_pathnamehash(); if (!isset($newhashes[$oldhash])) { // delete files not needed any more - deleted by user $oldfile->delete(); continue; } $newfile = $newhashes[$oldhash]; // status changed, we delete old file, and create a new one if ($oldfile->get_status() != $newfile->get_status()) { // file was changed, use updated with new timemodified data $oldfile->delete(); // This file will be added later continue; } // Updated author if ($oldfile->get_author() != $newfile->get_author()) { $oldfile->set_author($newfile->get_author()); } // Updated license if ($oldfile->get_license() != $newfile->get_license()) { $oldfile->set_license($newfile->get_license()); } // Updated file source if ($oldfile->get_source() != $newfile->get_source()) { $oldfile->set_source($newfile->get_source()); } // Updated sort order if ($oldfile->get_sortorder() != $newfile->get_sortorder()) { $oldfile->set_sortorder($newfile->get_sortorder()); } // Update file timemodified if ($oldfile->get_timemodified() != $newfile->get_timemodified()) { $oldfile->set_timemodified($newfile->get_timemodified()); } // Replaced file content if ($oldfile->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize()) { $oldfile->replace_content_with($newfile); // push changes to all local files that are referencing this file $fs->update_references_to_storedfile($oldfile); } // unchanged file or directory - we keep it as is unset($newhashes[$oldhash]); if (!$oldfile->is_directory()) { $filecount++; } } // Add fresh file or the file which has changed status // the size and subdirectory tests are extra safety only, the UI should prevent it foreach ($newhashes as $file) { $file_record = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid, 'timemodified' => time()); if (!$options['subdirs']) { if ($file->get_filepath() !== '/' or $file->is_directory()) { continue; } } if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) { // oversized file - should not get here at all continue; } if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) { // more files - should not get here at all break; } if (!$file->is_directory()) { $filecount++; } if ($file->is_external_file()) { if (!$allowreferences) { continue; } $repoid = $file->get_repository_id(); if (!empty($repoid)) { $file_record['repositoryid'] = $repoid; $file_record['reference'] = $file->get_reference(); } } $fs->create_file_from_storedfile($file_record, $file); } } } // note: do not purge the draft area - we clean up areas later in cron, // the reason is that user might press submit twice and they would loose the files, // also sometimes we might want to use hacks that save files into two different areas if (is_null($text)) { return null; } else { return file_rewrite_urls_to_pluginfile($text, $draftitemid, $forcehttps); } }