[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 /** 3 * PEAR_Registry 4 * 5 * PHP versions 4 and 5 6 * 7 * LICENSE: This source file is subject to version 3.0 of the PHP license 8 * that is available through the world-wide-web at the following URI: 9 * http://www.php.net/license/3_0.txt. If you did not receive a copy of 10 * the PHP License and are unable to obtain it through the web, please 11 * send a note to license@php.net so we can mail you a copy immediately. 12 * 13 * @category pear 14 * @package PEAR 15 * @author Stig Bakken <ssb@php.net> 16 * @author Tomas V. V. Cox <cox@idecnet.com> 17 * @author Greg Beaver <cellog@php.net> 18 * @copyright 1997-2006 The PHP Group 19 * @license http://www.php.net/license/3_0.txt PHP License 3.0 20 * @version CVS: $Id: Registry.php,v 1.159 2006/12/20 19:34:03 cellog Exp $ 21 * @link http://pear.php.net/package/PEAR 22 * @since File available since Release 0.1 23 */ 24 25 /** 26 * for PEAR_Error 27 */ 28 require_once 'PEAR.php'; 29 require_once 'PEAR/DependencyDB.php'; 30 31 define('PEAR_REGISTRY_ERROR_LOCK', -2); 32 define('PEAR_REGISTRY_ERROR_FORMAT', -3); 33 define('PEAR_REGISTRY_ERROR_FILE', -4); 34 define('PEAR_REGISTRY_ERROR_CONFLICT', -5); 35 define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); 36 37 /** 38 * Administration class used to maintain the installed package database. 39 * @category pear 40 * @package PEAR 41 * @author Stig Bakken <ssb@php.net> 42 * @author Tomas V. V. Cox <cox@idecnet.com> 43 * @author Greg Beaver <cellog@php.net> 44 * @copyright 1997-2006 The PHP Group 45 * @license http://www.php.net/license/3_0.txt PHP License 3.0 46 * @version Release: 1.5.0 47 * @link http://pear.php.net/package/PEAR 48 * @since Class available since Release 1.4.0a1 49 */ 50 class PEAR_Registry extends PEAR 51 { 52 // {{{ properties 53 54 /** 55 * File containing all channel information. 56 * @var string 57 */ 58 var $channels = ''; 59 60 /** Directory where registry files are stored. 61 * @var string 62 */ 63 var $statedir = ''; 64 65 /** File where the file map is stored 66 * @var string 67 */ 68 var $filemap = ''; 69 70 /** Directory where registry files for channels are stored. 71 * @var string 72 */ 73 var $channelsdir = ''; 74 75 /** Name of file used for locking the registry 76 * @var string 77 */ 78 var $lockfile = ''; 79 80 /** File descriptor used during locking 81 * @var resource 82 */ 83 var $lock_fp = null; 84 85 /** Mode used during locking 86 * @var int 87 */ 88 var $lock_mode = 0; // XXX UNUSED 89 90 /** Cache of package information. Structure: 91 * array( 92 * 'package' => array('id' => ... ), 93 * ... ) 94 * @var array 95 */ 96 var $pkginfo_cache = array(); 97 98 /** Cache of file map. Structure: 99 * array( '/path/to/file' => 'package', ... ) 100 * @var array 101 */ 102 var $filemap_cache = array(); 103 104 /** 105 * @var false|PEAR_ChannelFile 106 */ 107 var $_pearChannel; 108 109 /** 110 * @var false|PEAR_ChannelFile 111 */ 112 var $_peclChannel; 113 114 /** 115 * @var PEAR_DependencyDB 116 */ 117 var $_dependencyDB; 118 119 /** 120 * @var PEAR_Config 121 */ 122 var $_config; 123 // }}} 124 125 // {{{ constructor 126 127 /** 128 * PEAR_Registry constructor. 129 * 130 * @param string (optional) PEAR install directory (for .php files) 131 * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if 132 * default values are not desired. Only used the very first time a PEAR 133 * repository is initialized 134 * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if 135 * default values are not desired. Only used the very first time a PEAR 136 * repository is initialized 137 * 138 * @access public 139 */ 140 function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, 141 $pecl_channel = false) 142 { 143 parent::PEAR(); 144 $ds = DIRECTORY_SEPARATOR; 145 $this->install_dir = $pear_install_dir; 146 $this->channelsdir = $pear_install_dir.$ds.'.channels'; 147 $this->statedir = $pear_install_dir.$ds.'.registry'; 148 $this->filemap = $pear_install_dir.$ds.'.filemap'; 149 $this->lockfile = $pear_install_dir.$ds.'.lock'; 150 $this->_pearChannel = $pear_channel; 151 $this->_peclChannel = $pecl_channel; 152 $this->_config = false; 153 } 154 155 function hasWriteAccess() 156 { 157 if (!file_exists($this->install_dir)) { 158 $dir = $this->install_dir; 159 while ($dir && $dir != '.') { 160 $dir = dirname($dir); // cd .. 161 if ($dir != '.' && file_exists($dir)) { 162 if (is_writeable($dir)) { 163 return true; 164 } else { 165 return false; 166 } 167 } 168 } 169 return false; 170 } 171 return is_writeable($this->install_dir); 172 } 173 174 function setConfig(&$config) 175 { 176 $this->_config = &$config; 177 } 178 179 function _initializeChannelDirs() 180 { 181 static $running = false; 182 if (!$running) { 183 $running = true; 184 $ds = DIRECTORY_SEPARATOR; 185 if (!is_dir($this->channelsdir) || 186 !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || 187 !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || 188 !file_exists($this->channelsdir . $ds . '__uri.reg')) { 189 if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { 190 $pear_channel = $this->_pearChannel; 191 if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { 192 if (!class_exists('PEAR_ChannelFile')) { 193 require_once 'PEAR/ChannelFile.php'; 194 } 195 $pear_channel = new PEAR_ChannelFile; 196 $pear_channel->setName('pear.php.net'); 197 $pear_channel->setAlias('pear'); 198 $pear_channel->setServer('pear.php.net'); 199 $pear_channel->setSummary('PHP Extension and Application Repository'); 200 $pear_channel->setDefaultPEARProtocols(); 201 $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); 202 $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); 203 } else { 204 $pear_channel->setName('pear.php.net'); 205 $pear_channel->setAlias('pear'); 206 } 207 $pear_channel->validate(); 208 $this->_addChannel($pear_channel); 209 } 210 if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { 211 $pecl_channel = $this->_peclChannel; 212 if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { 213 if (!class_exists('PEAR_ChannelFile')) { 214 require_once 'PEAR/ChannelFile.php'; 215 } 216 $pecl_channel = new PEAR_ChannelFile; 217 $pecl_channel->setName('pecl.php.net'); 218 $pecl_channel->setAlias('pecl'); 219 $pecl_channel->setServer('pecl.php.net'); 220 $pecl_channel->setSummary('PHP Extension Community Library'); 221 $pecl_channel->setDefaultPEARProtocols(); 222 $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); 223 $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); 224 $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); 225 } else { 226 $pecl_channel->setName('pecl.php.net'); 227 $pecl_channel->setAlias('pecl'); 228 } 229 $pecl_channel->validate(); 230 $this->_addChannel($pecl_channel); 231 } 232 if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { 233 if (!class_exists('PEAR_ChannelFile')) { 234 require_once 'PEAR/ChannelFile.php'; 235 } 236 $private = new PEAR_ChannelFile; 237 $private->setName('__uri'); 238 $private->addFunction('xmlrpc', '1.0', '****'); 239 $private->setSummary('Pseudo-channel for static packages'); 240 $this->_addChannel($private); 241 } 242 $this->_rebuildFileMap(); 243 } 244 $running = false; 245 } 246 } 247 248 function _initializeDirs() 249 { 250 $ds = DIRECTORY_SEPARATOR; 251 // XXX Compatibility code should be removed in the future 252 // rename all registry files if any to lowercase 253 if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && 254 $handle = opendir($this->statedir)) { 255 $dest = $this->statedir . $ds; 256 while (false !== ($file = readdir($handle))) { 257 if (preg_match('/^.*[A-Z].*\.reg$/', $file)) { 258 rename($dest . $file, $dest . strtolower($file)); 259 } 260 } 261 closedir($handle); 262 } 263 $this->_initializeChannelDirs(); 264 if (!file_exists($this->filemap)) { 265 $this->_rebuildFileMap(); 266 } 267 $this->_initializeDepDB(); 268 } 269 270 function _initializeDepDB() 271 { 272 if (!isset($this->_dependencyDB)) { 273 static $initializing = false; 274 if (!$initializing) { 275 $initializing = true; 276 if (!$this->_config) { // never used? 277 if (OS_WINDOWS) { 278 $file = 'pear.ini'; 279 } else { 280 $file = '.pearrc'; 281 } 282 $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . 283 $file); 284 $this->_config->setRegistry($this); 285 $this->_config->set('php_dir', $this->install_dir); 286 } 287 $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); 288 if (PEAR::isError($this->_dependencyDB)) { 289 // attempt to recover by removing the dep db 290 if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . 291 DIRECTORY_SEPARATOR . '.depdb')) { 292 @unlink($this->_config->get('php_dir', null, 'pear.php.net') . 293 DIRECTORY_SEPARATOR . '.depdb'); 294 } 295 $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); 296 if (PEAR::isError($this->_dependencyDB)) { 297 echo $this->_dependencyDB->getMessage(); 298 echo 'Unrecoverable error'; 299 exit(1); 300 } 301 } 302 $initializing = false; 303 } 304 } 305 } 306 // }}} 307 // {{{ destructor 308 309 /** 310 * PEAR_Registry destructor. Makes sure no locks are forgotten. 311 * 312 * @access private 313 */ 314 function _PEAR_Registry() 315 { 316 parent::_PEAR(); 317 if (is_resource($this->lock_fp)) { 318 $this->_unlock(); 319 } 320 } 321 322 // }}} 323 324 // {{{ _assertStateDir() 325 326 /** 327 * Make sure the directory where we keep registry files exists. 328 * 329 * @return bool TRUE if directory exists, FALSE if it could not be 330 * created 331 * 332 * @access private 333 */ 334 function _assertStateDir($channel = false) 335 { 336 if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { 337 return $this->_assertChannelStateDir($channel); 338 } 339 static $init = false; 340 if (!file_exists($this->statedir)) { 341 if (!$this->hasWriteAccess()) { 342 return false; 343 } 344 require_once 'System.php'; 345 if (!System::mkdir(array('-p', $this->statedir))) { 346 return $this->raiseError("could not create directory '{$this->statedir}'"); 347 } 348 $init = true; 349 } elseif (!is_dir($this->statedir)) { 350 return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . 351 'it already exists and is not a directory'); 352 } 353 $ds = DIRECTORY_SEPARATOR; 354 if (!file_exists($this->channelsdir)) { 355 if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || 356 !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || 357 !file_exists($this->channelsdir . $ds . '__uri.reg')) { 358 $init = true; 359 } 360 } elseif (!is_dir($this->channelsdir)) { 361 return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . 362 'it already exists and is not a directory'); 363 } 364 if ($init) { 365 static $running = false; 366 if (!$running) { 367 $running = true; 368 $this->_initializeDirs(); 369 $running = false; 370 $init = false; 371 } 372 } else { 373 $this->_initializeDepDB(); 374 } 375 return true; 376 } 377 378 // }}} 379 // {{{ _assertChannelStateDir() 380 381 /** 382 * Make sure the directory where we keep registry files exists for a non-standard channel. 383 * 384 * @param string channel name 385 * @return bool TRUE if directory exists, FALSE if it could not be 386 * created 387 * 388 * @access private 389 */ 390 function _assertChannelStateDir($channel) 391 { 392 $ds = DIRECTORY_SEPARATOR; 393 if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { 394 if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { 395 $this->_initializeChannelDirs(); 396 } 397 return $this->_assertStateDir($channel); 398 } 399 $channelDir = $this->_channelDirectoryName($channel); 400 if (!is_dir($this->channelsdir) || 401 !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { 402 $this->_initializeChannelDirs(); 403 } 404 if (!file_exists($channelDir)) { 405 if (!$this->hasWriteAccess()) { 406 return false; 407 } 408 require_once 'System.php'; 409 if (!System::mkdir(array('-p', $channelDir))) { 410 return $this->raiseError("could not create directory '" . $channelDir . 411 "'"); 412 } 413 } elseif (!is_dir($channelDir)) { 414 return $this->raiseError("could not create directory '" . $channelDir . 415 "', already exists and is not a directory"); 416 } 417 return true; 418 } 419 420 // }}} 421 // {{{ _assertChannelDir() 422 423 /** 424 * Make sure the directory where we keep registry files for channels exists 425 * 426 * @return bool TRUE if directory exists, FALSE if it could not be 427 * created 428 * 429 * @access private 430 */ 431 function _assertChannelDir() 432 { 433 if (!file_exists($this->channelsdir)) { 434 if (!$this->hasWriteAccess()) { 435 return false; 436 } 437 require_once 'System.php'; 438 if (!System::mkdir(array('-p', $this->channelsdir))) { 439 return $this->raiseError("could not create directory '{$this->channelsdir}'"); 440 } 441 } elseif (!is_dir($this->channelsdir)) { 442 return $this->raiseError("could not create directory '{$this->channelsdir}" . 443 "', it already exists and is not a directory"); 444 445 } 446 if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { 447 if (!$this->hasWriteAccess()) { 448 return false; 449 } 450 require_once 'System.php'; 451 if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { 452 return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); 453 } 454 } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { 455 return $this->raiseError("could not create directory '{$this->channelsdir}" . 456 "/.alias', it already exists and is not a directory"); 457 458 } 459 return true; 460 } 461 462 // }}} 463 // {{{ _packageFileName() 464 465 /** 466 * Get the name of the file where data for a given package is stored. 467 * 468 * @param string channel name, or false if this is a PEAR package 469 * @param string package name 470 * 471 * @return string registry file name 472 * 473 * @access public 474 */ 475 function _packageFileName($package, $channel = false) 476 { 477 if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { 478 return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . 479 strtolower($package) . '.reg'; 480 } 481 return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; 482 } 483 484 // }}} 485 // {{{ _channelFileName() 486 487 /** 488 * Get the name of the file where data for a given channel is stored. 489 * @param string channel name 490 * @return string registry file name 491 */ 492 function _channelFileName($channel, $noaliases = false) 493 { 494 if (!$noaliases) { 495 if (file_exists($this->_getChannelAliasFileName($channel))) { 496 $channel = implode('', file($this->_getChannelAliasFileName($channel))); 497 } 498 } 499 return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', 500 strtolower($channel)) . '.reg'; 501 } 502 503 // }}} 504 // {{{ getChannelAliasFileName() 505 506 /** 507 * @param string 508 * @return string 509 */ 510 function _getChannelAliasFileName($alias) 511 { 512 return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . 513 DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; 514 } 515 516 // }}} 517 // {{{ _getChannelFromAlias() 518 519 /** 520 * Get the name of a channel from its alias 521 */ 522 function _getChannelFromAlias($channel) 523 { 524 if (!$this->_channelExists($channel)) { 525 if ($channel == 'pear.php.net') { 526 return 'pear.php.net'; 527 } 528 if ($channel == 'pecl.php.net') { 529 return 'pecl.php.net'; 530 } 531 if ($channel == '__uri') { 532 return '__uri'; 533 } 534 return false; 535 } 536 $channel = strtolower($channel); 537 if (file_exists($this->_getChannelAliasFileName($channel))) { 538 // translate an alias to an actual channel 539 return implode('', file($this->_getChannelAliasFileName($channel))); 540 } else { 541 return $channel; 542 } 543 } 544 // }}} 545 // {{{ _getChannelFromAlias() 546 547 /** 548 * Get the alias of a channel from its alias or its name 549 */ 550 function _getAlias($channel) 551 { 552 if (!$this->_channelExists($channel)) { 553 if ($channel == 'pear.php.net') { 554 return 'pear'; 555 } 556 if ($channel == 'pecl.php.net') { 557 return 'pecl'; 558 } 559 return false; 560 } 561 $channel = $this->_getChannel($channel); 562 if (PEAR::isError($channel)) { 563 return $channel; 564 } 565 return $channel->getAlias(); 566 } 567 // }}} 568 // {{{ _channelDirectoryName() 569 570 /** 571 * Get the name of the file where data for a given package is stored. 572 * 573 * @param string channel name, or false if this is a PEAR package 574 * @param string package name 575 * 576 * @return string registry file name 577 * 578 * @access public 579 */ 580 function _channelDirectoryName($channel) 581 { 582 if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { 583 return $this->statedir; 584 } else { 585 $ch = $this->_getChannelFromAlias($channel); 586 if (!$ch) { 587 $ch = $channel; 588 } 589 return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . 590 str_replace('/', '_', $ch)); 591 } 592 } 593 594 // }}} 595 // {{{ _openPackageFile() 596 597 function _openPackageFile($package, $mode, $channel = false) 598 { 599 if (!$this->_assertStateDir($channel)) { 600 return null; 601 } 602 if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { 603 return null; 604 } 605 $file = $this->_packageFileName($package, $channel); 606 if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { 607 return null; 608 } 609 $fp = @fopen($file, $mode); 610 if (!$fp) { 611 return null; 612 } 613 return $fp; 614 } 615 616 // }}} 617 // {{{ _closePackageFile() 618 619 function _closePackageFile($fp) 620 { 621 fclose($fp); 622 } 623 624 // }}} 625 // {{{ _openChannelFile() 626 627 function _openChannelFile($channel, $mode) 628 { 629 if (!$this->_assertChannelDir()) { 630 return null; 631 } 632 if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { 633 return null; 634 } 635 $file = $this->_channelFileName($channel); 636 if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { 637 return null; 638 } 639 $fp = @fopen($file, $mode); 640 if (!$fp) { 641 return null; 642 } 643 return $fp; 644 } 645 646 // }}} 647 // {{{ _closePackageFile() 648 649 function _closeChannelFile($fp) 650 { 651 fclose($fp); 652 } 653 654 // }}} 655 // {{{ _rebuildFileMap() 656 657 function _rebuildFileMap() 658 { 659 if (!class_exists('PEAR_Installer_Role')) { 660 require_once 'PEAR/Installer/Role.php'; 661 } 662 $channels = $this->_listAllPackages(); 663 $files = array(); 664 foreach ($channels as $channel => $packages) { 665 foreach ($packages as $package) { 666 $version = $this->_packageInfo($package, 'version', $channel); 667 $filelist = $this->_packageInfo($package, 'filelist', $channel); 668 if (!is_array($filelist)) { 669 continue; 670 } 671 foreach ($filelist as $name => $attrs) { 672 if (isset($attrs['attribs'])) { 673 $attrs = $attrs['attribs']; 674 } 675 // it is possible for conflicting packages in different channels to 676 // conflict with data files/doc files 677 if ($name == 'dirtree') { 678 continue; 679 } 680 if (isset($attrs['role']) && !in_array($attrs['role'], 681 PEAR_Installer_Role::getInstallableRoles())) { 682 // these are not installed 683 continue; 684 } 685 if (isset($attrs['role']) && !in_array($attrs['role'], 686 PEAR_Installer_Role::getBaseinstallRoles())) { 687 $attrs['baseinstalldir'] = $package; 688 } 689 if (isset($attrs['baseinstalldir'])) { 690 $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; 691 } else { 692 $file = $name; 693 } 694 $file = preg_replace(',^/+,', '', $file); 695 if ($channel != 'pear.php.net') { 696 $files[$attrs['role']][$file] = array(strtolower($channel), 697 strtolower($package)); 698 } else { 699 if (!is_array($files)) { 700 $file = array(); 701 } 702 if (!isset($files[$attrs['role']])) { 703 $files[$attrs['role']] = array(); 704 } 705 $files[$attrs['role']][$file] = strtolower($package); 706 } 707 } 708 } 709 } 710 $this->_assertStateDir(); 711 if (!$this->hasWriteAccess()) { 712 return false; 713 } 714 $fp = @fopen($this->filemap, 'wb'); 715 if (!$fp) { 716 return false; 717 } 718 $this->filemap_cache = $files; 719 fwrite($fp, serialize($files)); 720 fclose($fp); 721 return true; 722 } 723 724 // }}} 725 // {{{ _readFileMap() 726 727 function _readFileMap() 728 { 729 if (!file_exists($this->filemap)) { 730 return array(); 731 } 732 $fp = @fopen($this->filemap, 'r'); 733 if (!$fp) { 734 return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); 735 } 736 clearstatcache(); 737 $rt = get_magic_quotes_runtime(); 738 set_magic_quotes_runtime(0); 739 $fsize = filesize($this->filemap); 740 fclose($fp); 741 $data = file_get_contents($this->filemap); 742 set_magic_quotes_runtime($rt); 743 $tmp = unserialize($data); 744 if (!$tmp && $fsize > 7) { 745 return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); 746 } 747 $this->filemap_cache = $tmp; 748 return true; 749 } 750 751 // }}} 752 // {{{ _lock() 753 754 /** 755 * Lock the registry. 756 * 757 * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. 758 * See flock manual for more information. 759 * 760 * @return bool TRUE on success, FALSE if locking failed, or a 761 * PEAR error if some other error occurs (such as the 762 * lock file not being writable). 763 * 764 * @access private 765 */ 766 function _lock($mode = LOCK_EX) 767 { 768 if (!eregi('Windows 9', php_uname())) { 769 if ($mode != LOCK_UN && is_resource($this->lock_fp)) { 770 // XXX does not check type of lock (LOCK_SH/LOCK_EX) 771 return true; 772 } 773 if (!$this->_assertStateDir()) { 774 if ($mode == LOCK_EX) { 775 return $this->raiseError('Registry directory is not writeable by the current user'); 776 } else { 777 return true; 778 } 779 } 780 $open_mode = 'w'; 781 // XXX People reported problems with LOCK_SH and 'w' 782 if ($mode === LOCK_SH || $mode === LOCK_UN) { 783 if (!file_exists($this->lockfile)) { 784 touch($this->lockfile); 785 } 786 $open_mode = 'r'; 787 } 788 789 if (!is_resource($this->lock_fp)) { 790 $this->lock_fp = @fopen($this->lockfile, $open_mode); 791 } 792 793 if (!is_resource($this->lock_fp)) { 794 return $this->raiseError("could not create lock file" . 795 (isset($php_errormsg) ? ": " . $php_errormsg : "")); 796 } 797 if (!(int)flock($this->lock_fp, $mode)) { 798 switch ($mode) { 799 case LOCK_SH: $str = 'shared'; break; 800 case LOCK_EX: $str = 'exclusive'; break; 801 case LOCK_UN: $str = 'unlock'; break; 802 default: $str = 'unknown'; break; 803 } 804 return $this->raiseError("could not acquire $str lock ($this->lockfile)", 805 PEAR_REGISTRY_ERROR_LOCK); 806 } 807 } 808 return true; 809 } 810 811 // }}} 812 // {{{ _unlock() 813 814 function _unlock() 815 { 816 $ret = $this->_lock(LOCK_UN); 817 if (is_resource($this->lock_fp)) { 818 fclose($this->lock_fp); 819 } 820 $this->lock_fp = null; 821 return $ret; 822 } 823 824 // }}} 825 // {{{ _packageExists() 826 827 function _packageExists($package, $channel = false) 828 { 829 return file_exists($this->_packageFileName($package, $channel)); 830 } 831 832 // }}} 833 // {{{ _channelExists() 834 835 /** 836 * Determine whether a channel exists in the registry 837 * @param string Channel name 838 * @param bool if true, then aliases will be ignored 839 * @return boolean 840 */ 841 function _channelExists($channel, $noaliases = false) 842 { 843 $a = file_exists($this->_channelFileName($channel, $noaliases)); 844 if (!$a && $channel == 'pear.php.net') { 845 return true; 846 } 847 if (!$a && $channel == 'pecl.php.net') { 848 return true; 849 } 850 return $a; 851 } 852 853 // }}} 854 // {{{ _addChannel() 855 856 /** 857 * @param PEAR_ChannelFile Channel object 858 * @param donotuse 859 * @param string Last-Modified HTTP tag from remote request 860 * @return boolean|PEAR_Error True on creation, false if it already exists 861 */ 862 function _addChannel($channel, $update = false, $lastmodified = false) 863 { 864 if (!is_a($channel, 'PEAR_ChannelFile')) { 865 return false; 866 } 867 if (!$channel->validate()) { 868 return false; 869 } 870 if (file_exists($this->_channelFileName($channel->getName()))) { 871 if (!$update) { 872 return false; 873 } 874 $checker = $this->_getChannel($channel->getName()); 875 if (PEAR::isError($checker)) { 876 return $checker; 877 } 878 if ($channel->getAlias() != $checker->getAlias()) { 879 if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { 880 @unlink($this->_getChannelAliasFileName($checker->getAlias())); 881 } 882 } 883 } else { 884 if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net'))) { 885 return false; 886 } 887 } 888 $ret = $this->_assertChannelDir(); 889 if (PEAR::isError($ret)) { 890 return $ret; 891 } 892 $ret = $this->_assertChannelStateDir($channel->getName()); 893 if (PEAR::isError($ret)) { 894 return $ret; 895 } 896 if ($channel->getAlias() != $channel->getName()) { 897 if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && 898 $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { 899 $channel->setAlias($channel->getName()); 900 } 901 if (!$this->hasWriteAccess()) { 902 return false; 903 } 904 $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); 905 if (!$fp) { 906 return false; 907 } 908 fwrite($fp, $channel->getName()); 909 fclose($fp); 910 } 911 if (!$this->hasWriteAccess()) { 912 return false; 913 } 914 $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); 915 if (!$fp) { 916 return false; 917 } 918 $info = $channel->toArray(); 919 if ($lastmodified) { 920 $info['_lastmodified'] = $lastmodified; 921 } else { 922 $info['_lastmodified'] = date('r'); 923 } 924 fwrite($fp, serialize($info)); 925 fclose($fp); 926 return true; 927 } 928 929 // }}} 930 // {{{ _deleteChannel() 931 932 /** 933 * Deletion fails if there are any packages installed from the channel 934 * @param string|PEAR_ChannelFile channel name 935 * @return boolean|PEAR_Error True on deletion, false if it doesn't exist 936 */ 937 function _deleteChannel($channel) 938 { 939 if (!is_string($channel)) { 940 if (is_a($channel, 'PEAR_ChannelFile')) { 941 if (!$channel->validate()) { 942 return false; 943 } 944 $channel = $channel->getName(); 945 } else { 946 return false; 947 } 948 } 949 if ($this->_getChannelFromAlias($channel) == '__uri') { 950 return false; 951 } 952 if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { 953 return false; 954 } 955 if (!$this->_channelExists($channel)) { 956 return false; 957 } 958 if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { 959 return false; 960 } 961 $channel = $this->_getChannelFromAlias($channel); 962 if ($channel == 'pear.php.net') { 963 return false; 964 } 965 $test = $this->_listChannelPackages($channel); 966 if (count($test)) { 967 return false; 968 } 969 $test = @rmdir($this->_channelDirectoryName($channel)); 970 if (!$test) { 971 return false; 972 } 973 $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); 974 if (file_exists($file)) { 975 $test = @unlink($file); 976 if (!$test) { 977 return false; 978 } 979 } 980 $file = $this->_channelFileName($channel); 981 $ret = true; 982 if (file_exists($file)) { 983 $ret = @unlink($file); 984 } 985 return $ret; 986 } 987 988 // }}} 989 // {{{ _isChannelAlias() 990 991 /** 992 * Determine whether a channel exists in the registry 993 * @param string Channel Alias 994 * @return boolean 995 */ 996 function _isChannelAlias($alias) 997 { 998 return file_exists($this->_getChannelAliasFileName($alias)); 999 } 1000 1001 // }}} 1002 // {{{ _packageInfo() 1003 1004 /** 1005 * @param string|null 1006 * @param string|null 1007 * @param string|null 1008 * @return array|null 1009 * @access private 1010 */ 1011 function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') 1012 { 1013 if ($package === null) { 1014 if ($channel === null) { 1015 $channels = $this->_listChannels(); 1016 $ret = array(); 1017 foreach ($channels as $channel) { 1018 $channel = strtolower($channel); 1019 $ret[$channel] = array(); 1020 $packages = $this->_listPackages($channel); 1021 foreach ($packages as $package) { 1022 $ret[$channel][] = $this->_packageInfo($package, null, $channel); 1023 } 1024 } 1025 return $ret; 1026 } 1027 $ps = $this->_listPackages($channel); 1028 if (!count($ps)) { 1029 return array(); 1030 } 1031 return array_map(array(&$this, '_packageInfo'), 1032 $ps, array_fill(0, count($ps), null), 1033 array_fill(0, count($ps), $channel)); 1034 } 1035 $fp = $this->_openPackageFile($package, 'r', $channel); 1036 if ($fp === null) { 1037 return null; 1038 } 1039 $rt = get_magic_quotes_runtime(); 1040 set_magic_quotes_runtime(0); 1041 clearstatcache(); 1042 $this->_closePackageFile($fp); 1043 $data = file_get_contents($this->_packageFileName($package, $channel)); 1044 set_magic_quotes_runtime($rt); 1045 $data = unserialize($data); 1046 if ($key === null) { 1047 return $data; 1048 } 1049 // compatibility for package.xml version 2.0 1050 if (isset($data['old'][$key])) { 1051 return $data['old'][$key]; 1052 } 1053 if (isset($data[$key])) { 1054 return $data[$key]; 1055 } 1056 return null; 1057 } 1058 1059 // }}} 1060 // {{{ _channelInfo() 1061 1062 /** 1063 * @param string Channel name 1064 * @param bool whether to strictly retrieve info of channels, not just aliases 1065 * @return array|null 1066 */ 1067 function _channelInfo($channel, $noaliases = false) 1068 { 1069 if (!$this->_channelExists($channel, $noaliases)) { 1070 return null; 1071 } 1072 $fp = $this->_openChannelFile($channel, 'r'); 1073 if ($fp === null) { 1074 return null; 1075 } 1076 $rt = get_magic_quotes_runtime(); 1077 set_magic_quotes_runtime(0); 1078 clearstatcache(); 1079 $this->_closeChannelFile($fp); 1080 $data = file_get_contents($this->_channelFileName($channel)); 1081 set_magic_quotes_runtime($rt); 1082 $data = unserialize($data); 1083 return $data; 1084 } 1085 1086 // }}} 1087 // {{{ _listChannels() 1088 1089 function _listChannels() 1090 { 1091 $channellist = array(); 1092 if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { 1093 return array('pear.php.net', 'pecl.php.net', '__uri'); 1094 } 1095 $dp = opendir($this->channelsdir); 1096 while ($ent = readdir($dp)) { 1097 if ($ent{0} == '.' || substr($ent, -4) != '.reg') { 1098 continue; 1099 } 1100 if ($ent == '__uri.reg') { 1101 $channellist[] = '__uri'; 1102 continue; 1103 } 1104 $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); 1105 } 1106 closedir($dp); 1107 if (!in_array('pear.php.net', $channellist)) { 1108 $channellist[] = 'pear.php.net'; 1109 } 1110 if (!in_array('pecl.php.net', $channellist)) { 1111 $channellist[] = 'pecl.php.net'; 1112 } 1113 if (!in_array('__uri', $channellist)) { 1114 $channellist[] = '__uri'; 1115 } 1116 return $channellist; 1117 } 1118 1119 // }}} 1120 // {{{ _listPackages() 1121 1122 function _listPackages($channel = false) 1123 { 1124 if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { 1125 return $this->_listChannelPackages($channel); 1126 } 1127 if (!file_exists($this->statedir) || !is_dir($this->statedir)) { 1128 return array(); 1129 } 1130 $pkglist = array(); 1131 $dp = opendir($this->statedir); 1132 if (!$dp) { 1133 return $pkglist; 1134 } 1135 while ($ent = readdir($dp)) { 1136 if ($ent{0} == '.' || substr($ent, -4) != '.reg') { 1137 continue; 1138 } 1139 $pkglist[] = substr($ent, 0, -4); 1140 } 1141 closedir($dp); 1142 return $pkglist; 1143 } 1144 1145 // }}} 1146 // {{{ _listChannelPackages() 1147 1148 function _listChannelPackages($channel) 1149 { 1150 $pkglist = array(); 1151 if (!file_exists($this->_channelDirectoryName($channel)) || 1152 !is_dir($this->_channelDirectoryName($channel))) { 1153 return array(); 1154 } 1155 $dp = opendir($this->_channelDirectoryName($channel)); 1156 if (!$dp) { 1157 return $pkglist; 1158 } 1159 while ($ent = readdir($dp)) { 1160 if ($ent{0} == '.' || substr($ent, -4) != '.reg') { 1161 continue; 1162 } 1163 $pkglist[] = substr($ent, 0, -4); 1164 } 1165 closedir($dp); 1166 return $pkglist; 1167 } 1168 1169 // }}} 1170 1171 function _listAllPackages() 1172 { 1173 $ret = array(); 1174 foreach ($this->_listChannels() as $channel) { 1175 $ret[$channel] = $this->_listPackages($channel); 1176 } 1177 return $ret; 1178 } 1179 1180 /** 1181 * Add an installed package to the registry 1182 * @param string package name 1183 * @param array package info (parsed by PEAR_Common::infoFrom*() methods) 1184 * @return bool success of saving 1185 * @access private 1186 */ 1187 function _addPackage($package, $info) 1188 { 1189 if ($this->_packageExists($package)) { 1190 return false; 1191 } 1192 $fp = $this->_openPackageFile($package, 'wb'); 1193 if ($fp === null) { 1194 return false; 1195 } 1196 $info['_lastmodified'] = time(); 1197 fwrite($fp, serialize($info)); 1198 $this->_closePackageFile($fp); 1199 if (isset($info['filelist'])) { 1200 $this->_rebuildFileMap(); 1201 } 1202 return true; 1203 } 1204 1205 /** 1206 * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 1207 * @return bool 1208 * @access private 1209 */ 1210 function _addPackage2($info) 1211 { 1212 if (!$info->validate()) { 1213 if (class_exists('PEAR_Common')) { 1214 $ui = PEAR_Frontend::singleton(); 1215 if ($ui) { 1216 foreach ($info->getValidationWarnings() as $err) { 1217 $ui->log($err['message'], true); 1218 } 1219 } 1220 } 1221 return false; 1222 } 1223 $channel = $info->getChannel(); 1224 $package = $info->getPackage(); 1225 $save = $info; 1226 if ($this->_packageExists($package, $channel)) { 1227 return false; 1228 } 1229 if (!$this->_channelExists($channel, true)) { 1230 return false; 1231 } 1232 $info = $info->toArray(true); 1233 if (!$info) { 1234 return false; 1235 } 1236 $fp = $this->_openPackageFile($package, 'wb', $channel); 1237 if ($fp === null) { 1238 return false; 1239 } 1240 $info['_lastmodified'] = time(); 1241 fwrite($fp, serialize($info)); 1242 $this->_closePackageFile($fp); 1243 $this->_rebuildFileMap(); 1244 return true; 1245 } 1246 1247 /** 1248 * @param string Package name 1249 * @param array parsed package.xml 1.0 1250 * @param bool this parameter is only here for BC. Don't use it. 1251 * @access private 1252 */ 1253 function _updatePackage($package, $info, $merge = true) 1254 { 1255 $oldinfo = $this->_packageInfo($package); 1256 if (empty($oldinfo)) { 1257 return false; 1258 } 1259 $fp = $this->_openPackageFile($package, 'w'); 1260 if ($fp === null) { 1261 return false; 1262 } 1263 if (is_object($info)) { 1264 $info = $info->toArray(); 1265 } 1266 $info['_lastmodified'] = time(); 1267 $newinfo = $info; 1268 if ($merge) { 1269 $info = array_merge($oldinfo, $info); 1270 } else { 1271 $diff = $info; 1272 } 1273 fwrite($fp, serialize($info)); 1274 $this->_closePackageFile($fp); 1275 if (isset($newinfo['filelist'])) { 1276 $this->_rebuildFileMap(); 1277 } 1278 return true; 1279 } 1280 1281 /** 1282 * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 1283 * @return bool 1284 * @access private 1285 */ 1286 function _updatePackage2($info) 1287 { 1288 if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { 1289 return false; 1290 } 1291 $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); 1292 if ($fp === null) { 1293 return false; 1294 } 1295 $save = $info; 1296 $info = $save->getArray(true); 1297 $info['_lastmodified'] = time(); 1298 fwrite($fp, serialize($info)); 1299 $this->_closePackageFile($fp); 1300 $this->_rebuildFileMap(); 1301 return true; 1302 } 1303 1304 /** 1305 * @param string Package name 1306 * @param string Channel name 1307 * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null 1308 * @access private 1309 */ 1310 function &_getPackage($package, $channel = 'pear.php.net') 1311 { 1312 $info = $this->_packageInfo($package, null, $channel); 1313 if ($info === null) { 1314 return $info; 1315 } 1316 $a = $this->_config; 1317 if (!$a) { 1318 $this->_config = &new PEAR_Config; 1319 $this->_config->set('php_dir', $this->statedir); 1320 } 1321 if (!class_exists('PEAR_PackageFile')) { 1322 require_once 'PEAR/PackageFile.php'; 1323 } 1324 $pkg = &new PEAR_PackageFile($this->_config); 1325 $pf = &$pkg->fromArray($info); 1326 return $pf; 1327 } 1328 1329 /** 1330 * @param string channel name 1331 * @param bool whether to strictly retrieve channel names 1332 * @return PEAR_ChannelFile|PEAR_Error 1333 * @access private 1334 */ 1335 function &_getChannel($channel, $noaliases = false) 1336 { 1337 $ch = false; 1338 if ($this->_channelExists($channel, $noaliases)) { 1339 $chinfo = $this->_channelInfo($channel, $noaliases); 1340 if ($chinfo) { 1341 if (!class_exists('PEAR_ChannelFile')) { 1342 require_once 'PEAR/ChannelFile.php'; 1343 } 1344 $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); 1345 } 1346 } 1347 if ($ch) { 1348 if ($ch->validate()) { 1349 return $ch; 1350 } 1351 foreach ($ch->getErrors(true) as $err) { 1352 $message = $err['message'] . "\n"; 1353 } 1354 $ch = PEAR::raiseError($message); 1355 return $ch; 1356 } 1357 if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { 1358 // the registry is not properly set up, so use defaults 1359 if (!class_exists('PEAR_ChannelFile')) { 1360 require_once 'PEAR/ChannelFile.php'; 1361 } 1362 $pear_channel = new PEAR_ChannelFile; 1363 $pear_channel->setName('pear.php.net'); 1364 $pear_channel->setAlias('pear'); 1365 $pear_channel->setSummary('PHP Extension and Application Repository'); 1366 $pear_channel->setDefaultPEARProtocols(); 1367 $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); 1368 $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); 1369 return $pear_channel; 1370 } 1371 if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { 1372 // the registry is not properly set up, so use defaults 1373 if (!class_exists('PEAR_ChannelFile')) { 1374 require_once 'PEAR/ChannelFile.php'; 1375 } 1376 $pear_channel = new PEAR_ChannelFile; 1377 $pear_channel->setName('pecl.php.net'); 1378 $pear_channel->setAlias('pecl'); 1379 $pear_channel->setSummary('PHP Extension Community Library'); 1380 $pear_channel->setDefaultPEARProtocols(); 1381 $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); 1382 $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); 1383 $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); 1384 return $pear_channel; 1385 } 1386 if ($this->_getChannelFromAlias($channel) == '__uri') { 1387 // the registry is not properly set up, so use defaults 1388 if (!class_exists('PEAR_ChannelFile')) { 1389 require_once 'PEAR/ChannelFile.php'; 1390 } 1391 $private = new PEAR_ChannelFile; 1392 $private->setName('__uri'); 1393 $private->addFunction('xmlrpc', '1.0', '****'); 1394 $private->setSummary('Pseudo-channel for static packages'); 1395 return $private; 1396 } 1397 return $ch; 1398 } 1399 1400 // {{{ packageExists() 1401 1402 /** 1403 * @param string Package name 1404 * @param string Channel name 1405 * @return bool 1406 */ 1407 function packageExists($package, $channel = 'pear.php.net') 1408 { 1409 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1410 return $e; 1411 } 1412 $ret = $this->_packageExists($package, $channel); 1413 $this->_unlock(); 1414 return $ret; 1415 } 1416 1417 // }}} 1418 1419 // {{{ channelExists() 1420 1421 /** 1422 * @param string channel name 1423 * @param bool if true, then aliases will be ignored 1424 * @return bool 1425 */ 1426 function channelExists($channel, $noaliases = false) 1427 { 1428 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1429 return $e; 1430 } 1431 $ret = $this->_channelExists($channel, $noaliases); 1432 $this->_unlock(); 1433 return $ret; 1434 } 1435 1436 // }}} 1437 1438 // {{{ isAlias() 1439 1440 /** 1441 * Determines whether the parameter is an alias of a channel 1442 * @param string 1443 * @return bool 1444 */ 1445 function isAlias($alias) 1446 { 1447 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1448 return $e; 1449 } 1450 $ret = $this->_isChannelAlias($alias); 1451 $this->_unlock(); 1452 return $ret; 1453 } 1454 1455 // }}} 1456 // {{{ packageInfo() 1457 1458 /** 1459 * @param string|null 1460 * @param string|null 1461 * @param string 1462 * @return array|null 1463 */ 1464 function packageInfo($package = null, $key = null, $channel = 'pear.php.net') 1465 { 1466 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1467 return $e; 1468 } 1469 $ret = $this->_packageInfo($package, $key, $channel); 1470 $this->_unlock(); 1471 return $ret; 1472 } 1473 1474 // }}} 1475 // {{{ channelInfo() 1476 1477 /** 1478 * Retrieve a raw array of channel data. 1479 * 1480 * Do not use this, instead use {@link getChannel()} for normal 1481 * operations. Array structure is undefined in this method 1482 * @param string channel name 1483 * @param bool whether to strictly retrieve information only on non-aliases 1484 * @return array|null|PEAR_Error 1485 */ 1486 function channelInfo($channel = null, $noaliases = false) 1487 { 1488 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1489 return $e; 1490 } 1491 $ret = $this->_channelInfo($channel, $noaliases); 1492 $this->_unlock(); 1493 return $ret; 1494 } 1495 1496 // }}} 1497 1498 /** 1499 * @param string 1500 */ 1501 function channelName($channel) 1502 { 1503 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1504 return $e; 1505 } 1506 $ret = $this->_getChannelFromAlias($channel); 1507 $this->_unlock(); 1508 return $ret; 1509 } 1510 1511 /** 1512 * @param string 1513 */ 1514 function channelAlias($channel) 1515 { 1516 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1517 return $e; 1518 } 1519 $ret = $this->_getAlias($channel); 1520 $this->_unlock(); 1521 return $ret; 1522 } 1523 // {{{ listPackages() 1524 1525 function listPackages($channel = false) 1526 { 1527 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1528 return $e; 1529 } 1530 $ret = $this->_listPackages($channel); 1531 $this->_unlock(); 1532 return $ret; 1533 } 1534 1535 // }}} 1536 // {{{ listAllPackages() 1537 1538 function listAllPackages() 1539 { 1540 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1541 return $e; 1542 } 1543 $ret = $this->_listAllPackages(); 1544 $this->_unlock(); 1545 return $ret; 1546 } 1547 1548 // }}} 1549 // {{{ listChannel() 1550 1551 function listChannels() 1552 { 1553 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1554 return $e; 1555 } 1556 $ret = $this->_listChannels(); 1557 $this->_unlock(); 1558 return $ret; 1559 } 1560 1561 // }}} 1562 // {{{ addPackage() 1563 1564 /** 1565 * Add an installed package to the registry 1566 * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object 1567 * that will be passed to {@link addPackage2()} 1568 * @param array package info (parsed by PEAR_Common::infoFrom*() methods) 1569 * @return bool success of saving 1570 */ 1571 function addPackage($package, $info) 1572 { 1573 if (is_object($info)) { 1574 return $this->addPackage2($info); 1575 } 1576 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1577 return $e; 1578 } 1579 $ret = $this->_addPackage($package, $info); 1580 $this->_unlock(); 1581 if ($ret) { 1582 if (!class_exists('PEAR_PackageFile_v1')) { 1583 require_once 'PEAR/PackageFile/v1.php'; 1584 } 1585 $pf = new PEAR_PackageFile_v1; 1586 $pf->setConfig($this->_config); 1587 $pf->fromArray($info); 1588 $this->_dependencyDB->uninstallPackage($pf); 1589 $this->_dependencyDB->installPackage($pf); 1590 } 1591 return $ret; 1592 } 1593 1594 // }}} 1595 // {{{ addPackage2() 1596 1597 function addPackage2($info) 1598 { 1599 if (!is_object($info)) { 1600 return $this->addPackage($info['package'], $info); 1601 } 1602 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1603 return $e; 1604 } 1605 $ret = $this->_addPackage2($info); 1606 $this->_unlock(); 1607 if ($ret) { 1608 $this->_dependencyDB->uninstallPackage($info); 1609 $this->_dependencyDB->installPackage($info); 1610 } 1611 return $ret; 1612 } 1613 1614 // }}} 1615 // {{{ updateChannel() 1616 1617 /** 1618 * For future expandibility purposes, separate this 1619 * @param PEAR_ChannelFile 1620 */ 1621 function updateChannel($channel, $lastmodified = null) 1622 { 1623 if ($channel->getName() == '__uri') { 1624 return false; 1625 } 1626 return $this->addChannel($channel, $lastmodified, true); 1627 } 1628 1629 // }}} 1630 // {{{ deleteChannel() 1631 1632 /** 1633 * Deletion fails if there are any packages installed from the channel 1634 * @param string|PEAR_ChannelFile channel name 1635 * @return boolean|PEAR_Error True on deletion, false if it doesn't exist 1636 */ 1637 function deleteChannel($channel) 1638 { 1639 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1640 return $e; 1641 } 1642 $ret = $this->_deleteChannel($channel); 1643 $this->_unlock(); 1644 if ($ret && is_a($this->_config, 'PEAR_Config')) { 1645 $this->_config->setChannels($this->listChannels()); 1646 } 1647 return $ret; 1648 } 1649 1650 // }}} 1651 // {{{ addChannel() 1652 1653 /** 1654 * @param PEAR_ChannelFile Channel object 1655 * @param string Last-Modified header from HTTP for caching 1656 * @return boolean|PEAR_Error True on creation, false if it already exists 1657 */ 1658 function addChannel($channel, $lastmodified = false, $update = false) 1659 { 1660 if (!is_a($channel, 'PEAR_ChannelFile')) { 1661 return false; 1662 } 1663 if (!$channel->validate()) { 1664 return false; 1665 } 1666 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1667 return $e; 1668 } 1669 $ret = $this->_addChannel($channel, $update, $lastmodified); 1670 $this->_unlock(); 1671 if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { 1672 $this->_config->setChannels($this->listChannels()); 1673 } 1674 return $ret; 1675 } 1676 1677 // }}} 1678 // {{{ deletePackage() 1679 1680 function deletePackage($package, $channel = 'pear.php.net') 1681 { 1682 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1683 return $e; 1684 } 1685 $file = $this->_packageFileName($package, $channel); 1686 if (file_exists($file)) { 1687 $ret = @unlink($file); 1688 } else { 1689 $ret = false; 1690 } 1691 $this->_rebuildFileMap(); 1692 $this->_unlock(); 1693 $p = array('channel' => $channel, 'package' => $package); 1694 $this->_dependencyDB->uninstallPackage($p); 1695 return $ret; 1696 } 1697 1698 // }}} 1699 // {{{ updatePackage() 1700 1701 function updatePackage($package, $info, $merge = true) 1702 { 1703 if (is_object($info)) { 1704 return $this->updatePackage2($info, $merge); 1705 } 1706 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1707 return $e; 1708 } 1709 $ret = $this->_updatePackage($package, $info, $merge); 1710 $this->_unlock(); 1711 if ($ret) { 1712 if (!class_exists('PEAR_PackageFile_v1')) { 1713 require_once 'PEAR/PackageFile/v1.php'; 1714 } 1715 $pf = new PEAR_PackageFile_v1; 1716 $pf->setConfig($this->_config); 1717 $pf->fromArray($this->packageInfo($package)); 1718 $this->_dependencyDB->uninstallPackage($pf); 1719 $this->_dependencyDB->installPackage($pf); 1720 } 1721 return $ret; 1722 } 1723 1724 // }}} 1725 // {{{ updatePackage2() 1726 1727 function updatePackage2($info) 1728 { 1729 if (!is_object($info)) { 1730 return $this->updatePackage($info['package'], $info, $merge); 1731 } 1732 if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { 1733 return false; 1734 } 1735 if (PEAR::isError($e = $this->_lock(LOCK_EX))) { 1736 return $e; 1737 } 1738 $ret = $this->_updatePackage2($info); 1739 $this->_unlock(); 1740 if ($ret) { 1741 $this->_dependencyDB->uninstallPackage($info); 1742 $this->_dependencyDB->installPackage($info); 1743 } 1744 return $ret; 1745 } 1746 1747 // }}} 1748 // {{{ getChannel() 1749 /** 1750 * @param string channel name 1751 * @param bool whether to strictly return raw channels (no aliases) 1752 * @return PEAR_ChannelFile|PEAR_Error 1753 */ 1754 function &getChannel($channel, $noaliases = false) 1755 { 1756 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1757 return $e; 1758 } 1759 $ret = &$this->_getChannel($channel, $noaliases); 1760 if (!$ret) { 1761 return PEAR::raiseError('Unknown channel: ' . $channel); 1762 } 1763 $this->_unlock(); 1764 return $ret; 1765 } 1766 1767 // }}} 1768 // {{{ getPackage() 1769 /** 1770 * @param string package name 1771 * @param string channel name 1772 * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null 1773 */ 1774 function &getPackage($package, $channel = 'pear.php.net') 1775 { 1776 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1777 return $e; 1778 } 1779 $pf = &$this->_getPackage($package, $channel); 1780 $this->_unlock(); 1781 return $pf; 1782 } 1783 1784 // }}} 1785 1786 /** 1787 * Get PEAR_PackageFile_v[1/2] objects representing the contents of 1788 * a dependency group that are installed. 1789 * 1790 * This is used at uninstall-time 1791 * @param array 1792 * @return array|false 1793 */ 1794 function getInstalledGroup($group) 1795 { 1796 $ret = array(); 1797 if (isset($group['package'])) { 1798 if (!isset($group['package'][0])) { 1799 $group['package'] = array($group['package']); 1800 } 1801 foreach ($group['package'] as $package) { 1802 $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; 1803 $p = &$this->getPackage($package['name'], $depchannel); 1804 if ($p) { 1805 $save = &$p; 1806 $ret[] = &$save; 1807 } 1808 } 1809 } 1810 if (isset($group['subpackage'])) { 1811 if (!isset($group['subpackage'][0])) { 1812 $group['subpackage'] = array($group['subpackage']); 1813 } 1814 foreach ($group['subpackage'] as $package) { 1815 $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; 1816 $p = &$this->getPackage($package['name'], $depchannel); 1817 if ($p) { 1818 $save = &$p; 1819 $ret[] = &$save; 1820 } 1821 } 1822 } 1823 if (!count($ret)) { 1824 return false; 1825 } 1826 return $ret; 1827 } 1828 1829 // {{{ getChannelValidator() 1830 /** 1831 * @param string channel name 1832 * @return PEAR_Validate|false 1833 */ 1834 function &getChannelValidator($channel) 1835 { 1836 $chan = $this->getChannel($channel); 1837 if (PEAR::isError($chan)) { 1838 return $chan; 1839 } 1840 $val = $chan->getValidationObject(); 1841 return $val; 1842 } 1843 // }}} 1844 // {{{ getChannels() 1845 /** 1846 * @param string channel name 1847 * @return array an array of PEAR_ChannelFile objects representing every installed channel 1848 */ 1849 function &getChannels() 1850 { 1851 $ret = array(); 1852 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1853 return $e; 1854 } 1855 foreach ($this->_listChannels() as $channel) { 1856 $e = &$this->_getChannel($channel); 1857 if (!$e || PEAR::isError($e)) { 1858 continue; 1859 } 1860 $ret[] = $e; 1861 } 1862 $this->_unlock(); 1863 return $ret; 1864 } 1865 1866 // }}} 1867 // {{{ checkFileMap() 1868 1869 /** 1870 * Test whether a file or set of files belongs to a package. 1871 * 1872 * If an array is passed in 1873 * @param string|array file path, absolute or relative to the pear 1874 * install dir 1875 * @param string|array name of PEAR package or array('package' => name, 'channel' => 1876 * channel) of a package that will be ignored 1877 * @param string API version - 1.1 will exclude any files belonging to a package 1878 * @param array private recursion variable 1879 * @return array|false which package and channel the file belongs to, or an empty 1880 * string if the file does not belong to an installed package, 1881 * or belongs to the second parameter's package 1882 */ 1883 function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) 1884 { 1885 if (is_array($path)) { 1886 static $notempty; 1887 if (empty($notempty)) { 1888 if (!class_exists('PEAR_Installer_Role')) { 1889 require_once 'PEAR/Installer/Role.php'; 1890 } 1891 $notempty = create_function('$a','return !empty($a);'); 1892 } 1893 $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) 1894 : strtolower($package); 1895 $pkgs = array(); 1896 foreach ($path as $name => $attrs) { 1897 if (is_array($attrs)) { 1898 if (isset($attrs['install-as'])) { 1899 $name = $attrs['install-as']; 1900 } 1901 if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { 1902 // these are not installed 1903 continue; 1904 } 1905 if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { 1906 $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; 1907 } 1908 if (isset($attrs['baseinstalldir'])) { 1909 $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; 1910 } 1911 } 1912 $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); 1913 if (PEAR::isError($pkgs[$name])) { 1914 return $pkgs[$name]; 1915 } 1916 } 1917 return array_filter($pkgs, $notempty); 1918 } 1919 if (empty($this->filemap_cache)) { 1920 if (PEAR::isError($e = $this->_lock(LOCK_SH))) { 1921 return $e; 1922 } 1923 $err = $this->_readFileMap(); 1924 $this->_unlock(); 1925 if (PEAR::isError($err)) { 1926 return $err; 1927 } 1928 } 1929 if (!$attrs) { 1930 $attrs = array('role' => 'php'); // any old call would be for PHP role only 1931 } 1932 if (isset($this->filemap_cache[$attrs['role']][$path])) { 1933 if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { 1934 return false; 1935 } 1936 return $this->filemap_cache[$attrs['role']][$path]; 1937 } 1938 $l = strlen($this->install_dir); 1939 if (substr($path, 0, $l) == $this->install_dir) { 1940 $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); 1941 } 1942 if (isset($this->filemap_cache[$attrs['role']][$path])) { 1943 if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { 1944 return false; 1945 } 1946 return $this->filemap_cache[$attrs['role']][$path]; 1947 } 1948 return false; 1949 } 1950 1951 // }}} 1952 // {{{ flush() 1953 /** 1954 * Force a reload of the filemap 1955 * @since 1.5.0RC3 1956 */ 1957 function flushFileMap() 1958 { 1959 $this->filemap_cache = null; 1960 clearstatcache(); // ensure that the next read gets the full, current filemap 1961 } 1962 1963 // }}} 1964 // {{{ apiVersion() 1965 /** 1966 * Get the expected API version. Channels API is version 1.1, as it is backwards 1967 * compatible with 1.0 1968 * @return string 1969 */ 1970 function apiVersion() 1971 { 1972 return '1.1'; 1973 } 1974 // }}} 1975 1976 1977 /** 1978 * Parse a package name, or validate a parsed package name array 1979 * @param string|array pass in an array of format 1980 * array( 1981 * 'package' => 'pname', 1982 * ['channel' => 'channame',] 1983 * ['version' => 'version',] 1984 * ['state' => 'state',] 1985 * ['group' => 'groupname']) 1986 * or a string of format 1987 * [channel://][channame/]pname[-version|-state][/group=groupname] 1988 * @return array|PEAR_Error 1989 */ 1990 function parsePackageName($param, $defaultchannel = 'pear.php.net') 1991 { 1992 $saveparam = $param; 1993 if (is_array($param)) { 1994 // convert to string for error messages 1995 $saveparam = $this->parsedPackageNameToString($param); 1996 // process the array 1997 if (!isset($param['package'])) { 1998 return PEAR::raiseError('parsePackageName(): array $param ' . 1999 'must contain a valid package name in index "param"', 2000 'package', null, null, $param); 2001 } 2002 if (!isset($param['uri'])) { 2003 if (!isset($param['channel'])) { 2004 $param['channel'] = $defaultchannel; 2005 } 2006 } else { 2007 $param['channel'] = '__uri'; 2008 } 2009 } else { 2010 $components = @parse_url((string) $param); 2011 if (isset($components['scheme'])) { 2012 if ($components['scheme'] == 'http') { 2013 // uri package 2014 $param = array('uri' => $param, 'channel' => '__uri'); 2015 } elseif($components['scheme'] != 'channel') { 2016 return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . 2017 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); 2018 } 2019 } 2020 if (!isset($components['path'])) { 2021 return PEAR::raiseError('parsePackageName(): array $param ' . 2022 'must contain a valid package name in "' . $param . '"', 2023 'package', null, null, $param); 2024 } 2025 if (isset($components['host'])) { 2026 // remove the leading "/" 2027 $components['path'] = substr($components['path'], 1); 2028 } 2029 if (!isset($components['scheme'])) { 2030 if (strpos($components['path'], '/') !== false) { 2031 if ($components['path']{0} == '/') { 2032 return PEAR::raiseError('parsePackageName(): this is not ' . 2033 'a package name, it begins with "/" in "' . $param . '"', 2034 'invalid', null, null, $param); 2035 } 2036 $parts = explode('/', $components['path']); 2037 $components['host'] = array_shift($parts); 2038 if (count($parts) > 1) { 2039 $components['path'] = array_pop($parts); 2040 $components['host'] .= '/' . implode('/', $parts); 2041 } else { 2042 $components['path'] = implode('/', $parts); 2043 } 2044 } else { 2045 $components['host'] = $defaultchannel; 2046 } 2047 } else { 2048 if (strpos($components['path'], '/')) { 2049 $parts = explode('/', $components['path']); 2050 $components['path'] = array_pop($parts); 2051 $components['host'] .= '/' . implode('/', $parts); 2052 } 2053 } 2054 2055 if (is_array($param)) { 2056 $param['package'] = $components['path']; 2057 } else { 2058 $param = array( 2059 'package' => $components['path'] 2060 ); 2061 if (isset($components['host'])) { 2062 $param['channel'] = $components['host']; 2063 } 2064 } 2065 if (isset($components['fragment'])) { 2066 $param['group'] = $components['fragment']; 2067 } 2068 if (isset($components['user'])) { 2069 $param['user'] = $components['user']; 2070 } 2071 if (isset($components['pass'])) { 2072 $param['pass'] = $components['pass']; 2073 } 2074 if (isset($components['query'])) { 2075 parse_str($components['query'], $param['opts']); 2076 } 2077 // check for extension 2078 $pathinfo = pathinfo($param['package']); 2079 if (isset($pathinfo['extension']) && 2080 in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { 2081 $param['extension'] = $pathinfo['extension']; 2082 $param['package'] = substr($pathinfo['basename'], 0, 2083 strlen($pathinfo['basename']) - 4); 2084 } 2085 // check for version 2086 if (strpos($param['package'], '-')) { 2087 $test = explode('-', $param['package']); 2088 if (count($test) != 2) { 2089 return PEAR::raiseError('parsePackageName(): only one version/state ' . 2090 'delimiter "-" is allowed in "' . $saveparam . '"', 2091 'version', null, null, $param); 2092 } 2093 list($param['package'], $param['version']) = $test; 2094 } 2095 } 2096 // validation 2097 $info = $this->channelExists($param['channel']); 2098 if (PEAR::isError($info)) { 2099 return $info; 2100 } 2101 if (!$info) { 2102 return PEAR::raiseError('unknown channel "' . $param['channel'] . 2103 '" in "' . $saveparam . '"', 'channel', null, null, $param); 2104 } 2105 $chan = $this->getChannel($param['channel']); 2106 if (PEAR::isError($chan)) { 2107 return $chan; 2108 } 2109 if (!$chan) { 2110 return PEAR::raiseError("Exception: corrupt registry, could not " . 2111 "retrieve channel " . $param['channel'] . " information", 2112 'registry', null, null, $param); 2113 } 2114 $param['channel'] = $chan->getName(); 2115 $validate = $chan->getValidationObject(); 2116 $vpackage = $chan->getValidationPackage(); 2117 // validate package name 2118 if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { 2119 return PEAR::raiseError('parsePackageName(): invalid package name "' . 2120 $param['package'] . '" in "' . $saveparam . '"', 2121 'package', null, null, $param); 2122 } 2123 if (isset($param['group'])) { 2124 if (!PEAR_Validate::validGroupName($param['group'])) { 2125 return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . 2126 '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, 2127 $param); 2128 } 2129 } 2130 if (isset($param['state'])) { 2131 if (!in_array(strtolower($param['state']), $validate->getValidStates())) { 2132 return PEAR::raiseError('parsePackageName(): state "' . $param['state'] 2133 . '" is not a valid state in "' . $saveparam . '"', 2134 'state', null, null, $param); 2135 } 2136 } 2137 if (isset($param['version'])) { 2138 if (isset($param['state'])) { 2139 return PEAR::raiseError('parsePackageName(): cannot contain both ' . 2140 'a version and a stability (state) in "' . $saveparam . '"', 2141 'version/state', null, null, $param); 2142 } 2143 // check whether version is actually a state 2144 if (in_array(strtolower($param['version']), $validate->getValidStates())) { 2145 $param['state'] = strtolower($param['version']); 2146 unset($param['version']); 2147 } else { 2148 if (!$validate->validVersion($param['version'])) { 2149 return PEAR::raiseError('parsePackageName(): "' . $param['version'] . 2150 '" is neither a valid version nor a valid state in "' . 2151 $saveparam . '"', 'version/state', null, null, $param); 2152 } 2153 } 2154 } 2155 return $param; 2156 } 2157 2158 /** 2159 * @param array 2160 * @return string 2161 */ 2162 function parsedPackageNameToString($parsed, $brief = false) 2163 { 2164 if (is_string($parsed)) { 2165 return $parsed; 2166 } 2167 if (is_object($parsed)) { 2168 $p = $parsed; 2169 $parsed = array( 2170 'package' => $p->getPackage(), 2171 'channel' => $p->getChannel(), 2172 'version' => $p->getVersion(), 2173 ); 2174 } 2175 if (isset($parsed['uri'])) { 2176 return $parsed['uri']; 2177 } 2178 if ($brief) { 2179 if ($channel = $this->channelAlias($parsed['channel'])) { 2180 return $channel . '/' . $parsed['package']; 2181 } 2182 } 2183 $upass = ''; 2184 if (isset($parsed['user'])) { 2185 $upass = $parsed['user']; 2186 if (isset($parsed['pass'])) { 2187 $upass .= ':' . $parsed['pass']; 2188 } 2189 $upass = "$upass@"; 2190 } 2191 $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; 2192 if (isset($parsed['version']) || isset($parsed['state'])) { 2193 $ver = isset($parsed['version']) ? $parsed['version'] : ''; 2194 $ver .= isset($parsed['state']) ? $parsed['state'] : ''; 2195 $ret .= '-' . $ver; 2196 } 2197 if (isset($parsed['extension'])) { 2198 $ret .= '.' . $parsed['extension']; 2199 } 2200 if (isset($parsed['opts'])) { 2201 $ret .= '?'; 2202 foreach ($parsed['opts'] as $name => $value) { 2203 $parsed['opts'][$name] = "$name=$value"; 2204 } 2205 $ret .= implode('&', $parsed['opts']); 2206 } 2207 if (isset($parsed['group'])) { 2208 $ret .= '#' . $parsed['group']; 2209 } 2210 return $ret; 2211 } 2212 } 2213 2214 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |