|
Moodle
2.2.1
http://www.collinsharper.com
|
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 00128 defined('MOODLE_INTERNAL') || die(); 00129 00134 global $CFG; 00135 require_once($CFG->libdir.'/filelib.php'); 00136 00137 // Some needed constants 00138 define('COMPONENT_ERROR', 0); 00139 define('COMPONENT_UPTODATE', 1); 00140 define('COMPONENT_NEEDUPDATE', 2); 00141 define('COMPONENT_INSTALLED', 3); 00142 00155 class component_installer { 00159 var $sourcebase; 00160 var $zippath; 00161 00162 var $zipfilename; 00163 var $md5filename; 00164 var $componentname; 00165 00166 00167 00168 var $destpath; 00169 00170 var $errorstring; 00171 var $extramd5info; 00172 var $requisitesok; 00173 00176 var $cachedmd5components; 00177 00178 00193 function component_installer ($sourcebase, $zippath, $zipfilename, $md5filename='', $destpath='') { 00194 00195 $this->sourcebase = $sourcebase; 00196 $this->zippath = $zippath; 00197 $this->zipfilename = $zipfilename; 00198 $this->md5filename = $md5filename; 00199 $this->componentname= ''; 00200 $this->destpath = $destpath; 00201 $this->errorstring = ''; 00202 $this->extramd5info = ''; 00203 $this->requisitesok = false; 00204 $this->cachedmd5components = array(); 00205 00206 $this->check_requisites(); 00207 } 00208 00217 function check_requisites() { 00218 global $CFG; 00219 00220 $this->requisitesok = false; 00221 00223 if (empty($this->sourcebase) || empty($this->zippath) || empty($this->zipfilename)) { 00224 $this->errorstring='missingrequiredfield'; 00225 return false; 00226 } 00228 if ($this->sourcebase != 'http://download.moodle.org') { 00229 $this->errorstring='wrongsourcebase'; 00230 return false; 00231 } 00233 if (stripos($this->zipfilename, '.zip') === false) { 00234 $this->errorstring='wrongzipfilename'; 00235 return false; 00236 } 00238 if (!empty($this->destpath)) { 00239 if (!file_exists($CFG->dataroot.'/'.$this->destpath)) { 00240 $this->errorstring='wrongdestpath'; 00241 return false; 00242 } 00243 } 00245 $pos = stripos($this->zipfilename, '.zip'); 00246 $this->componentname = substr($this->zipfilename, 0, $pos); 00248 if (empty($this->md5filename)) { 00249 $this->md5filename = $this->componentname.'.md5'; 00250 } 00252 $this->requisitesok = true; 00253 return true; 00254 } 00255 00268 function install() { 00269 00270 global $CFG; 00271 00273 if (!$this->requisitesok) { 00274 return COMPONENT_ERROR; 00275 } 00277 if ($this->need_upgrade() === COMPONENT_ERROR) { 00278 return COMPONENT_ERROR; 00279 } else if ($this->need_upgrade() === COMPONENT_UPTODATE) { 00280 $this->errorstring='componentisuptodate'; 00281 return COMPONENT_UPTODATE; 00282 } 00284 if (!make_temp_directory('', false)) { 00285 $this->errorstring='cannotcreatetempdir'; 00286 return COMPONENT_ERROR; 00287 } 00289 $source = $this->sourcebase.'/'.$this->zippath.'/'.$this->zipfilename; 00290 $zipfile= $CFG->tempdir.'/'.$this->zipfilename; 00291 00292 if($contents = download_file_content($source)) { 00293 if ($file = fopen($zipfile, 'w')) { 00294 if (!fwrite($file, $contents)) { 00295 fclose($file); 00296 $this->errorstring='cannotsavezipfile'; 00297 return COMPONENT_ERROR; 00298 } 00299 } else { 00300 $this->errorstring='cannotsavezipfile'; 00301 return COMPONENT_ERROR; 00302 } 00303 fclose($file); 00304 } else { 00305 $this->errorstring='cannotdownloadzipfile'; 00306 return COMPONENT_ERROR; 00307 } 00309 $new_md5 = md5($contents); 00311 if (!$remote_md5 = $this->get_component_md5()) { 00312 return COMPONENT_ERROR; 00313 } 00314 if ($new_md5 != $remote_md5) { 00315 $this->errorstring='downloadedfilecheckfailed'; 00316 return COMPONENT_ERROR; 00317 } 00319 $destinationdir = $CFG->dataroot.'/'.$this->destpath; 00320 $destinationcomponent = $destinationdir.'/'.$this->componentname; 00321 @remove_dir($destinationcomponent.'_old'); //Deleting possible old components before 00322 @rename ($destinationcomponent, $destinationcomponent.'_old'); //Moving to a safe place 00324 if (!unzip_file($zipfile, $destinationdir, false)) { 00326 @remove_dir($destinationcomponent); 00327 @rename ($destinationcomponent.'_old', $destinationcomponent); 00328 $this->errorstring='cannotunzipfile'; 00329 return COMPONENT_ERROR; 00330 } 00332 @remove_dir($destinationcomponent.'_old'); 00334 if ($file = fopen($destinationcomponent.'/'.$this->componentname.'.md5', 'w')) { 00335 if (!fwrite($file, $new_md5)) { 00336 fclose($file); 00337 $this->errorstring='cannotsavemd5file'; 00338 return COMPONENT_ERROR; 00339 } 00340 } else { 00341 $this->errorstring='cannotsavemd5file'; 00342 return COMPONENT_ERROR; 00343 } 00344 fclose($file); 00346 @unlink($zipfile); 00347 00348 return COMPONENT_INSTALLED; 00349 } 00350 00360 function need_upgrade() { 00361 00363 if (!$this->requisitesok) { 00364 return COMPONENT_ERROR; 00365 } 00367 $local_md5 = $this->get_local_md5(); 00369 if (!$remote_md5 = $this->get_component_md5()) { 00370 return COMPONENT_ERROR; 00371 } 00373 if ($local_md5 == $remote_md5) { 00374 return COMPONENT_UPTODATE; 00375 } else { 00376 return COMPONENT_NEEDUPDATE; 00377 } 00378 } 00379 00388 function change_zip_file($newzipfilename) { 00389 00390 $this->zipfilename = $newzipfilename; 00391 return $this->check_requisites(); 00392 } 00393 00401 function get_local_md5() { 00402 global $CFG; 00403 00405 if (!$this->requisitesok) { 00406 return false; 00407 } 00408 00409 $return_value = 'needtobeinstalled'; 00410 00412 $source = $CFG->dataroot.'/'.$this->destpath.'/'.$this->componentname.'/'.$this->componentname.'.md5'; 00414 if (file_exists($source)) { 00415 if ($temp = file_get_contents($source)) { 00416 $return_value = $temp; 00417 } 00418 } 00419 return $return_value; 00420 } 00421 00430 function get_component_md5() { 00431 00433 if (!$this->requisitesok) { 00434 return false; 00435 } 00437 if (!$comp_arr = $this->get_all_components_md5()) { 00438 if (empty($this->errorstring)) { 00439 $this->errorstring='cannotdownloadcomponents'; 00440 } 00441 return false; 00442 } 00444 if (empty($comp_arr[$this->componentname]) || !$component = $comp_arr[$this->componentname]) { 00445 $this->errorstring='cannotfindcomponent'; 00446 return false; 00447 } 00449 if (empty($component[1]) || strlen($component[1]) != 32) { 00450 $this->errorstring='invalidmd5'; 00451 return false; 00452 } 00454 if (!empty($component[2])) { 00455 $this->extramd5info = $component[2]; 00456 } 00457 return $component[1]; 00458 } 00459 00466 function get_all_components_md5() { 00467 00469 if (!$this->requisitesok) { 00470 return false; 00471 } 00472 00474 $comp_arr = array(); 00475 00477 $source = $this->sourcebase.'/'.$this->zippath.'/'.$this->md5filename; 00478 00480 if (!empty($this->cachedmd5components[$source])) { 00481 $comp_arr = $this->cachedmd5components[$source]; 00482 } else { 00484 $availablecomponents = array(); 00485 00486 if ($contents = download_file_content($source)) { 00488 $lines=preg_split('/\r?\n/',$contents); 00490 foreach($lines as $line) { 00491 $availablecomponents[] = explode(',', $line); 00492 } 00494 if (empty($availablecomponents)) { 00495 $this->errorstring='cannotdownloadcomponents'; 00496 return false; 00497 } 00500 $comp_arr = array(); 00501 foreach ($availablecomponents as $component) { 00503 if (empty($component[0])) { 00504 continue; 00505 } 00506 $component[0]=trim($component[0]); 00507 if (!empty($component[1])) { 00508 $component[1]=trim($component[1]); 00509 } 00510 if (!empty($component[2])) { 00511 $component[2]=trim($component[2]); 00512 } 00513 $comp_arr[$component[0]] = $component; 00514 } 00516 $this->cachedmd5components[$source] = $comp_arr; 00517 } else { 00519 $this->errorstring='remotedownloaderror'; 00520 return false; 00521 } 00522 } 00524 if (!empty($this->errorstring)) { 00525 return false; 00526 00527 } else if (empty($comp_arr)) { 00528 $this->errorstring='cannotdownloadcomponents'; 00529 return false; 00530 } 00531 return $comp_arr; 00532 } 00533 00539 function get_error() { 00540 return $this->errorstring; 00541 } 00542 00547 function get_extra_md5_field() { 00548 return $this->extramd5info; 00549 } 00550 00551 } 00552 00553 00567 class lang_installer { 00568 00570 const RESULT_INSTALLED = 'installed'; 00572 const RESULT_UPTODATE = 'uptodate'; 00574 const RESULT_DOWNLOADERROR = 'downloaderror'; 00575 00577 protected $queue = array(); 00579 protected $current; 00581 protected $done = array(); 00583 protected $version; 00584 00591 public function __construct($langcode = '') { 00592 global $CFG; 00593 00594 $this->set_queue($langcode); 00595 $this->version = '2.2'; 00596 00597 if (!empty($CFG->langotherroot) and $CFG->langotherroot !== $CFG->dataroot . '/lang') { 00598 debugging('The in-built language pack installer does not support alternative location ' . 00599 'of languages root directory. You are supposed to install and update your language '. 00600 'packs on your own.'); 00601 } 00602 } 00603 00609 public function set_queue($langcodes) { 00610 if (is_array($langcodes)) { 00611 $this->queue = $langcodes; 00612 } else if (!empty($langcodes)) { 00613 $this->queue = array($langcodes); 00614 } 00615 } 00616 00625 public function run() { 00626 00627 $results = array(); 00628 00629 while ($this->current = array_shift($this->queue)) { 00630 00631 if ($this->was_processed($this->current)) { 00632 // do not repeat yourself 00633 continue; 00634 } 00635 00636 if ($this->current === 'en') { 00637 $this->mark_processed($this->current); 00638 continue; 00639 } 00640 00641 $results[$this->current] = $this->install_language_pack($this->current); 00642 00643 if (in_array($results[$this->current], array(self::RESULT_INSTALLED, self::RESULT_UPTODATE))) { 00644 if ($parentlang = $this->get_parent_language($this->current)) { 00645 if (!$this->is_queued($parentlang) and !$this->was_processed($parentlang)) { 00646 $this->add_to_queue($parentlang); 00647 } 00648 } 00649 } 00650 00651 $this->mark_processed($this->current); 00652 } 00653 00654 return $results; 00655 } 00656 00666 public function lang_pack_url($langcode = '') { 00667 00668 if (empty($langcode)) { 00669 return 'http://download.moodle.org/langpack/'.$this->version.'/'; 00670 } else { 00671 return 'http://download.moodle.org/download.php/langpack/'.$this->version.'/'.$langcode.'.zip'; 00672 } 00673 } 00674 00680 public function get_remote_list_of_languages() { 00681 $source = 'http://download.moodle.org/langpack/' . $this->version . '/languages.md5'; 00682 $availablelangs = array(); 00683 00684 if ($content = download_file_content($source)) { 00685 $alllines = explode("\n", $content); 00686 foreach($alllines as $line) { 00687 if (!empty($line)){ 00688 $availablelangs[] = explode(',', $line); 00689 } 00690 } 00691 return $availablelangs; 00692 00693 } else { 00694 return false; 00695 } 00696 } 00697 00698 // Internal implementation ///////////////////////////////////////////////// 00699 00705 protected function add_to_queue($langcodes) { 00706 if (is_array($langcodes)) { 00707 $this->queue = array_merge($this->queue, $langcodes); 00708 } else if (!empty($langcodes)) { 00709 $this->queue[] = $langcodes; 00710 } 00711 } 00712 00722 protected function is_queued($langcode = '') { 00723 00724 if (empty($langcode)) { 00725 return !empty($this->queue); 00726 00727 } else { 00728 return in_array($langcode, $this->queue); 00729 } 00730 } 00731 00739 protected function was_processed($langcode) { 00740 return isset($this->done[$langcode]); 00741 } 00742 00749 protected function mark_processed($langcode) { 00750 $this->done[$langcode] = 1; 00751 } 00752 00759 protected function get_parent_language($langcode) { 00760 return get_parent_language($langcode); 00761 } 00762 00770 protected function install_language_pack($langcode) { 00771 00772 // initialise new component installer to process this language 00773 $installer = new component_installer('http://download.moodle.org', 'download.php/direct/langpack/' . $this->version, 00774 $langcode . '.zip', 'languages.md5', 'lang'); 00775 00776 if (!$installer->requisitesok) { 00777 throw new lang_installer_exception('installer_requisites_check_failed'); 00778 } 00779 00780 $status = $installer->install(); 00781 00782 if ($status == COMPONENT_ERROR) { 00783 if ($installer->get_error() === 'remotedownloaderror') { 00784 return self::RESULT_DOWNLOADERROR; 00785 } else { 00786 throw new lang_installer_exception($installer->get_error(), $langcode); 00787 } 00788 00789 } else if ($status == COMPONENT_UPTODATE) { 00790 return self::RESULT_UPTODATE; 00791 00792 } else if ($status == COMPONENT_INSTALLED) { 00793 return self::RESULT_INSTALLED; 00794 00795 } else { 00796 throw new lang_installer_exception('unexpected_installer_result', $status); 00797 } 00798 } 00799 } 00800 00801 00808 class lang_installer_exception extends moodle_exception { 00809 00810 public function __construct($errorcode, $debuginfo = null) { 00811 parent::__construct($errorcode, 'error', '', null, $debuginfo); 00812 } 00813 }