|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00024 require_once 'xmlbase.php'; 00025 00032 abstract class cc_helpers { 00033 00039 public static function is_html($filename) { 00040 $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); 00041 return in_array($extension, array('htm', 'html')); 00042 } 00043 00051 public static function uuidgen($prefix = '', $suffix = '', $uppercase = true) { 00052 $uuid = trim(sprintf('%s%04x%04x%s', $prefix, mt_rand(0, 65535), mt_rand(0, 65535), $suffix)); 00053 $result = $uppercase ? strtoupper($uuid) : strtolower($uuid) ; 00054 return $result; 00055 } 00056 00065 public static function randomdir($where, $prefix = '', $suffix = '') { 00066 $dirname = false; 00067 $randomname = self::uuidgen($prefix, $suffix, false); 00068 $newdirname = $where.DIRECTORY_SEPARATOR.$randomname; 00069 if (mkdir($newdirname)) { 00070 chmod($newdirname, 0755); 00071 $dirname = $randomname; 00072 } 00073 return $dirname; 00074 } 00075 00076 public static function build_query($attributes, $search) { 00077 $result = ''; 00078 foreach ($attributes as $attribute) { 00079 if ($result != '') { 00080 $result .= ' | '; 00081 } 00082 $result .= "//*[starts-with(@{$attribute},'{$search}')]/@{$attribute}"; 00083 } 00084 return $result; 00085 } 00086 00087 public static function process_embedded_files(&$doc, $attributes, $search, $customslash = null) { 00088 $result = array(); 00089 $query = self::build_query($attributes, $search); 00090 $list = $doc->nodeList($query); 00091 foreach ($list as $filelink) { 00092 $rvalue = str_replace($search, '', $filelink->nodeValue); 00093 if (!empty($customslash)) { 00094 $rvalue = str_replace($customslash, '/', $rvalue); 00095 } 00096 $result[] = rawurldecode($rvalue); 00097 } 00098 return $result; 00099 } 00100 00107 public static function embedded_files($html) { 00108 $result = array(); 00109 $doc = new XMLGenericDocument(); 00110 $doc->doc->validateOnParse = false; 00111 $doc->doc->strictErrorChecking = false; 00112 if (!empty($html) && $doc->loadHTML($html)) { 00113 $attributes = array('src', 'href'); 00114 $result1 = self::process_embedded_files($doc, $attributes, '@@PLUGINFILE@@'); 00115 $result2 = self::process_embedded_files($doc, $attributes, '$@FILEPHP@$', '$@SLASH@$'); 00116 $result = array_merge($result1, $result2); 00117 } 00118 return $result; 00119 } 00120 00121 public static function embedded_mapping($packageroot, $contextid = null) { 00122 $main_file = $packageroot . DIRECTORY_SEPARATOR . 'files.xml'; 00123 $mfile = new XMLGenericDocument(); 00124 if (!$mfile->load($main_file)) { 00125 return false; 00126 } 00127 $query = "/files/file[filename!='.']"; 00128 if (!empty($contextid)) { 00129 $query .= "[contextid='{$contextid}']"; 00130 } 00131 $files = $mfile->nodeList($query); 00132 $depfiles = array(); 00133 foreach ($files as $node) { 00134 $mainfile = intval($mfile->nodeValue('sortorder', $node)); 00135 $filename = $mfile->nodeValue('filename', $node); 00136 $filepath = $mfile->nodeValue('filepath', $node); 00137 $source = $mfile->nodeValue('source', $node); 00138 $author = $mfile->nodeValue('author', $node); 00139 $license = $mfile->nodeValue('license', $node); 00140 $hashedname = $mfile->nodeValue('contenthash', $node); 00141 $hashpart = substr($hashedname, 0, 2); 00142 $location = 'files'.DIRECTORY_SEPARATOR.$hashpart.DIRECTORY_SEPARATOR.$hashedname; 00143 $type = $mfile->nodeValue('mimetype', $node); 00144 $depfiles[$filepath.$filename] = array( $location, 00145 ($mainfile == 1), 00146 strtolower(str_replace(' ', '_',$filename)), 00147 $type, 00148 $source, 00149 $author, 00150 $license, 00151 strtolower(str_replace(' ', '_',$filepath))); 00152 } 00153 00154 return $depfiles; 00155 } 00156 00157 public static function add_files(cc_i_manifest &$manifest, $packageroot, $outdir, $allinone = true) { 00158 if (pkg_static_resources::instance()->finished) { 00159 return; 00160 } 00161 $files = cc_helpers::embedded_mapping($packageroot); 00162 $rdir = $allinone ? new cc_resource_location($outdir) : null; 00163 foreach ($files as $virtual => $values) { 00164 $clean_filename = $values[2]; 00165 if (!$allinone) { 00166 $rdir = new cc_resource_location($outdir); 00167 } 00168 $rtp = $rdir->fullpath().$values[7].$clean_filename; 00169 //Are there any relative virtual directories? 00170 //let us try to recreate them 00171 $justdir = $rdir->fullpath(false).$values[7]; 00172 if (!file_exists($justdir)) { 00173 if (!mkdir($justdir, 0777, true)) { 00174 throw new RuntimeException('Unable to create directories!'); 00175 } 00176 } 00177 00178 $source = $packageroot.DIRECTORY_SEPARATOR.$values[0]; 00179 if (!copy($source, $rtp)) { 00180 throw new RuntimeException('Unable to copy files!'); 00181 } 00182 $resource = new cc_resource($rdir->rootdir(), 00183 $values[7].$clean_filename, 00184 $rdir->dirname(false)); 00185 $res = $manifest->add_resource($resource, null, cc_version11::webcontent); 00186 pkg_static_resources::instance()->add($virtual, 00187 $res[0], 00188 $rdir->dirname(false).$values[7].$clean_filename, 00189 $values[1], 00190 $resource); 00191 } 00192 00193 pkg_static_resources::instance()->finished = true; 00194 } 00195 00209 public static function handle_static_content(cc_i_manifest &$manifest, $packageroot, $contextid, $outdir, $allinone = true){ 00210 cc_helpers::add_files($manifest, $packageroot, $outdir, $allinone); 00211 return pkg_static_resources::instance()->get_values(); 00212 } 00213 00214 public static function handle_resource_content(cc_i_manifest &$manifest, $packageroot, $contextid, $outdir, $allinone = true){ 00215 $result = array(); 00216 cc_helpers::add_files($manifest, $packageroot, $outdir, $allinone); 00217 $files = cc_helpers::embedded_mapping($packageroot, $contextid); 00218 //$rdir = $allinone ? new cc_resource_location($outdir) : null; 00219 $rootnode = null; 00220 $rootvals = null; 00221 $depfiles = array(); 00222 $depres = array(); 00223 $flocation = null; 00224 foreach ($files as $virtual => $values) { 00225 $clean_filename = $values[2]; 00226 $vals = pkg_static_resources::instance()->get_identifier($virtual); 00227 $resource = $vals[3]; 00228 $identifier = $resource->identifier; 00229 $flocation = $vals[1]; 00230 if ($values[1]) { 00231 $rootnode = $resource; 00232 $rootvals = $flocation; 00233 continue; 00234 } 00235 00236 $depres[] = $identifier; 00237 $depfiles[] = $vals[1]; 00238 $result[$virtual] = array($identifier, $flocation, false); 00239 } 00240 00241 if (!empty($rootnode)) { 00242 $rootnode->files = array_merge($rootnode->files, $depfiles); 00243 $result[$virtual] = array($rootnode->identifier, $rootvals, true); 00244 } 00245 00246 return $result; 00247 } 00248 00249 public static function process_linked_files($content, cc_i_manifest &$manifest, $packageroot, $contextid, $outdir, $webcontent = false) { 00260 $lfiles = self::embedded_files($content); 00261 $text = $content; 00262 $deps = array(); 00263 if (!empty($lfiles)) { 00264 $files = self::handle_static_content($manifest, 00265 $packageroot, 00266 $contextid, 00267 $outdir); 00268 $replaceprefix = $webcontent ? '' : '$IMS-CC-FILEBASE$'; 00269 foreach ($lfiles as $lfile) { 00270 if (array_key_exists($lfile, $files)) { 00271 $filename = str_replace('%2F', '/',rawurlencode($lfile)); 00272 $content = str_replace('@@PLUGINFILE@@'.$filename, 00273 $replaceprefix.'../'.$files[$lfile][1], 00274 $content); 00275 //for the legacy stuff 00276 $content = str_replace('$@FILEPHP@$'.str_replace('/','$@SLASH@$',$filename), 00277 $replaceprefix.'../'.$files[$lfile][1], 00278 $content); 00279 $deps[] = $files[$lfile][0]; 00280 } 00281 } 00282 $text = $content; 00283 } 00284 return array($text, $deps); 00285 } 00286 00287 public static function relative_location($originpath, $linkingpath) { 00288 return false; 00289 } 00290 00291 } 00292 00293 00294 final class cc_resource_location { 00300 private $rootdir = null; 00306 private $dir = null; 00312 private $fullpath = null; 00313 00321 public function __construct($rootdir) { 00322 $rdir = realpath($rootdir); 00323 if (empty($rdir)) { 00324 throw new InvalidArgumentException('Invalid path!'); 00325 } 00326 $dir = cc_helpers::randomdir($rdir, 'i_'); 00327 if ($dir === false) { 00328 throw new RuntimeException('Unable to create directory!'); 00329 } 00330 $this->rootdir = $rdir; 00331 $this->dir = $dir; 00332 $this->fullpath = $rdir.DIRECTORY_SEPARATOR.$dir; 00333 } 00334 00340 public function dirname($endseparator=false) { 00341 return $this->dir.($endseparator ? '/' : ''); 00342 } 00343 00349 public function fullpath($endseparator=false) { 00350 return $this->fullpath.($endseparator ? DIRECTORY_SEPARATOR : ''); 00351 } 00352 00357 public function rootdir($endseparator=false) { 00358 return $this->rootdir.($endseparator ? DIRECTORY_SEPARATOR : ''); 00359 } 00360 } 00361 00362 class pkg_static_resources { 00363 00367 private $values = array(); 00368 00372 public $finished = false; 00373 00377 private static $instance = null; 00378 00379 private function __clone() {} 00380 private function __construct() {} 00381 00385 public static function instance() { 00386 if (empty(self::$instance)) { 00387 $c = __CLASS__; 00388 self::$instance = new $c(); 00389 } 00390 return self::$instance; 00391 } 00392 00400 public function add($key, $identifier, $file, $main, $node = null) { 00401 $this->values[$key] = array($identifier, $file, $main, $node); 00402 } 00403 00407 public function get_values() { 00408 return $this->values; 00409 } 00410 00411 public function get_identifier($location) { 00412 $result = false; 00413 if (array_key_exists($location, $this->values)) { 00414 $result = $this->values[$location]; 00415 } 00416 return $result; 00417 } 00418 00419 public function reset() { 00420 $this->values = array(); 00421 $this->finished = false ; 00422 } 00423 } 00424 00425 00426 class pkg_resource_dependencies { 00430 private $values = array(); 00431 00435 private static $instance = null; 00436 00437 private function __clone() { 00438 } 00439 private function __construct() { 00440 } 00441 00445 public static function instance() { 00446 if (empty(self::$instance)) { 00447 $c = __CLASS__; 00448 self::$instance = new $c(); 00449 } 00450 return self::$instance; 00451 } 00452 00456 public function add(array $deps) { 00457 $this->values = array_merge($this->values, $deps); 00458 } 00459 00460 public function reset() { 00461 $this->values = array(); 00462 } 00463 00467 public function get_deps() { 00468 return $this->values; 00469 } 00470 }