public function set_value($value)
 {
     global $CFG;
     $localhostwwwroot = backup_plan_dbops::get_mnet_localhost_wwwroot();
     // If user wwwroot matches mnet local host one or if
     // there isn't associated wwwroot, skip sending it to file
     if ($localhostwwwroot == $value || empty($value)) {
         // Do nothing
     } else {
         parent::set_value($value);
     }
 }
 /**
  * Launches a automated backup routine for the given course
  *
  * @param stdClass $course
  * @param int $starttime
  * @param int $userid
  * @return bool
  */
 public static function launch_automated_backup($course, $starttime, $userid)
 {
     $outcome = self::BACKUP_STATUS_OK;
     $config = get_config('backup');
     $dir = $config->backup_auto_destination;
     $storage = (int) $config->backup_auto_storage;
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
     try {
         // Set the default filename.
         $format = $bc->get_format();
         $type = $bc->get_type();
         $id = $bc->get_id();
         $users = $bc->get_plan()->get_setting('users')->get_value();
         $anonymised = $bc->get_plan()->get_setting('anonymize')->get_value();
         $bc->get_plan()->get_setting('filename')->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
         $bc->set_status(backup::STATUS_AWAITING);
         $bc->execute_plan();
         $results = $bc->get_results();
         $outcome = self::outcome_from_results($results);
         $file = $results['backup_destination'];
         // May be empty if file already moved to target location.
         if (empty($dir) && $storage !== 0) {
             // This is intentionally left as a warning instead of an error because of the current behaviour of backup settings.
             // See MDL-48266 for details.
             $bc->log('No directory specified for automated backups', backup::LOG_WARNING);
             $outcome = self::BACKUP_STATUS_WARNING;
         } else {
             if ($storage !== 0 && (!file_exists($dir) || !is_dir($dir) || !is_writable($dir))) {
                 // If we need to copy the backup file to an external dir and it is not writable, change status to error.
                 $bc->log('Specified backup directory is not writable - ', backup::LOG_ERROR, $dir);
                 $dir = null;
                 $outcome = self::BACKUP_STATUS_ERROR;
             }
         }
         // Copy file only if there was no error.
         if ($file && !empty($dir) && $storage !== 0 && $outcome != self::BACKUP_STATUS_ERROR) {
             $filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, !$config->backup_shortname);
             if (!$file->copy_content_to($dir . '/' . $filename)) {
                 $bc->log('Attempt to copy backup file to the specified directory failed - ', backup::LOG_ERROR, $dir);
                 $outcome = self::BACKUP_STATUS_ERROR;
             }
             if ($outcome != self::BACKUP_STATUS_ERROR && $storage === 1) {
                 if (!$file->delete()) {
                     $outcome = self::BACKUP_STATUS_WARNING;
                     $bc->log('Attempt to delete the backup file from course automated backup area failed - ', backup::LOG_WARNING, $file->get_filename());
                 }
             }
         }
     } catch (moodle_exception $e) {
         $bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname);
         // Log error header.
         $bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1);
         // Log original exception problem.
         $bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1);
         // Log original debug information.
         $outcome = self::BACKUP_STATUS_ERROR;
     }
     // Delete the backup file immediately if something went wrong.
     if ($outcome === self::BACKUP_STATUS_ERROR) {
         // Delete the file from file area if exists.
         if (!empty($file)) {
             $file->delete();
         }
         // Delete file from external storage if exists.
         if ($storage !== 0 && !empty($filename) && file_exists($dir . '/' . $filename)) {
             @unlink($dir . '/' . $filename);
         }
     }
     $bc->destroy();
     unset($bc);
     return $outcome;
 }
Пример #3
0
 /**
  * We need to decide conditionally, based on dynamic information
  * about the execution of this step. Only will be executed if all
  * the module gradeitems have been already included in backup
  */
 protected function execute_condition()
 {
     return backup_plan_dbops::require_gradebook_backup($this->get_courseid(), $this->get_backupid());
 }
Пример #4
0
 /**
  * Given one backupid and the (FS) final generated file, perform its final storage
  * into Moodle file storage. For stored files it returns the complete file_info object
  *
  * Note: the $filepath is deleted if the backup file is created successfully
  *
  * If you specify the progress monitor, this will start a new progress section
  * to track progress in processing (in case this task takes a long time).
  *
  * @param int $backupid
  * @param string $filepath zip file containing the backup
  * @param \core\progress\base $progress Optional progress monitor
  * @return stored_file if created, null otherwise
  *
  * @throws moodle_exception in case of any problems
  */
 public static function store_backup_file($backupid, $filepath, \core\progress\base $progress = null)
 {
     global $CFG;
     // First of all, get some information from the backup_controller to help us decide
     list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($backupid, $progress);
     // Extract useful information to decide
     $hasusers = (bool) $sinfo['users']->value;
     // Backup has users
     $isannon = (bool) $sinfo['anonymize']->value;
     // Backup is anonymised
     $filename = $sinfo['filename']->value;
     // Backup filename
     $backupmode = $dinfo[0]->mode;
     // Backup mode backup::MODE_GENERAL/IMPORT/HUB
     $backuptype = $dinfo[0]->type;
     // Backup type backup::TYPE_1ACTIVITY/SECTION/COURSE
     $userid = $dinfo[0]->userid;
     // User->id executing the backup
     $id = $dinfo[0]->id;
     // Id of activity/section/course (depends of type)
     $courseid = $dinfo[0]->courseid;
     // Id of the course
     $format = $dinfo[0]->format;
     // Type of backup file
     // Quick hack. If for any reason, filename is blank, fix it here.
     // TODO: This hack will be out once MDL-22142 - P26 gets fixed
     if (empty($filename)) {
         $filename = backup_plan_dbops::get_default_backup_filename('moodle2', $backuptype, $id, $hasusers, $isannon);
     }
     // Backups of type IMPORT aren't stored ever
     if ($backupmode == backup::MODE_IMPORT) {
         return null;
     }
     if (!is_readable($filepath)) {
         // we have a problem if zip file does not exist
         throw new coding_exception('backup_helper::store_backup_file() expects valid $filepath parameter');
     }
     // Calculate file storage options of id being backup
     $ctxid = 0;
     $filearea = '';
     $component = '';
     $itemid = 0;
     switch ($backuptype) {
         case backup::TYPE_1ACTIVITY:
             $ctxid = context_module::instance($id)->id;
             $component = 'backup';
             $filearea = 'activity';
             $itemid = 0;
             break;
         case backup::TYPE_1SECTION:
             $ctxid = context_course::instance($courseid)->id;
             $component = 'backup';
             $filearea = 'section';
             $itemid = $id;
             break;
         case backup::TYPE_1COURSE:
             $ctxid = context_course::instance($courseid)->id;
             $component = 'backup';
             $filearea = 'course';
             $itemid = 0;
             break;
     }
     if ($backupmode == backup::MODE_AUTOMATED) {
         // Automated backups have there own special area!
         $filearea = 'automated';
         // If we're keeping the backup only in a chosen path, just move it there now
         // this saves copying from filepool to here later and filling trashdir.
         $config = get_config('backup');
         $dir = $config->backup_auto_destination;
         if ($config->backup_auto_storage == 1 and $dir and is_dir($dir) and is_writable($dir)) {
             $filedest = $dir . '/' . backup_plan_dbops::get_default_backup_filename($format, $backuptype, $courseid, $hasusers, $isannon, !$config->backup_shortname);
             // first try to move the file, if it is not possible copy and delete instead
             if (@rename($filepath, $filedest)) {
                 return null;
             }
             umask($CFG->umaskpermissions);
             if (copy($filepath, $filedest)) {
                 @chmod($filedest, $CFG->filepermissions);
                 // may fail because the permissions may not make sense outside of dataroot
                 unlink($filepath);
                 return null;
             } else {
                 $bc = backup_controller::load_controller($backupid);
                 $bc->log('Attempt to copy backup file to the specified directory using filesystem failed - ', backup::LOG_WARNING, $dir);
                 $bc->destroy();
             }
             // bad luck, try to deal with the file the old way - keep backup in file area if we can not copy to ext system
         }
     }
     // Backups of type HUB (by definition never have user info)
     // are sent to user's "user_tohub" file area. The upload process
     // will be responsible for cleaning that filearea once finished
     if ($backupmode == backup::MODE_HUB) {
         $ctxid = context_user::instance($userid)->id;
         $component = 'user';
         $filearea = 'tohub';
         $itemid = 0;
     }
     // Backups without user info or with the anonymise functionality
     // enabled are sent to user's "user_backup"
     // file area. Maintenance of such area is responsibility of
     // the user via corresponding file manager frontend
     if ($backupmode == backup::MODE_GENERAL && (!$hasusers || $isannon)) {
         $ctxid = context_user::instance($userid)->id;
         $component = 'user';
         $filearea = 'backup';
         $itemid = 0;
     }
     // Let's send the file to file storage, everything already defined
     $fs = get_file_storage();
     $fr = array('contextid' => $ctxid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid, 'filepath' => '/', 'filename' => $filename, 'userid' => $userid, 'timecreated' => time(), 'timemodified' => time());
     // If file already exists, delete if before
     // creating it again. This is BC behaviour - copy()
     // overwrites by default
     if ($fs->file_exists($fr['contextid'], $fr['component'], $fr['filearea'], $fr['itemid'], $fr['filepath'], $fr['filename'])) {
         $pathnamehash = $fs->get_pathname_hash($fr['contextid'], $fr['component'], $fr['filearea'], $fr['itemid'], $fr['filepath'], $fr['filename']);
         $sf = $fs->get_file_by_hash($pathnamehash);
         $sf->delete();
     }
     $file = $fs->create_file_from_pathname($fr, $filepath);
     unlink($filepath);
     return $file;
 }
Пример #5
0
 /**
  * Launches a automated backup routine for the given course
  *
  * @param stdClass $course
  * @param int $starttime
  * @param int $userid
  * @return bool
  */
 public static function launch_automated_backup($course, $starttime, $userid)
 {
     $config = get_config('backup');
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
     try {
         $settings = array('users' => 'backup_auto_users', 'role_assignments' => 'backup_auto_role_assignments', 'activities' => 'backup_auto_activities', 'blocks' => 'backup_auto_blocks', 'filters' => 'backup_auto_filters', 'comments' => 'backup_auto_comments', 'completion_information' => 'backup_auto_userscompletion', 'logs' => 'backup_auto_logs', 'histories' => 'backup_auto_histories');
         foreach ($settings as $setting => $configsetting) {
             if ($bc->get_plan()->setting_exists($setting)) {
                 $bc->get_plan()->get_setting($setting)->set_value($config->{$configsetting});
             }
         }
         // Set the default filename
         $format = $bc->get_format();
         $type = $bc->get_type();
         $id = $bc->get_id();
         $users = $bc->get_plan()->get_setting('users')->get_value();
         $anonymised = $bc->get_plan()->get_setting('anonymize')->get_value();
         $bc->get_plan()->get_setting('filename')->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
         $bc->set_status(backup::STATUS_AWAITING);
         $outcome = $bc->execute_plan();
         $results = $bc->get_results();
         $file = $results['backup_destination'];
         $dir = $config->backup_auto_destination;
         $storage = (int) $config->backup_auto_storage;
         if (!file_exists($dir) || !is_dir($dir) || !is_writable($dir)) {
             $dir = null;
         }
         if (!empty($dir) && $storage !== 0) {
             $filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, true);
             $outcome = $file->copy_content_to($dir . '/' . $filename);
             if ($outcome && $storage === 1) {
                 $file->delete();
             }
         }
         $outcome = true;
     } catch (backup_exception $e) {
         $bc->log('backup_auto_failed_on_course', backup::LOG_WARNING, $course->shortname);
         $outcome = false;
     }
     $bc->destroy();
     unset($bc);
     return true;
 }
 /**
  * @param string $plugintype Plugin type (always 'theme')
  * @param string $pluginname Plugin name (name of theme)
  * @param backup_optigroup $optigroup Group that will contain this data
  * @param backup_course_structure_step $step Backup step that this is part of
  */
 public function __construct($plugintype, $pluginname, $optigroup, $step)
 {
     parent::__construct($plugintype, $pluginname, $optigroup, $step);
     $this->coursetheme = backup_plan_dbops::get_theme_from_courseid($this->task->get_courseid());
 }
Пример #7
0
 /**
  * Limit the execution.
  *
  * This applies the same logic than the one applied to {@link backup_gradebook_structure_step},
  * because we do not want to save the history of items which are not backed up. At least for now.
  */
 protected function execute_condition()
 {
     $courseid = $this->get_courseid();
     if ($courseid == SITEID) {
         return false;
     }
     return backup_plan_dbops::require_gradebook_backup($courseid, $this->get_backupid());
 }
 /**
  * Launches a automated backup routine for the given course
  *
  * @param stdClass $course
  * @param int $starttime
  * @param int $userid
  * @return bool
  */
 public static function launch_automated_backup($course, $starttime, $userid)
 {
     $outcome = self::BACKUP_STATUS_OK;
     $config = get_config('backup');
     $dir = $config->backup_auto_destination;
     $storage = (int) $config->backup_auto_storage;
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
     try {
         $settings = array('users' => 'backup_auto_users', 'role_assignments' => 'backup_auto_role_assignments', 'activities' => 'backup_auto_activities', 'blocks' => 'backup_auto_blocks', 'filters' => 'backup_auto_filters', 'comments' => 'backup_auto_comments', 'badges' => 'backup_auto_badges', 'completion_information' => 'backup_auto_userscompletion', 'logs' => 'backup_auto_logs', 'histories' => 'backup_auto_histories', 'questionbank' => 'backup_auto_questionbank');
         foreach ($settings as $setting => $configsetting) {
             if ($bc->get_plan()->setting_exists($setting)) {
                 if (isset($config->{$configsetting})) {
                     $bc->get_plan()->get_setting($setting)->set_value($config->{$configsetting});
                 }
             }
         }
         // Set the default filename.
         $format = $bc->get_format();
         $type = $bc->get_type();
         $id = $bc->get_id();
         $users = $bc->get_plan()->get_setting('users')->get_value();
         $anonymised = $bc->get_plan()->get_setting('anonymize')->get_value();
         $bc->get_plan()->get_setting('filename')->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
         $bc->set_status(backup::STATUS_AWAITING);
         $bc->execute_plan();
         $results = $bc->get_results();
         $outcome = self::outcome_from_results($results);
         $file = $results['backup_destination'];
         // May be empty if file already moved to target location.
         if (!file_exists($dir) || !is_dir($dir) || !is_writable($dir)) {
             $dir = null;
         }
         // Copy file only if there was no error.
         if ($file && !empty($dir) && $storage !== 0 && $outcome != self::BACKUP_STATUS_ERROR) {
             $filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, !$config->backup_shortname);
             if (!$file->copy_content_to($dir . '/' . $filename)) {
                 $outcome = self::BACKUP_STATUS_ERROR;
             }
             if ($outcome != self::BACKUP_STATUS_ERROR && $storage === 1) {
                 $file->delete();
             }
         }
     } catch (moodle_exception $e) {
         $bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname);
         // Log error header.
         $bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1);
         // Log original exception problem.
         $bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1);
         // Log original debug information.
         $outcome = self::BACKUP_STATUS_ERROR;
     }
     // Delete the backup file immediately if something went wrong.
     if ($outcome === self::BACKUP_STATUS_ERROR) {
         // Delete the file from file area if exists.
         if (!empty($file)) {
             $file->delete();
         }
         // Delete file from external storage if exists.
         if ($storage !== 0 && !empty($filename) && file_exists($dir . '/' . $filename)) {
             @unlink($dir . '/' . $filename);
         }
     }
     $bc->destroy();
     unset($bc);
     return $outcome;
 }
Пример #9
0
 /**
  * Creates the backup_confirmation_form instance this stage requires
  *
  * @return backup_confirmation_form
  */
 protected function initialise_stage_form()
 {
     global $PAGE;
     if ($this->stageform === null) {
         // Get the form
         $form = new backup_confirmation_form($this, $PAGE->url);
         $content = '';
         $courseheading = false;
         foreach ($this->ui->get_tasks() as $task) {
             if ($setting = $task->get_setting('filename')) {
                 $form->add_heading('filenamesetting', get_string('filename', 'backup'));
                 if ($setting->get_value() == 'backup.mbz') {
                     $format = $this->ui->get_format();
                     $type = $this->ui->get_type();
                     $id = $this->ui->get_controller_id();
                     $users = $this->ui->get_setting_value('users');
                     $anonymised = $this->ui->get_setting_value('anonymize');
                     $setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
                 }
                 $form->add_setting($setting, $task);
                 break;
             }
         }
         foreach ($this->ui->get_tasks() as $task) {
             if ($task instanceof backup_root_task) {
                 // If its a backup root add a root settings heading to group nicely
                 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
             } else {
                 if (!$courseheading) {
                     // we havn't already add a course heading
                     $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
                     $courseheading = true;
                 }
             }
             // Iterate all settings, doesnt need to happen by reference
             foreach ($task->get_settings() as $setting) {
                 // For this stage only the filename setting should be editable
                 if ($setting->get_name() != 'filename') {
                     $form->add_fixed_setting($setting, $task);
                 }
             }
         }
         $this->stageform = $form;
     }
     return $this->stageform;
 }
Пример #10
0
 /**
  * Build one 1-course backup
  */
 protected static function build_course_plan($controller, $id)
 {
     $plan = $controller->get_plan();
     // Add the course task, responsible for outputting
     // all the course related information
     $plan->add_task(backup_factory::get_backup_course_task($controller->get_format(), $id));
     // For the given course, add as many section tasks as necessary
     $sections = backup_plan_dbops::get_sections_from_courseid($id);
     foreach ($sections as $section) {
         self::build_section_plan($controller, $section);
     }
     // For the given course, add as many block tasks as necessary
     $blockids = backup_plan_dbops::get_blockids_from_courseid($id);
     foreach ($blockids as $blockid) {
         $plan->add_task(backup_factory::get_backup_block_task($controller->get_format(), $blockid));
     }
 }
Пример #11
0
if ($options['courseid']) {
    $course = $DB->get_record('course', array('id' => $options['courseid']), '*', MUST_EXIST);
} else {
    if ($options['courseshortname']) {
        $course = $DB->get_record('course', array('shortname' => $options['courseshortname']), '*', MUST_EXIST);
    }
}
cli_heading('Performing backup...');
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
// Set the default filename.
$format = $bc->get_format();
$type = $bc->get_type();
$id = $bc->get_id();
$users = $bc->get_plan()->get_setting('users')->get_value();
$anonymised = $bc->get_plan()->get_setting('anonymize')->get_value();
$filename = backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised);
$bc->get_plan()->get_setting('filename')->set_value($filename);
// Execution.
$bc->finish_ui();
$bc->execute_plan();
$results = $bc->get_results();
$file = $results['backup_destination'];
// May be empty if file already moved to target location.
// Do we need to store backup somewhere else?
if (!empty($dir)) {
    if ($file) {
        mtrace("Writing " . $dir . '/' . $filename);
        if ($file->copy_content_to($dir . '/' . $filename)) {
            $file->delete();
            mtrace("Backup completed.");
        } else {
Пример #12
0
 /**
  * Given one backupid and the (FS) final generated file, perform its final storage
  * into Moodle file storage. For stored files it returns the complete file_info object
  */
 public static function store_backup_file($backupid, $filepath)
 {
     // First of all, get some information from the backup_controller to help us decide
     list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($backupid);
     // Extract useful information to decide
     $hasusers = (bool) $sinfo['users']->value;
     // Backup has users
     $isannon = (bool) $sinfo['anonymize']->value;
     // Backup is anonymised
     $filename = $sinfo['filename']->value;
     // Backup filename
     $backupmode = $dinfo[0]->mode;
     // Backup mode backup::MODE_GENERAL/IMPORT/HUB
     $backuptype = $dinfo[0]->type;
     // Backup type backup::TYPE_1ACTIVITY/SECTION/COURSE
     $userid = $dinfo[0]->userid;
     // User->id executing the backup
     $id = $dinfo[0]->id;
     // Id of activity/section/course (depends of type)
     $courseid = $dinfo[0]->courseid;
     // Id of the course
     // Quick hack. If for any reason, filename is blank, fix it here.
     // TODO: This hack will be out once MDL-22142 - P26 gets fixed
     if (empty($filename)) {
         $filename = backup_plan_dbops::get_default_backup_filename('moodle2', $backuptype, $id, $hasusers, $isannon);
     }
     // Backups of type IMPORT aren't stored ever
     if ($backupmode == backup::MODE_IMPORT) {
         return false;
     }
     // Calculate file storage options of id being backup
     $ctxid = 0;
     $filearea = '';
     $component = '';
     $itemid = 0;
     switch ($backuptype) {
         case backup::TYPE_1ACTIVITY:
             $ctxid = get_context_instance(CONTEXT_MODULE, $id)->id;
             $component = 'backup';
             $filearea = 'activity';
             $itemid = 0;
             break;
         case backup::TYPE_1SECTION:
             $ctxid = get_context_instance(CONTEXT_COURSE, $courseid)->id;
             $component = 'backup';
             $filearea = 'section';
             $itemid = $id;
             break;
         case backup::TYPE_1COURSE:
             $ctxid = get_context_instance(CONTEXT_COURSE, $courseid)->id;
             $component = 'backup';
             $filearea = 'course';
             $itemid = 0;
             break;
     }
     if ($backupmode == backup::MODE_AUTOMATED) {
         // Automated backups have there own special area!
         $filearea = 'automated';
     }
     // Backups of type HUB (by definition never have user info)
     // are sent to user's "user_tohub" file area. The upload process
     // will be responsible for cleaning that filearea once finished
     if ($backupmode == backup::MODE_HUB) {
         $ctxid = get_context_instance(CONTEXT_USER, $userid)->id;
         $component = 'user';
         $filearea = 'tohub';
         $itemid = 0;
     }
     // Backups without user info or with the anonymise functionality
     // enabled are sent to user's "user_backup"
     // file area. Maintenance of such area is responsibility of
     // the user via corresponding file manager frontend
     if ($backupmode == backup::MODE_GENERAL && (!$hasusers || $isannon)) {
         $ctxid = get_context_instance(CONTEXT_USER, $userid)->id;
         $component = 'user';
         $filearea = 'backup';
         $itemid = 0;
     }
     // Let's send the file to file storage, everything already defined
     $fs = get_file_storage();
     $fr = array('contextid' => $ctxid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid, 'filepath' => '/', 'filename' => $filename, 'userid' => $userid, 'timecreated' => time(), 'timemodified' => time());
     // If file already exists, delete if before
     // creating it again. This is BC behaviour - copy()
     // overwrites by default
     if ($fs->file_exists($fr['contextid'], $fr['component'], $fr['filearea'], $fr['itemid'], $fr['filepath'], $fr['filename'])) {
         $pathnamehash = $fs->get_pathname_hash($fr['contextid'], $fr['component'], $fr['filearea'], $fr['itemid'], $fr['filepath'], $fr['filename']);
         $sf = $fs->get_file_by_hash($pathnamehash);
         $sf->delete();
     }
     return $fs->create_file_from_pathname($fr, $filepath);
 }