Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/backup/controller/restore_controller.class.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00033 class restore_controller extends backup implements loggable {
00034 
00035     protected $tempdir;   // Directory under tempdir/backup awaiting restore
00036     protected $restoreid; // Unique identificator for this restore
00037 
00038     protected $courseid; // courseid where restore is going to happen
00039 
00040     protected $type;   // Type of backup (activity, section, course)
00041     protected $format; // Format of backup (moodle, imscc)
00042     protected $interactive; // yes/no
00043     protected $mode;   // Purpose of the backup (default settings)
00044     protected $userid; // user id executing the restore
00045     protected $operation; // Type of operation (backup/restore)
00046     protected $target;    // Restoring to new/existing/current_adding/_deleting
00047     protected $samesite;  // Are we restoring to the same site where the backup was generated
00048 
00049     protected $status; // Current status of the controller (created, planned, configured...)
00050     protected $precheck;    // Results of the execution of restore prechecks
00051 
00052     protected $info;   // Information retrieved from backup contents
00053     protected $plan;   // Restore execution plan
00054 
00055     protected $execution;     // inmediate/delayed
00056     protected $executiontime; // epoch time when we want the restore to be executed (requires cron to run)
00057 
00058     protected $logger;      // Logging chain object (moodle, inline, fs, db, syslog)
00059 
00060     protected $checksum; // Cache @checksumable results for lighter @is_checksum_correct() uses
00061 
00071     public function __construct($tempdir, $courseid, $interactive, $mode, $userid, $target){
00072         $this->tempdir = $tempdir;
00073         $this->courseid = $courseid;
00074         $this->interactive = $interactive;
00075         $this->mode = $mode;
00076         $this->userid = $userid;
00077         $this->target = $target;
00078 
00079         // Apply some defaults
00080         $this->type = '';
00081         $this->format = backup::FORMAT_UNKNOWN;
00082         $this->execution = backup::EXECUTION_INMEDIATE;
00083         $this->operation = backup::OPERATION_RESTORE;
00084         $this->executiontime = 0;
00085         $this->samesite = false;
00086         $this->checksum = '';
00087         $this->precheck = null;
00088 
00089         // Apply current backup version and release if necessary
00090         backup_controller_dbops::apply_version_and_release();
00091 
00092         // Check courseid is correct
00093         restore_check::check_courseid($this->courseid);
00094 
00095         // Check user is correct
00096         restore_check::check_user($this->userid);
00097 
00098         // Calculate unique $restoreid
00099         $this->calculate_restoreid();
00100 
00101         // Default logger chain (based on interactive/execution)
00102         $this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->restoreid);
00103 
00104         // Instantiate the output_controller singleton and active it if interactive and inmediate
00105         $oc = output_controller::get_instance();
00106         if ($this->interactive == backup::INTERACTIVE_YES && $this->execution == backup::EXECUTION_INMEDIATE) {
00107             $oc->set_active(true);
00108         }
00109 
00110         $this->log('instantiating restore controller', backup::LOG_INFO, $this->restoreid);
00111 
00112         // Set initial status
00113         $this->set_status(backup::STATUS_CREATED);
00114 
00115         // Calculate original restore format
00116         $this->format = backup_general_helper::detect_backup_format($tempdir);
00117 
00118         // If format is not moodle2, set to conversion needed
00119         if ($this->format !== backup::FORMAT_MOODLE) {
00120             $this->set_status(backup::STATUS_REQUIRE_CONV);
00121 
00122         // Else, format is moodle2, load plan, apply security and set status based on interactivity
00123         } else {
00124             // Load plan
00125             $this->load_plan();
00126 
00127             // Perform all initial security checks and apply (2nd param) them to settings automatically
00128             restore_check::check_security($this, true);
00129 
00130             if ($this->interactive == backup::INTERACTIVE_YES) {
00131                 $this->set_status(backup::STATUS_SETTING_UI);
00132             } else {
00133                 $this->set_status(backup::STATUS_NEED_PRECHECK);
00134             }
00135         }
00136     }
00137 
00150     public function destroy() {
00151         // Only need to destroy circulars under the plan. Delegate to it.
00152         $this->plan->destroy();
00153     }
00154 
00155     public function finish_ui() {
00156         if ($this->status != backup::STATUS_SETTING_UI) {
00157             throw new restore_controller_exception('cannot_finish_ui_if_not_setting_ui');
00158         }
00159         $this->set_status(backup::STATUS_NEED_PRECHECK);
00160     }
00161 
00162     public function process_ui_event() {
00163 
00164         // Perform security checks throwing exceptions (2nd param) if something is wrong
00165         restore_check::check_security($this, false);
00166     }
00167 
00168     public function set_status($status) {
00169         $this->log('setting controller status to', backup::LOG_DEBUG, $status);
00170         // TODO: Check it's a correct status
00171         $this->status = $status;
00172         // Ensure that, once set to backup::STATUS_AWAITING | STATUS_NEED_PRECHECK, controller is stored in DB
00173         // Note: never save_controller() after STATUS_EXECUTING or the whole controller,
00174         // containing all the steps will be sent to DB. 100% (monster) useless.
00175         if ($status == backup::STATUS_AWAITING || $status == backup::STATUS_NEED_PRECHECK) {
00176             $this->save_controller();
00177             $tbc = self::load_controller($this->restoreid);
00178             $this->logger = $tbc->logger; // wakeup loggers
00179             $tbc->destroy(); // Clean temp controller structures
00180         }
00181     }
00182 
00183     public function set_execution($execution, $executiontime = 0) {
00184         $this->log('setting controller execution', backup::LOG_DEBUG);
00185         // TODO: Check valid execution mode
00186         // TODO: Check time in future
00187         // TODO: Check time = 0 if inmediate
00188         $this->execution = $execution;
00189         $this->executiontime = $executiontime;
00190 
00191         // Default logger chain (based on interactive/execution)
00192         $this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->restoreid);
00193     }
00194 
00195 // checksumable interface methods
00196 
00197     public function calculate_checksum() {
00198         // Reset current checksum to take it out from calculations!
00199         $this->checksum = '';
00200         // Init checksum
00201         $tempchecksum = md5('tempdir-'    . $this->tempdir .
00202                             'restoreid-'  . $this->restoreid .
00203                             'courseid-'   . $this->courseid .
00204                             'type-'       . $this->type .
00205                             'format-'     . $this->format .
00206                             'interactive-'. $this->interactive .
00207                             'mode-'       . $this->mode .
00208                             'userid-'     . $this->userid .
00209                             'target-'     . $this->target .
00210                             'samesite-'   . $this->samesite .
00211                             'operation-'  . $this->operation .
00212                             'status-'     . $this->status .
00213                             'precheck-'   . backup_general_helper::array_checksum_recursive(array($this->precheck)) .
00214                             'execution-'  . $this->execution .
00215                             'plan-'       . backup_general_helper::array_checksum_recursive(array($this->plan)) .
00216                             'info-'       . backup_general_helper::array_checksum_recursive(array($this->info)) .
00217                             'logger-'     . backup_general_helper::array_checksum_recursive(array($this->logger)));
00218         $this->log('calculating controller checksum', backup::LOG_DEBUG, $tempchecksum);
00219         return $tempchecksum;
00220     }
00221 
00222     public function is_checksum_correct($checksum) {
00223         return $this->checksum === $checksum;
00224     }
00225 
00226     public function get_tempdir() {
00227         return $this->tempdir;
00228     }
00229 
00230     public function get_restoreid() {
00231         return $this->restoreid;
00232     }
00233 
00234     public function get_type() {
00235         return $this->type;
00236     }
00237 
00238     public function get_operation() {
00239         return $this->operation;
00240     }
00241 
00242     public function get_courseid() {
00243         return $this->courseid;
00244     }
00245 
00246     public function get_format() {
00247         return $this->format;
00248     }
00249 
00250     public function get_interactive() {
00251         return $this->interactive;
00252     }
00253 
00254     public function get_mode() {
00255         return $this->mode;
00256     }
00257 
00258     public function get_userid() {
00259         return $this->userid;
00260     }
00261 
00262     public function get_target() {
00263         return $this->target;
00264     }
00265 
00266     public function is_samesite() {
00267         return $this->samesite;
00268     }
00269 
00270     public function get_status() {
00271         return $this->status;
00272     }
00273 
00274     public function get_execution() {
00275         return $this->execution;
00276     }
00277 
00278     public function get_executiontime() {
00279         return $this->executiontime;
00280     }
00281 
00286     public function get_plan() {
00287         return $this->plan;
00288     }
00289 
00290     public function get_info() {
00291         return $this->info;
00292     }
00293 
00294     public function get_logger() {
00295         return $this->logger;
00296     }
00297 
00298     public function execute_plan() {
00299         // Basic/initial prevention against time/memory limits
00300         set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
00301         raise_memory_limit(MEMORY_EXTRA);
00302         // If this is not a course restore, inform the plan we are not
00303         // including all the activities for sure. This will affect any
00304         // task/step executed conditionally to stop processing information
00305         // for section and activity restore. MDL-28180.
00306         if ($this->get_type() !== backup::TYPE_1COURSE) {
00307             $this->log('notifying plan about excluded activities by type', backup::LOG_DEBUG);
00308             $this->plan->set_excluding_activities();
00309         }
00310         return $this->plan->execute();
00311     }
00312 
00326     public function execute_precheck($droptemptablesafter = false) {
00327         if (is_array($this->precheck)) {
00328             throw new restore_controller_exception('precheck_alredy_executed', $this->status);
00329         }
00330         if ($this->status != backup::STATUS_NEED_PRECHECK) {
00331             throw new restore_controller_exception('cannot_precheck_wrong_status', $this->status);
00332         }
00333         $this->precheck = restore_prechecks_helper::execute_prechecks($this, $droptemptablesafter);
00334         if (!array_key_exists('errors', $this->precheck)) { // No errors, can be executed
00335             $this->set_status(backup::STATUS_AWAITING);
00336         }
00337         if (empty($this->precheck)) { // No errors nor warnings, return true
00338             return true;
00339         }
00340         return false;
00341     }
00342 
00343     public function get_results() {
00344         return $this->plan->get_results();
00345     }
00346 
00351     public function precheck_executed() {
00352         return (is_array($this->precheck));
00353     }
00354 
00355     public function get_precheck_results() {
00356         if (!is_array($this->precheck)) {
00357             throw new restore_controller_exception('precheck_not_executed');
00358         }
00359         return $this->precheck;
00360     }
00361 
00362     public function log($message, $level, $a = null, $depth = null, $display = false) {
00363         backup_helper::log($message, $level, $a, $depth, $display, $this->logger);
00364     }
00365 
00366     public function save_controller() {
00367         // Going to save controller to persistent storage, calculate checksum for later checks and save it
00368         // TODO: flag the controller as NA. Any operation on it should be forbidden util loaded back
00369         $this->log('saving controller to db', backup::LOG_DEBUG);
00370         $this->checksum = $this->calculate_checksum();
00371         restore_controller_dbops::save_controller($this, $this->checksum);
00372     }
00373 
00374     public static function load_controller($restoreid) {
00375         // Load controller from persistent storage
00376         // TODO: flag the controller as available. Operations on it can continue
00377         $controller = restore_controller_dbops::load_controller($restoreid);
00378         $controller->log('loading controller from db', backup::LOG_DEBUG);
00379         return $controller;
00380     }
00381 
00385     public static function get_tempdir_name($courseid = 0, $userid = 0) {
00386         // Current epoch time + courseid + userid + random bits
00387         return md5(time() . '-' . $courseid . '-'. $userid . '-'. random_string(20));
00388     }
00389 
00393     public function convert() {
00394         global $CFG;
00395         require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');
00396 
00397         // Basic/initial prevention against time/memory limits
00398         set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
00399         raise_memory_limit(MEMORY_EXTRA);
00400 
00401         if ($this->status != backup::STATUS_REQUIRE_CONV) {
00402             throw new restore_controller_exception('cannot_convert_not_required_status');
00403         }
00404 
00405         $this->log('backup format conversion required', backup::LOG_INFO);
00406 
00407         // Run conversion to the proper format
00408         if (!convert_helper::to_moodle2_format($this->get_tempdir(), $this->format, $this->get_logger())) {
00409             // todo - unable to find the conversion path, what to do now?
00410             // throwing the exception as a temporary solution
00411             throw new restore_controller_exception('unable_to_find_conversion_path');
00412         }
00413 
00414         $this->log('backup format conversion successful', backup::LOG_INFO);
00415 
00416         // If no exceptions were thrown, then we are in the proper format
00417         $this->format = backup::FORMAT_MOODLE;
00418 
00419         // Load plan, apply security and set status based on interactivity
00420         $this->load_plan();
00421 
00422         // Perform all initial security checks and apply (2nd param) them to settings automatically
00423         restore_check::check_security($this, true);
00424 
00425         if ($this->interactive == backup::INTERACTIVE_YES) {
00426             $this->set_status(backup::STATUS_SETTING_UI);
00427         } else {
00428             $this->set_status(backup::STATUS_NEED_PRECHECK);
00429         }
00430     }
00431 
00432 // Protected API starts here
00433 
00434     protected function calculate_restoreid() {
00435         // Current epoch time + tempdir + courseid + interactive + mode + userid + target + operation + random bits
00436         $this->restoreid = md5(time() . '-' . $this->tempdir . '-' . $this->courseid . '-'. $this->interactive . '-' .
00437                                $this->mode . '-' . $this->userid . '-'. $this->target . '-' . $this->operation . '-' .
00438                                random_string(20));
00439     }
00440 
00441     protected function load_plan() {
00442         // First of all, we need to introspect the moodle_backup.xml file
00443         // in order to detect all the required stuff. So, create the
00444         // monster $info structure where everything will be defined
00445         $this->log('loading backup info', backup::LOG_DEBUG);
00446         $this->info = backup_general_helper::get_backup_information($this->tempdir);
00447 
00448         // Set the controller type to the one found in the information
00449         $this->type = $this->info->type;
00450 
00451         // Set the controller samesite flag as needed
00452         $this->samesite = backup_general_helper::backup_is_samesite($this->info);
00453 
00454         // Now we load the plan that will be configured following the
00455         // information provided by the $info
00456         $this->log('loading controller plan', backup::LOG_DEBUG);
00457         $this->plan = new restore_plan($this);
00458         $this->plan->build(); // Build plan for this controller
00459         $this->set_status(backup::STATUS_PLANNED);
00460     }
00461 }
00462 
00463 /*
00464  * Exception class used by all the @restore_controller stuff
00465  */
00466 class restore_controller_exception extends backup_exception {
00467 
00468     public function __construct($errorcode, $a=NULL, $debuginfo=null) {
00469         parent::__construct($errorcode, $a, $debuginfo);
00470     }
00471 }
 All Data Structures Namespaces Files Functions Variables Enumerations