Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/backup/util/helper/convert_helper.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 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 require_once($CFG->dirroot . '/backup/util/includes/convert_includes.php');
00030 
00034 abstract class convert_helper {
00035 
00040     public static function generate_id($entropy) {
00041         return md5(time() . '-' . $entropy . '-' . random_string(20));
00042     }
00043 
00053     public static function available_converters($restore=true) {
00054         global $CFG;
00055 
00056         $converters = array();
00057 
00058         // Only apply for backup converters if the (experimental) setting enables it.
00059         // This will be out once we get proper support of backup converters. MDL-29956
00060         if (!$restore && empty($CFG->enablebackupconverters)) {
00061             return $converters;
00062         }
00063 
00064         $plugins    = get_list_of_plugins('backup/converter');
00065         foreach ($plugins as $name) {
00066             $filename = $restore ? 'lib.php' : 'backuplib.php';
00067             $classuf  = $restore ? '_converter' : '_export_converter';
00068             $classfile = "{$CFG->dirroot}/backup/converter/{$name}/{$filename}";
00069             $classname = "{$name}{$classuf}";
00070             $zip_contents      = "{$name}_zip_contents";
00071             $store_backup_file = "{$name}_store_backup_file";
00072             $convert           = "{$name}_backup_convert";
00073 
00074             if (!file_exists($classfile)) {
00075                 throw new convert_helper_exception('converter_classfile_not_found', $classfile);
00076             }
00077 
00078             require_once($classfile);
00079 
00080             if (!class_exists($classname)) {
00081                 throw new convert_helper_exception('converter_classname_not_found', $classname);
00082             }
00083 
00084             if (call_user_func($classname .'::is_available')) {
00085                 if (!$restore) {
00086                     if (!class_exists($zip_contents)) {
00087                         throw new convert_helper_exception('converter_classname_not_found', $zip_contents);
00088                     }
00089                     if (!class_exists($store_backup_file)) {
00090                         throw new convert_helper_exception('converter_classname_not_found', $store_backup_file);
00091                     }
00092                     if (!class_exists($convert)) {
00093                         throw new convert_helper_exception('converter_classname_not_found', $convert);
00094                     }
00095                 }
00096 
00097                 $converters[] = $name;
00098             }
00099 
00100         }
00101 
00102         return $converters;
00103     }
00104 
00105     public static function export_converter_dependencies($converter, $dependency) {
00106         global $CFG;
00107 
00108         $result = array();
00109         $filename = 'backuplib.php';
00110         $classuf  = '_export_converter';
00111         $classfile = "{$CFG->dirroot}/backup/converter/{$converter}/{$filename}";
00112         $classname = "{$converter}{$classuf}";
00113 
00114         if (!file_exists($classfile)) {
00115             throw new convert_helper_exception('converter_classfile_not_found', $classfile);
00116         }
00117         require_once($classfile);
00118 
00119         if (!class_exists($classname)) {
00120             throw new convert_helper_exception('converter_classname_not_found', $classname);
00121         }
00122 
00123         if (call_user_func($classname .'::is_available')) {
00124             $deps = call_user_func($classname .'::get_deps');
00125             if (array_key_exists($dependency, $deps)) {
00126                 $result = $deps[$dependency];
00127             }
00128         }
00129 
00130         return $result;
00131     }
00132 
00139     public static function detect_moodle2_format($tempdir) {
00140         global $CFG;
00141 
00142         $dirpath    = $CFG->tempdir . '/backup/' . $tempdir;
00143         $filepath   = $dirpath . '/moodle_backup.xml';
00144 
00145         if (!is_dir($dirpath)) {
00146             throw new convert_helper_exception('tmp_backup_directory_not_found', $dirpath);
00147         }
00148 
00149         if (!file_exists($filepath)) {
00150             return false;
00151         }
00152 
00153         $handle     = fopen($filepath, 'r');
00154         $firstchars = fread($handle, 200);
00155         $status     = fclose($handle);
00156 
00157         if (strpos($firstchars,'<?xml version="1.0" encoding="UTF-8"?>') !== false and
00158             strpos($firstchars,'<moodle_backup>') !== false and
00159             strpos($firstchars,'<information>') !== false) {
00160                 return true;
00161         }
00162 
00163         return false;
00164     }
00165 
00175     public static function to_moodle2_format($tempdir, $format = null, $logger = null) {
00176 
00177         if (is_null($format)) {
00178             $format = backup_general_helper::detect_backup_format($tempdir);
00179         }
00180 
00181         // get the supported conversion paths from all available converters
00182         $converters   = self::available_converters();
00183         $descriptions = array();
00184         foreach ($converters as $name) {
00185             $classname = "{$name}_converter";
00186             if (!class_exists($classname)) {
00187                 throw new convert_helper_exception('class_not_loaded', $classname);
00188             }
00189             if ($logger instanceof base_logger) {
00190                 backup_helper::log('available converter', backup::LOG_DEBUG, $classname, 1, false, $logger);
00191             }
00192             $descriptions[$name] = call_user_func($classname .'::description');
00193         }
00194 
00195         // choose the best conversion path for the given format
00196         $path = self::choose_conversion_path($format, $descriptions);
00197 
00198         if (empty($path)) {
00199             if ($logger instanceof base_logger) {
00200                 backup_helper::log('unable to find the conversion path', backup::LOG_ERROR, null, 0, false, $logger);
00201             }
00202             return false;
00203         }
00204 
00205         if ($logger instanceof base_logger) {
00206             backup_helper::log('conversion path established', backup::LOG_INFO,
00207                 implode(' => ', array_merge($path, array('moodle2'))), 0, false, $logger);
00208         }
00209 
00210         foreach ($path as $name) {
00211             if ($logger instanceof base_logger) {
00212                 backup_helper::log('running converter', backup::LOG_INFO, $name, 0, false, $logger);
00213             }
00214             $converter = convert_factory::get_converter($name, $tempdir, $logger);
00215             $converter->convert();
00216         }
00217 
00218         // make sure we ended with moodle2 format
00219         if (!self::detect_moodle2_format($tempdir)) {
00220             throw new convert_helper_exception('conversion_failed');
00221         }
00222 
00223         return true;
00224     }
00225 
00229     public static function set_inforef($contextid) {
00230         global $DB;
00231     }
00232 
00233     public static function get_inforef($contextid) {
00234     }
00235 
00237 
00255     protected static function choose_conversion_path($format, array $descriptions) {
00256 
00257         // construct an oriented graph of conversion paths. backup formats are nodes
00258         // and the the converters are edges of the graph.
00259         $paths = array();   // [fromnode][tonode] => converter
00260         foreach ($descriptions as $converter => $description) {
00261             $from   = $description['from'];
00262             $to     = $description['to'];
00263             $cost   = $description['cost'];
00264 
00265             if (is_null($from) or $from === backup::FORMAT_UNKNOWN or
00266                 is_null($to) or $to === backup::FORMAT_UNKNOWN or
00267                 is_null($cost) or $cost <= 0) {
00268                     throw new convert_helper_exception('invalid_converter_description', $converter);
00269             }
00270 
00271             if (!isset($paths[$from][$to])) {
00272                 $paths[$from][$to] = $converter;
00273             } else {
00274                 // if there are two converters available for the same conversion
00275                 // path, choose the one with the lowest cost. if there are more
00276                 // available converters with the same cost, the chosen one is
00277                 // undefined (depends on the order of processing)
00278                 if ($descriptions[$paths[$from][$to]]['cost'] > $cost) {
00279                     $paths[$from][$to] = $converter;
00280                 }
00281             }
00282         }
00283 
00284         if (empty($paths)) {
00285             // no conversion paths available
00286             return array();
00287         }
00288 
00289         // now use Dijkstra's algorithm and find the shortest conversion path
00290 
00291         $dist = array(); // list of nodes and their distances from the source format
00292         $prev = array(); // list of previous nodes in optimal path from the source format
00293         foreach ($paths as $fromnode => $tonodes) {
00294             $dist[$fromnode] = null; // infinitive distance, can't be reached
00295             $prev[$fromnode] = null; // unknown
00296             foreach ($tonodes as $tonode => $converter) {
00297                 $dist[$tonode] = null; // infinitive distance, can't be reached
00298                 $prev[$tonode] = null; // unknown
00299             }
00300         }
00301 
00302         if (!array_key_exists($format, $dist)) {
00303             return array();
00304         } else {
00305             $dist[$format] = 0;
00306         }
00307 
00308         $queue = array_flip(array_keys($dist));
00309         while (!empty($queue)) {
00310             // find the node with the smallest distance from the source in the queue
00311             // in the first iteration, this will find the original format node itself
00312             $closest = null;
00313             foreach ($queue as $node => $undefined) {
00314                 if (is_null($dist[$node])) {
00315                     continue;
00316                 }
00317                 if (is_null($closest) or ($dist[$node] < $dist[$closest])) {
00318                     $closest = $node;
00319                 }
00320             }
00321 
00322             if (is_null($closest) or is_null($dist[$closest])) {
00323                 // all remaining nodes are inaccessible from source
00324                 break;
00325             }
00326 
00327             if ($closest === backup::FORMAT_MOODLE) {
00328                 // bingo we can break now
00329                 break;
00330             }
00331 
00332             unset($queue[$closest]);
00333 
00334             // visit all neighbors and update distances to them eventually
00335 
00336             if (!isset($paths[$closest])) {
00337                 continue;
00338             }
00339             $neighbors = array_keys($paths[$closest]);
00340             // keep just neighbors that are in the queue yet
00341             foreach ($neighbors as $ix => $neighbor) {
00342                 if (!array_key_exists($neighbor, $queue)) {
00343                     unset($neighbors[$ix]);
00344                 }
00345             }
00346 
00347             foreach ($neighbors as $neighbor) {
00348                 // the alternative distance to the neighbor if we went thru the
00349                 // current $closest node
00350                 $alt = $dist[$closest] + $descriptions[$paths[$closest][$neighbor]]['cost'];
00351 
00352                 if (is_null($dist[$neighbor]) or $alt < $dist[$neighbor]) {
00353                     // we found a shorter way to the $neighbor, remember it
00354                     $dist[$neighbor] = $alt;
00355                     $prev[$neighbor] = $closest;
00356                 }
00357             }
00358         }
00359 
00360         if (is_null($dist[backup::FORMAT_MOODLE])) {
00361             // unable to find a conversion path, the target format not reachable
00362             return array();
00363         }
00364 
00365         // reconstruct the optimal path from the source format to the target one
00366         $conversionpath = array();
00367         $target         = backup::FORMAT_MOODLE;
00368         while (isset($prev[$target])) {
00369             array_unshift($conversionpath, $paths[$prev[$target]][$target]);
00370             $target = $prev[$target];
00371         }
00372 
00373         return $conversionpath;
00374     }
00375 }
00376 
00382 class convert_helper_exception extends moodle_exception {
00383 
00391     public function __construct($errorcode, $a = null, $debuginfo = null) {
00392         parent::__construct($errorcode, '', '', $a, $debuginfo);
00393     }
00394 }
 All Data Structures Namespaces Files Functions Variables Enumerations