1<?php 2/** 3 * PEAR_Config, customized configuration handling for the PEAR Installer 4 * 5 * PHP versions 4 and 5 6 * 7 * @category pear 8 * @package PEAR 9 * @author Stig Bakken <ssb@php.net> 10 * @author Greg Beaver <cellog@php.net> 11 * @copyright 1997-2009 The Authors 12 * @license http://opensource.org/licenses/bsd-license.php New BSD License 13 * @link http://pear.php.net/package/PEAR 14 * @since File available since Release 0.1 15 */ 16 17/** 18 * Required for error handling 19 */ 20require_once 'PEAR.php'; 21require_once 'PEAR/Registry.php'; 22require_once 'PEAR/Installer/Role.php'; 23require_once 'System.php'; 24 25/** 26 * Last created PEAR_Config instance. 27 * @var object 28 */ 29$GLOBALS['_PEAR_Config_instance'] = null; 30if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { 31 $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; 32} else { 33 $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; 34} 35 36// Below we define constants with default values for all configuration 37// parameters except username/password. All of them can have their 38// defaults set through environment variables. The reason we use the 39// PHP_ prefix is for some security, PHP protects environment 40// variables starting with PHP_*. 41 42// default channel and preferred mirror is based on whether we are invoked through 43// the "pear" or the "pecl" command 44if (!defined('PEAR_RUNTYPE')) { 45 define('PEAR_RUNTYPE', 'pear'); 46} 47 48if (PEAR_RUNTYPE == 'pear') { 49 define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); 50} else { 51 define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); 52} 53 54if (getenv('PHP_PEAR_SYSCONF_DIR')) { 55 define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); 56} elseif (getenv('SystemRoot')) { 57 define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); 58} else { 59 define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); 60} 61 62// Default for master_server 63if (getenv('PHP_PEAR_MASTER_SERVER')) { 64 define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); 65} else { 66 define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); 67} 68 69// Default for http_proxy 70if (getenv('PHP_PEAR_HTTP_PROXY')) { 71 define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); 72} elseif (getenv('http_proxy')) { 73 define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); 74} else { 75 define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); 76} 77 78// Default for php_dir 79if (getenv('PHP_PEAR_INSTALL_DIR')) { 80 define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); 81} else { 82 if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { 83 define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); 84 } else { 85 define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); 86 } 87} 88 89// Default for metadata_dir 90if (getenv('PHP_PEAR_METADATA_DIR')) { 91 define('PEAR_CONFIG_DEFAULT_METADATA_DIR', getenv('PHP_PEAR_METADATA_DIR')); 92} else { 93 define('PEAR_CONFIG_DEFAULT_METADATA_DIR', ''); 94} 95 96// Default for ext_dir 97if (getenv('PHP_PEAR_EXTENSION_DIR')) { 98 define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); 99} else { 100 if (ini_get('extension_dir')) { 101 define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); 102 } elseif (defined('PEAR_EXTENSION_DIR') && 103 file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { 104 define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); 105 } elseif (defined('PHP_EXTENSION_DIR')) { 106 define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); 107 } else { 108 define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); 109 } 110} 111 112// Default for doc_dir 113if (getenv('PHP_PEAR_DOC_DIR')) { 114 define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); 115} else { 116 define('PEAR_CONFIG_DEFAULT_DOC_DIR', 117 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); 118} 119 120// Default for bin_dir 121if (getenv('PHP_PEAR_BIN_DIR')) { 122 define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); 123} else { 124 define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); 125} 126 127// Default for data_dir 128if (getenv('PHP_PEAR_DATA_DIR')) { 129 define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); 130} else { 131 define('PEAR_CONFIG_DEFAULT_DATA_DIR', 132 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); 133} 134 135// Default for cfg_dir 136if (getenv('PHP_PEAR_CFG_DIR')) { 137 define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); 138} else { 139 define('PEAR_CONFIG_DEFAULT_CFG_DIR', 140 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); 141} 142 143// Default for www_dir 144if (getenv('PHP_PEAR_WWW_DIR')) { 145 define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); 146} else { 147 define('PEAR_CONFIG_DEFAULT_WWW_DIR', 148 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); 149} 150 151// Default for man_dir 152if (getenv('PHP_PEAR_MAN_DIR')) { 153 define('PEAR_CONFIG_DEFAULT_MAN_DIR', getenv('PHP_PEAR_MAN_DIR')); 154} else { 155 if (defined('PHP_MANDIR')) { // Added in PHP5.3.7 156 define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_MANDIR); 157 } else { 158 define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_PREFIX . DIRECTORY_SEPARATOR . 159 'local' . DIRECTORY_SEPARATOR .'man'); 160 } 161} 162 163// Default for test_dir 164if (getenv('PHP_PEAR_TEST_DIR')) { 165 define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); 166} else { 167 define('PEAR_CONFIG_DEFAULT_TEST_DIR', 168 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); 169} 170 171// Default for temp_dir 172if (getenv('PHP_PEAR_TEMP_DIR')) { 173 define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); 174} else { 175 define('PEAR_CONFIG_DEFAULT_TEMP_DIR', 176 System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . 177 DIRECTORY_SEPARATOR . 'temp'); 178} 179 180// Default for cache_dir 181if (getenv('PHP_PEAR_CACHE_DIR')) { 182 define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); 183} else { 184 define('PEAR_CONFIG_DEFAULT_CACHE_DIR', 185 System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . 186 DIRECTORY_SEPARATOR . 'cache'); 187} 188 189// Default for download_dir 190if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { 191 define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); 192} else { 193 define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', 194 System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . 195 DIRECTORY_SEPARATOR . 'download'); 196} 197 198// Default for php_bin 199if (getenv('PHP_PEAR_PHP_BIN')) { 200 define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); 201} else { 202 define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. 203 DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); 204} 205 206// Default for verbose 207if (getenv('PHP_PEAR_VERBOSE')) { 208 define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); 209} else { 210 define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); 211} 212 213// Default for preferred_state 214if (getenv('PHP_PEAR_PREFERRED_STATE')) { 215 define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); 216} else { 217 define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); 218} 219 220// Default for umask 221if (getenv('PHP_PEAR_UMASK')) { 222 define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); 223} else { 224 define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); 225} 226 227// Default for cache_ttl 228if (getenv('PHP_PEAR_CACHE_TTL')) { 229 define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); 230} else { 231 define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); 232} 233 234// Default for sig_type 235if (getenv('PHP_PEAR_SIG_TYPE')) { 236 define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); 237} else { 238 define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); 239} 240 241// Default for sig_bin 242if (getenv('PHP_PEAR_SIG_BIN')) { 243 define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); 244} else { 245 define('PEAR_CONFIG_DEFAULT_SIG_BIN', 246 System::which( 247 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); 248} 249 250// Default for sig_keydir 251if (getenv('PHP_PEAR_SIG_KEYDIR')) { 252 define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); 253} else { 254 define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', 255 PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); 256} 257 258/** 259 * This is a class for storing configuration data, keeping track of 260 * which are system-defined, user-defined or defaulted. 261 * @category pear 262 * @package PEAR 263 * @author Stig Bakken <ssb@php.net> 264 * @author Greg Beaver <cellog@php.net> 265 * @copyright 1997-2009 The Authors 266 * @license http://opensource.org/licenses/bsd-license.php New BSD License 267 * @version Release: @package_version@ 268 * @link http://pear.php.net/package/PEAR 269 * @since Class available since Release 0.1 270 */ 271class PEAR_Config extends PEAR 272{ 273 /** 274 * Array of config files used. 275 * 276 * @var array layer => config file 277 */ 278 var $files = array( 279 'system' => '', 280 'user' => '', 281 ); 282 283 var $layers = array(); 284 285 /** 286 * Configuration data, two-dimensional array where the first 287 * dimension is the config layer ('user', 'system' and 'default'), 288 * and the second dimension is keyname => value. 289 * 290 * The order in the first dimension is important! Earlier 291 * layers will shadow later ones when a config value is 292 * requested (if a 'user' value exists, it will be returned first, 293 * then 'system' and finally 'default'). 294 * 295 * @var array layer => array(keyname => value, ...) 296 */ 297 var $configuration = array( 298 'user' => array(), 299 'system' => array(), 300 'default' => array(), 301 ); 302 303 /** 304 * Configuration values that can be set for a channel 305 * 306 * All other configuration values can only have a global value 307 * @var array 308 * @access private 309 */ 310 var $_channelConfigInfo = array( 311 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', 312 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', 313 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' 314 ); 315 316 /** 317 * Channels that can be accessed 318 * @see setChannels() 319 * @var array 320 * @access private 321 */ 322 var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); 323 324 /** 325 * This variable is used to control the directory values returned 326 * @see setInstallRoot(); 327 * @var string|false 328 * @access private 329 */ 330 var $_installRoot = false; 331 332 /** 333 * If requested, this will always refer to the registry 334 * contained in php_dir 335 * @var PEAR_Registry 336 */ 337 var $_registry = array(); 338 339 /** 340 * @var array 341 * @access private 342 */ 343 var $_regInitialized = array(); 344 345 /** 346 * @var bool 347 * @access private 348 */ 349 var $_noRegistry = false; 350 351 /** 352 * amount of errors found while parsing config 353 * @var integer 354 * @access private 355 */ 356 var $_errorsFound = 0; 357 var $_lastError = null; 358 359 /** 360 * Information about the configuration data. Stores the type, 361 * default value and a documentation string for each configuration 362 * value. 363 * 364 * @var array layer => array(infotype => value, ...) 365 */ 366 var $configuration_info = array( 367 // Channels/Internet Access 368 'default_channel' => array( 369 'type' => 'string', 370 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, 371 'doc' => 'the default channel to use for all non explicit commands', 372 'prompt' => 'Default Channel', 373 'group' => 'Internet Access', 374 ), 375 'preferred_mirror' => array( 376 'type' => 'string', 377 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, 378 'doc' => 'the default server or mirror to use for channel actions', 379 'prompt' => 'Default Channel Mirror', 380 'group' => 'Internet Access', 381 ), 382 'remote_config' => array( 383 'type' => 'password', 384 'default' => '', 385 'doc' => 'ftp url of remote configuration file to use for synchronized install', 386 'prompt' => 'Remote Configuration File', 387 'group' => 'Internet Access', 388 ), 389 'auto_discover' => array( 390 'type' => 'integer', 391 'default' => 0, 392 'doc' => 'whether to automatically discover new channels', 393 'prompt' => 'Auto-discover new Channels', 394 'group' => 'Internet Access', 395 ), 396 // Internet Access 397 'master_server' => array( 398 'type' => 'string', 399 'default' => 'pear.php.net', 400 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', 401 'prompt' => 'PEAR server [DEPRECATED]', 402 'group' => 'Internet Access', 403 ), 404 'http_proxy' => array( 405 'type' => 'string', 406 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, 407 'doc' => 'HTTP proxy (host:port) to use when downloading packages', 408 'prompt' => 'HTTP Proxy Server Address', 409 'group' => 'Internet Access', 410 ), 411 // File Locations 412 'php_dir' => array( 413 'type' => 'directory', 414 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, 415 'doc' => 'directory where .php files are installed', 416 'prompt' => 'PEAR directory', 417 'group' => 'File Locations', 418 ), 419 'ext_dir' => array( 420 'type' => 'directory', 421 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, 422 'doc' => 'directory where loadable extensions are installed', 423 'prompt' => 'PHP extension directory', 424 'group' => 'File Locations', 425 ), 426 'doc_dir' => array( 427 'type' => 'directory', 428 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, 429 'doc' => 'directory where documentation is installed', 430 'prompt' => 'PEAR documentation directory', 431 'group' => 'File Locations', 432 ), 433 'bin_dir' => array( 434 'type' => 'directory', 435 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, 436 'doc' => 'directory where executables are installed', 437 'prompt' => 'PEAR executables directory', 438 'group' => 'File Locations', 439 ), 440 'data_dir' => array( 441 'type' => 'directory', 442 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, 443 'doc' => 'directory where data files are installed', 444 'prompt' => 'PEAR data directory', 445 'group' => 'File Locations (Advanced)', 446 ), 447 'cfg_dir' => array( 448 'type' => 'directory', 449 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, 450 'doc' => 'directory where modifiable configuration files are installed', 451 'prompt' => 'PEAR configuration file directory', 452 'group' => 'File Locations (Advanced)', 453 ), 454 'www_dir' => array( 455 'type' => 'directory', 456 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, 457 'doc' => 'directory where www frontend files (html/js) are installed', 458 'prompt' => 'PEAR www files directory', 459 'group' => 'File Locations (Advanced)', 460 ), 461 'man_dir' => array( 462 'type' => 'directory', 463 'default' => PEAR_CONFIG_DEFAULT_MAN_DIR, 464 'doc' => 'directory where unix manual pages are installed', 465 'prompt' => 'Systems manpage files directory', 466 'group' => 'File Locations (Advanced)', 467 ), 468 'test_dir' => array( 469 'type' => 'directory', 470 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, 471 'doc' => 'directory where regression tests are installed', 472 'prompt' => 'PEAR test directory', 473 'group' => 'File Locations (Advanced)', 474 ), 475 'cache_dir' => array( 476 'type' => 'directory', 477 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, 478 'doc' => 'directory which is used for web service cache', 479 'prompt' => 'PEAR Installer cache directory', 480 'group' => 'File Locations (Advanced)', 481 ), 482 'temp_dir' => array( 483 'type' => 'directory', 484 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, 485 'doc' => 'directory which is used for all temp files', 486 'prompt' => 'PEAR Installer temp directory', 487 'group' => 'File Locations (Advanced)', 488 ), 489 'download_dir' => array( 490 'type' => 'directory', 491 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, 492 'doc' => 'directory which is used for all downloaded files', 493 'prompt' => 'PEAR Installer download directory', 494 'group' => 'File Locations (Advanced)', 495 ), 496 'php_bin' => array( 497 'type' => 'file', 498 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, 499 'doc' => 'PHP CLI/CGI binary for executing scripts', 500 'prompt' => 'PHP CLI/CGI binary', 501 'group' => 'File Locations (Advanced)', 502 ), 503 'php_prefix' => array( 504 'type' => 'string', 505 'default' => '', 506 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', 507 'prompt' => '--program-prefix passed to PHP\'s ./configure', 508 'group' => 'File Locations (Advanced)', 509 ), 510 'php_suffix' => array( 511 'type' => 'string', 512 'default' => '', 513 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', 514 'prompt' => '--program-suffix passed to PHP\'s ./configure', 515 'group' => 'File Locations (Advanced)', 516 ), 517 'php_ini' => array( 518 'type' => 'file', 519 'default' => '', 520 'doc' => 'location of php.ini in which to enable PECL extensions on install', 521 'prompt' => 'php.ini location', 522 'group' => 'File Locations (Advanced)', 523 ), 524 'metadata_dir' => array( 525 'type' => 'directory', 526 'default' => PEAR_CONFIG_DEFAULT_METADATA_DIR, 527 'doc' => 'directory where metadata files are installed (registry, filemap, channels, ...)', 528 'prompt' => 'PEAR metadata directory', 529 'group' => 'File Locations (Advanced)', 530 ), 531 // Maintainers 532 'username' => array( 533 'type' => 'string', 534 'default' => '', 535 'doc' => '(maintainers) your PEAR account name', 536 'prompt' => 'PEAR username (for maintainers)', 537 'group' => 'Maintainers', 538 ), 539 'password' => array( 540 'type' => 'password', 541 'default' => '', 542 'doc' => '(maintainers) your PEAR account password', 543 'prompt' => 'PEAR password (for maintainers)', 544 'group' => 'Maintainers', 545 ), 546 // Advanced 547 'verbose' => array( 548 'type' => 'integer', 549 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, 550 'doc' => 'verbosity level 5510: really quiet 5521: somewhat quiet 5532: verbose 5543: debug', 555 'prompt' => 'Debug Log Level', 556 'group' => 'Advanced', 557 ), 558 'preferred_state' => array( 559 'type' => 'set', 560 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, 561 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', 562 'valid_set' => array( 563 'stable', 'beta', 'alpha', 'devel', 'snapshot'), 564 'prompt' => 'Preferred Package State', 565 'group' => 'Advanced', 566 ), 567 'umask' => array( 568 'type' => 'mask', 569 'default' => PEAR_CONFIG_DEFAULT_UMASK, 570 'doc' => 'umask used when creating files (Unix-like systems only)', 571 'prompt' => 'Unix file mask', 572 'group' => 'Advanced', 573 ), 574 'cache_ttl' => array( 575 'type' => 'integer', 576 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, 577 'doc' => 'amount of secs where the local cache is used and not updated', 578 'prompt' => 'Cache TimeToLive', 579 'group' => 'Advanced', 580 ), 581 'sig_type' => array( 582 'type' => 'set', 583 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, 584 'doc' => 'which package signature mechanism to use', 585 'valid_set' => array('gpg'), 586 'prompt' => 'Package Signature Type', 587 'group' => 'Maintainers', 588 ), 589 'sig_bin' => array( 590 'type' => 'string', 591 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, 592 'doc' => 'which package signature mechanism to use', 593 'prompt' => 'Signature Handling Program', 594 'group' => 'Maintainers', 595 ), 596 'sig_keyid' => array( 597 'type' => 'string', 598 'default' => '', 599 'doc' => 'which key to use for signing with', 600 'prompt' => 'Signature Key Id', 601 'group' => 'Maintainers', 602 ), 603 'sig_keydir' => array( 604 'type' => 'directory', 605 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, 606 'doc' => 'directory where signature keys are located', 607 'prompt' => 'Signature Key Directory', 608 'group' => 'Maintainers', 609 ), 610 // __channels is reserved - used for channel-specific configuration 611 ); 612 613 /** 614 * Constructor. 615 * 616 * @param string file to read user-defined options from 617 * @param string file to read system-wide defaults from 618 * @param bool determines whether a registry object "follows" 619 * the value of php_dir (is automatically created 620 * and moved when php_dir is changed) 621 * @param bool if true, fails if configuration files cannot be loaded 622 * 623 * @access public 624 * 625 * @see PEAR_Config::singleton 626 */ 627 function __construct($user_file = '', $system_file = '', $ftp_file = false, 628 $strict = true) 629 { 630 parent::__construct(); 631 PEAR_Installer_Role::initializeConfig($this); 632 $sl = DIRECTORY_SEPARATOR; 633 if (empty($user_file)) { 634 if (OS_WINDOWS) { 635 $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; 636 } else { 637 $user_file = getenv('HOME') . $sl . '.pearrc'; 638 } 639 } 640 641 if (empty($system_file)) { 642 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; 643 if (OS_WINDOWS) { 644 $system_file .= 'pearsys.ini'; 645 } else { 646 $system_file .= 'pear.conf'; 647 } 648 } 649 650 $this->layers = array_keys($this->configuration); 651 $this->files['user'] = $user_file; 652 $this->files['system'] = $system_file; 653 if ($user_file && file_exists($user_file)) { 654 $this->pushErrorHandling(PEAR_ERROR_RETURN); 655 $this->readConfigFile($user_file, 'user', $strict); 656 $this->popErrorHandling(); 657 if ($this->_errorsFound > 0) { 658 return; 659 } 660 } 661 662 if ($system_file && @file_exists($system_file)) { 663 $this->mergeConfigFile($system_file, false, 'system', $strict); 664 if ($this->_errorsFound > 0) { 665 return; 666 } 667 668 } 669 670 if (!$ftp_file) { 671 $ftp_file = $this->get('remote_config'); 672 } 673 674 if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { 675 $this->readFTPConfigFile($ftp_file); 676 } 677 678 foreach ($this->configuration_info as $key => $info) { 679 $this->configuration['default'][$key] = $info['default']; 680 } 681 682 $this->_registry['default'] = new PEAR_Registry( 683 $this->configuration['default']['php_dir'], false, false, 684 $this->configuration['default']['metadata_dir']); 685 $this->_registry['default']->setConfig($this, false); 686 $this->_regInitialized['default'] = false; 687 //$GLOBALS['_PEAR_Config_instance'] = &$this; 688 } 689 690 /** 691 * Return the default locations of user and system configuration files 692 */ 693 public static function getDefaultConfigFiles() 694 { 695 $sl = DIRECTORY_SEPARATOR; 696 if (OS_WINDOWS) { 697 return array( 698 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', 699 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' 700 ); 701 } 702 703 return array( 704 'user' => getenv('HOME') . $sl . '.pearrc', 705 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' 706 ); 707 } 708 709 /** 710 * Static singleton method. If you want to keep only one instance 711 * of this class in use, this method will give you a reference to 712 * the last created PEAR_Config object if one exists, or create a 713 * new object. 714 * 715 * @param string (optional) file to read user-defined options from 716 * @param string (optional) file to read system-wide defaults from 717 * 718 * @return object an existing or new PEAR_Config instance 719 * 720 * @see PEAR_Config::PEAR_Config 721 */ 722 public static function &singleton($user_file = '', $system_file = '', $strict = true) 723 { 724 if (is_object($GLOBALS['_PEAR_Config_instance'])) { 725 return $GLOBALS['_PEAR_Config_instance']; 726 } 727 728 $t_conf = new PEAR_Config($user_file, $system_file, false, $strict); 729 if ($t_conf->_errorsFound > 0) { 730 return $t_conf->lastError; 731 } 732 733 $GLOBALS['_PEAR_Config_instance'] = &$t_conf; 734 return $GLOBALS['_PEAR_Config_instance']; 735 } 736 737 /** 738 * Determine whether any configuration files have been detected, and whether a 739 * registry object can be retrieved from this configuration. 740 * @return bool 741 * @since PEAR 1.4.0a1 742 */ 743 function validConfiguration() 744 { 745 if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { 746 return true; 747 } 748 749 return false; 750 } 751 752 /** 753 * Reads configuration data from a file. All existing values in 754 * the config layer are discarded and replaced with data from the 755 * file. 756 * @param string file to read from, if NULL or not specified, the 757 * last-used file for the same layer (second param) is used 758 * @param string config layer to insert data into ('user' or 'system') 759 * @return bool TRUE on success or a PEAR error on failure 760 */ 761 function readConfigFile($file = null, $layer = 'user', $strict = true) 762 { 763 if (empty($this->files[$layer])) { 764 return $this->raiseError("unknown config layer `$layer'"); 765 } 766 767 if ($file === null) { 768 $file = $this->files[$layer]; 769 } 770 771 $data = $this->_readConfigDataFrom($file); 772 if (PEAR::isError($data)) { 773 if (!$strict) { 774 return true; 775 } 776 777 $this->_errorsFound++; 778 $this->lastError = $data; 779 780 return $data; 781 } 782 783 $this->files[$layer] = $file; 784 $this->_decodeInput($data); 785 $this->configuration[$layer] = $data; 786 $this->_setupChannels(); 787 if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { 788 $this->_registry[$layer] = new PEAR_Registry( 789 $phpdir, false, false, 790 $this->get('metadata_dir', $layer, 'pear.php.net')); 791 $this->_registry[$layer]->setConfig($this, false); 792 $this->_regInitialized[$layer] = false; 793 } else { 794 unset($this->_registry[$layer]); 795 } 796 return true; 797 } 798 799 /** 800 * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini 801 * @return true|PEAR_Error 802 */ 803 function readFTPConfigFile($path) 804 { 805 do { // poor man's try 806 if (!class_exists('PEAR_FTP')) { 807 if (!class_exists('PEAR_Common')) { 808 require_once 'PEAR/Common.php'; 809 } 810 if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { 811 require_once 'PEAR/FTP.php'; 812 } 813 } 814 815 if (!class_exists('PEAR_FTP')) { 816 return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); 817 } 818 819 $this->_ftp = new PEAR_FTP; 820 $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); 821 $e = $this->_ftp->init($path); 822 if (PEAR::isError($e)) { 823 $this->_ftp->popErrorHandling(); 824 return $e; 825 } 826 827 $tmp = System::mktemp('-d'); 828 PEAR_Common::addTempFile($tmp); 829 $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . 830 'pear.ini', false, FTP_BINARY); 831 if (PEAR::isError($e)) { 832 $this->_ftp->popErrorHandling(); 833 return $e; 834 } 835 836 PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); 837 $this->_ftp->disconnect(); 838 $this->_ftp->popErrorHandling(); 839 $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; 840 $e = $this->readConfigFile(null, 'ftp'); 841 if (PEAR::isError($e)) { 842 return $e; 843 } 844 845 $fail = array(); 846 foreach ($this->configuration_info as $key => $val) { 847 if (in_array($this->getGroup($key), 848 array('File Locations', 'File Locations (Advanced)')) && 849 $this->getType($key) == 'directory') { 850 // any directory configs must be set for this to work 851 if (!isset($this->configuration['ftp'][$key])) { 852 $fail[] = $key; 853 } 854 } 855 } 856 857 if (!count($fail)) { 858 return true; 859 } 860 861 $fail = '"' . implode('", "', $fail) . '"'; 862 unset($this->files['ftp']); 863 unset($this->configuration['ftp']); 864 return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . 865 'directory configuration variables. These variables were not set: ' . 866 $fail); 867 } while (false); // poor man's catch 868 unset($this->files['ftp']); 869 return PEAR::raiseError('no remote host specified'); 870 } 871 872 /** 873 * Reads the existing configurations and creates the _channels array from it 874 */ 875 function _setupChannels() 876 { 877 $set = array_flip(array_values($this->_channels)); 878 foreach ($this->configuration as $layer => $data) { 879 $i = 1000; 880 if (isset($data['__channels']) && is_array($data['__channels'])) { 881 foreach ($data['__channels'] as $channel => $info) { 882 $set[$channel] = $i++; 883 } 884 } 885 } 886 $this->_channels = array_values(array_flip($set)); 887 $this->setChannels($this->_channels); 888 } 889 890 function deleteChannel($channel) 891 { 892 $ch = strtolower($channel); 893 foreach ($this->configuration as $layer => $data) { 894 if (isset($data['__channels']) && isset($data['__channels'][$ch])) { 895 unset($this->configuration[$layer]['__channels'][$ch]); 896 } 897 } 898 899 $this->_channels = array_flip($this->_channels); 900 unset($this->_channels[$ch]); 901 $this->_channels = array_flip($this->_channels); 902 } 903 904 /** 905 * Merges data into a config layer from a file. Does the same 906 * thing as readConfigFile, except it does not replace all 907 * existing values in the config layer. 908 * @param string file to read from 909 * @param bool whether to overwrite existing data (default TRUE) 910 * @param string config layer to insert data into ('user' or 'system') 911 * @param string if true, errors are returned if file opening fails 912 * @return bool TRUE on success or a PEAR error on failure 913 */ 914 function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) 915 { 916 if (empty($this->files[$layer])) { 917 return $this->raiseError("unknown config layer `$layer'"); 918 } 919 920 if ($file === null) { 921 $file = $this->files[$layer]; 922 } 923 924 $data = $this->_readConfigDataFrom($file); 925 if (PEAR::isError($data)) { 926 if (!$strict) { 927 return true; 928 } 929 930 $this->_errorsFound++; 931 $this->lastError = $data; 932 933 return $data; 934 } 935 936 $this->_decodeInput($data); 937 if ($override) { 938 $this->configuration[$layer] = 939 PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); 940 } else { 941 $this->configuration[$layer] = 942 PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); 943 } 944 945 $this->_setupChannels(); 946 if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { 947 $this->_registry[$layer] = new PEAR_Registry( 948 $phpdir, false, false, 949 $this->get('metadata_dir', $layer, 'pear.php.net')); 950 $this->_registry[$layer]->setConfig($this, false); 951 $this->_regInitialized[$layer] = false; 952 } else { 953 unset($this->_registry[$layer]); 954 } 955 return true; 956 } 957 958 /** 959 * @param array 960 * @param array 961 * @return array 962 */ 963 public static function arrayMergeRecursive($arr2, $arr1) 964 { 965 $ret = array(); 966 foreach ($arr2 as $key => $data) { 967 if (!isset($arr1[$key])) { 968 $ret[$key] = $data; 969 unset($arr1[$key]); 970 continue; 971 } 972 if (is_array($data)) { 973 if (!is_array($arr1[$key])) { 974 $ret[$key] = $arr1[$key]; 975 unset($arr1[$key]); 976 continue; 977 } 978 $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); 979 unset($arr1[$key]); 980 } 981 } 982 983 return array_merge($ret, $arr1); 984 } 985 986 /** 987 * Writes data into a config layer from a file. 988 * 989 * @param string|null file to read from, or null for default 990 * @param string config layer to insert data into ('user' or 991 * 'system') 992 * @param string|null data to write to config file or null for internal data [DEPRECATED] 993 * @return bool TRUE on success or a PEAR error on failure 994 */ 995 function writeConfigFile($file = null, $layer = 'user', $data = null) 996 { 997 $this->_lazyChannelSetup($layer); 998 if ($layer == 'both' || $layer == 'all') { 999 foreach ($this->files as $type => $file) { 1000 $err = $this->writeConfigFile($file, $type, $data); 1001 if (PEAR::isError($err)) { 1002 return $err; 1003 } 1004 } 1005 return true; 1006 } 1007 1008 if (empty($this->files[$layer])) { 1009 return $this->raiseError("unknown config file type `$layer'"); 1010 } 1011 1012 if ($file === null) { 1013 $file = $this->files[$layer]; 1014 } 1015 1016 $data = ($data === null) ? $this->configuration[$layer] : $data; 1017 $this->_encodeOutput($data); 1018 $opt = array('-p', dirname($file)); 1019 if (!@System::mkDir($opt)) { 1020 return $this->raiseError("could not create directory: " . dirname($file)); 1021 } 1022 1023 if (file_exists($file) && is_file($file) && !is_writeable($file)) { 1024 return $this->raiseError("no write access to $file!"); 1025 } 1026 1027 $fp = @fopen($file, "w"); 1028 if (!$fp) { 1029 return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); 1030 } 1031 1032 $contents = "#PEAR_Config 0.9\n" . serialize($data); 1033 if (!@fwrite($fp, $contents)) { 1034 return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); 1035 } 1036 return true; 1037 } 1038 1039 /** 1040 * Reads configuration data from a file and returns the parsed data 1041 * in an array. 1042 * 1043 * @param string file to read from 1044 * @return array configuration data or a PEAR error on failure 1045 * @access private 1046 */ 1047 function _readConfigDataFrom($file) 1048 { 1049 $fp = false; 1050 if (file_exists($file)) { 1051 $fp = @fopen($file, "r"); 1052 } 1053 1054 if (!$fp) { 1055 return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); 1056 } 1057 1058 $size = filesize($file); 1059 fclose($fp); 1060 $contents = file_get_contents($file); 1061 if (empty($contents)) { 1062 return $this->raiseError('Configuration file "' . $file . '" is empty'); 1063 } 1064 1065 $version = false; 1066 if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { 1067 $version = $matches[1]; 1068 $contents = substr($contents, strlen($matches[0])); 1069 } else { 1070 // Museum config file 1071 if (substr($contents,0,2) == 'a:') { 1072 $version = '0.1'; 1073 } 1074 } 1075 1076 if ($version && version_compare("$version", '1', '<')) { 1077 // no '@', it is possible that unserialize 1078 // raises a notice but it seems to block IO to 1079 // STDOUT if a '@' is used and a notice is raise 1080 $data = unserialize($contents); 1081 1082 if (!is_array($data) && !$data) { 1083 if ($contents == serialize(false)) { 1084 $data = array(); 1085 } else { 1086 $err = $this->raiseError("PEAR_Config: bad data in $file"); 1087 return $err; 1088 } 1089 } 1090 if (!is_array($data)) { 1091 if (strlen(trim($contents)) > 0) { 1092 $error = "PEAR_Config: bad data in $file"; 1093 $err = $this->raiseError($error); 1094 return $err; 1095 } 1096 1097 $data = array(); 1098 } 1099 // add parsing of newer formats here... 1100 } else { 1101 $err = $this->raiseError("$file: unknown version `$version'"); 1102 return $err; 1103 } 1104 1105 return $data; 1106 } 1107 1108 /** 1109 * Gets the file used for storing the config for a layer 1110 * 1111 * @param string $layer 'user' or 'system' 1112 */ 1113 function getConfFile($layer) 1114 { 1115 return $this->files[$layer]; 1116 } 1117 1118 /** 1119 * @param string Configuration class name, used for detecting duplicate calls 1120 * @param array information on a role as parsed from its xml file 1121 * @return true|PEAR_Error 1122 * @access private 1123 */ 1124 function _addConfigVars($class, $vars) 1125 { 1126 static $called = array(); 1127 if (isset($called[$class])) { 1128 return; 1129 } 1130 1131 $called[$class] = 1; 1132 if (count($vars) > 3) { 1133 return $this->raiseError('Roles can only define 3 new config variables or less'); 1134 } 1135 1136 foreach ($vars as $name => $var) { 1137 if (!is_array($var)) { 1138 return $this->raiseError('Configuration information must be an array'); 1139 } 1140 1141 if (!isset($var['type'])) { 1142 return $this->raiseError('Configuration information must contain a type'); 1143 } elseif (!in_array($var['type'], 1144 array('string', 'mask', 'password', 'directory', 'file', 'set'))) { 1145 return $this->raiseError( 1146 'Configuration type must be one of directory, file, string, ' . 1147 'mask, set, or password'); 1148 } 1149 if (!isset($var['default'])) { 1150 return $this->raiseError( 1151 'Configuration information must contain a default value ("default" index)'); 1152 } 1153 1154 if (is_array($var['default'])) { 1155 $real_default = ''; 1156 foreach ($var['default'] as $config_var => $val) { 1157 if (strpos($config_var, 'text') === 0) { 1158 $real_default .= $val; 1159 } elseif (strpos($config_var, 'constant') === 0) { 1160 if (!defined($val)) { 1161 return $this->raiseError( 1162 'Unknown constant "' . $val . '" requested in ' . 1163 'default value for configuration variable "' . 1164 $name . '"'); 1165 } 1166 1167 $real_default .= constant($val); 1168 } elseif (isset($this->configuration_info[$config_var])) { 1169 $real_default .= 1170 $this->configuration_info[$config_var]['default']; 1171 } else { 1172 return $this->raiseError( 1173 'Unknown request for "' . $config_var . '" value in ' . 1174 'default value for configuration variable "' . 1175 $name . '"'); 1176 } 1177 } 1178 $var['default'] = $real_default; 1179 } 1180 1181 if ($var['type'] == 'integer') { 1182 $var['default'] = (integer) $var['default']; 1183 } 1184 1185 if (!isset($var['doc'])) { 1186 return $this->raiseError( 1187 'Configuration information must contain a summary ("doc" index)'); 1188 } 1189 1190 if (!isset($var['prompt'])) { 1191 return $this->raiseError( 1192 'Configuration information must contain a simple prompt ("prompt" index)'); 1193 } 1194 1195 if (!isset($var['group'])) { 1196 return $this->raiseError( 1197 'Configuration information must contain a simple group ("group" index)'); 1198 } 1199 1200 if (isset($this->configuration_info[$name])) { 1201 return $this->raiseError('Configuration variable "' . $name . 1202 '" already exists'); 1203 } 1204 1205 $this->configuration_info[$name] = $var; 1206 // fix bug #7351: setting custom config variable in a channel fails 1207 $this->_channelConfigInfo[] = $name; 1208 } 1209 1210 return true; 1211 } 1212 1213 /** 1214 * Encodes/scrambles configuration data before writing to files. 1215 * Currently, 'password' values will be base64-encoded as to avoid 1216 * that people spot cleartext passwords by accident. 1217 * 1218 * @param array (reference) array to encode values in 1219 * @return bool TRUE on success 1220 * @access private 1221 */ 1222 function _encodeOutput(&$data) 1223 { 1224 foreach ($data as $key => $value) { 1225 if ($key == '__channels') { 1226 foreach ($data['__channels'] as $channel => $blah) { 1227 $this->_encodeOutput($data['__channels'][$channel]); 1228 } 1229 } 1230 1231 if (!isset($this->configuration_info[$key])) { 1232 continue; 1233 } 1234 1235 $type = $this->configuration_info[$key]['type']; 1236 switch ($type) { 1237 // we base64-encode passwords so they are at least 1238 // not shown in plain by accident 1239 case 'password': { 1240 $data[$key] = base64_encode($data[$key]); 1241 break; 1242 } 1243 case 'mask': { 1244 $data[$key] = octdec($data[$key]); 1245 break; 1246 } 1247 } 1248 } 1249 1250 return true; 1251 } 1252 1253 /** 1254 * Decodes/unscrambles configuration data after reading from files. 1255 * 1256 * @param array (reference) array to encode values in 1257 * @return bool TRUE on success 1258 * @access private 1259 * 1260 * @see PEAR_Config::_encodeOutput 1261 */ 1262 function _decodeInput(&$data) 1263 { 1264 if (!is_array($data)) { 1265 return true; 1266 } 1267 1268 foreach ($data as $key => $value) { 1269 if ($key == '__channels') { 1270 foreach ($data['__channels'] as $channel => $blah) { 1271 $this->_decodeInput($data['__channels'][$channel]); 1272 } 1273 } 1274 1275 if (!isset($this->configuration_info[$key])) { 1276 continue; 1277 } 1278 1279 $type = $this->configuration_info[$key]['type']; 1280 switch ($type) { 1281 case 'password': { 1282 $data[$key] = base64_decode($data[$key]); 1283 break; 1284 } 1285 case 'mask': { 1286 $data[$key] = decoct($data[$key]); 1287 break; 1288 } 1289 } 1290 } 1291 1292 return true; 1293 } 1294 1295 /** 1296 * Retrieve the default channel. 1297 * 1298 * On startup, channels are not initialized, so if the default channel is not 1299 * pear.php.net, then initialize the config. 1300 * @param string registry layer 1301 * @return string|false 1302 */ 1303 function getDefaultChannel($layer = null) 1304 { 1305 $ret = false; 1306 if ($layer === null) { 1307 foreach ($this->layers as $layer) { 1308 if (isset($this->configuration[$layer]['default_channel'])) { 1309 $ret = $this->configuration[$layer]['default_channel']; 1310 break; 1311 } 1312 } 1313 } elseif (isset($this->configuration[$layer]['default_channel'])) { 1314 $ret = $this->configuration[$layer]['default_channel']; 1315 } 1316 1317 if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { 1318 $ret = 'pecl.php.net'; 1319 } 1320 1321 if ($ret) { 1322 if ($ret != 'pear.php.net') { 1323 $this->_lazyChannelSetup(); 1324 } 1325 1326 return $ret; 1327 } 1328 1329 return PEAR_CONFIG_DEFAULT_CHANNEL; 1330 } 1331 1332 /** 1333 * Returns a configuration value, prioritizing layers as per the 1334 * layers property. 1335 * 1336 * @param string config key 1337 * @return mixed the config value, or NULL if not found 1338 * @access public 1339 */ 1340 function get($key, $layer = null, $channel = false) 1341 { 1342 if (!isset($this->configuration_info[$key])) { 1343 return null; 1344 } 1345 1346 if ($key == '__channels') { 1347 return null; 1348 } 1349 1350 if ($key == 'default_channel') { 1351 return $this->getDefaultChannel($layer); 1352 } 1353 1354 if (!$channel) { 1355 $channel = $this->getDefaultChannel(); 1356 } elseif ($channel != 'pear.php.net') { 1357 $this->_lazyChannelSetup(); 1358 } 1359 $channel = strtolower($channel); 1360 1361 $test = (in_array($key, $this->_channelConfigInfo)) ? 1362 $this->_getChannelValue($key, $layer, $channel) : 1363 null; 1364 if ($test !== null) { 1365 if ($this->_installRoot) { 1366 if (in_array($this->getGroup($key), 1367 array('File Locations', 'File Locations (Advanced)')) && 1368 $this->getType($key) == 'directory') { 1369 return $this->_prependPath($test, $this->_installRoot); 1370 } 1371 } 1372 return $test; 1373 } 1374 1375 if ($layer === null) { 1376 foreach ($this->layers as $layer) { 1377 if (isset($this->configuration[$layer][$key])) { 1378 $test = $this->configuration[$layer][$key]; 1379 if ($this->_installRoot) { 1380 if (in_array($this->getGroup($key), 1381 array('File Locations', 'File Locations (Advanced)')) && 1382 $this->getType($key) == 'directory') { 1383 return $this->_prependPath($test, $this->_installRoot); 1384 } 1385 } 1386 1387 if ($key == 'preferred_mirror') { 1388 $reg = &$this->getRegistry(); 1389 if (is_object($reg)) { 1390 $chan = $reg->getChannel($channel); 1391 if (PEAR::isError($chan)) { 1392 return $channel; 1393 } 1394 1395 if (!$chan->getMirror($test) && $chan->getName() != $test) { 1396 return $channel; // mirror does not exist 1397 } 1398 } 1399 } 1400 return $test; 1401 } 1402 } 1403 } elseif (isset($this->configuration[$layer][$key])) { 1404 $test = $this->configuration[$layer][$key]; 1405 if ($this->_installRoot) { 1406 if (in_array($this->getGroup($key), 1407 array('File Locations', 'File Locations (Advanced)')) && 1408 $this->getType($key) == 'directory') { 1409 return $this->_prependPath($test, $this->_installRoot); 1410 } 1411 } 1412 1413 if ($key == 'preferred_mirror') { 1414 $reg = &$this->getRegistry(); 1415 if (is_object($reg)) { 1416 $chan = $reg->getChannel($channel); 1417 if (PEAR::isError($chan)) { 1418 return $channel; 1419 } 1420 1421 if (!$chan->getMirror($test) && $chan->getName() != $test) { 1422 return $channel; // mirror does not exist 1423 } 1424 } 1425 } 1426 1427 return $test; 1428 } 1429 1430 return null; 1431 } 1432 1433 /** 1434 * Returns a channel-specific configuration value, prioritizing layers as per the 1435 * layers property. 1436 * 1437 * @param string config key 1438 * @return mixed the config value, or NULL if not found 1439 * @access private 1440 */ 1441 function _getChannelValue($key, $layer, $channel) 1442 { 1443 if ($key == '__channels' || $channel == 'pear.php.net') { 1444 return null; 1445 } 1446 1447 $ret = null; 1448 if ($layer === null) { 1449 foreach ($this->layers as $ilayer) { 1450 if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { 1451 $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; 1452 break; 1453 } 1454 } 1455 } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { 1456 $ret = $this->configuration[$layer]['__channels'][$channel][$key]; 1457 } 1458 1459 if ($key != 'preferred_mirror') { 1460 return $ret; 1461 } 1462 1463 1464 if ($ret !== null) { 1465 $reg = &$this->getRegistry($layer); 1466 if (is_object($reg)) { 1467 $chan = $reg->getChannel($channel); 1468 if (PEAR::isError($chan)) { 1469 return $channel; 1470 } 1471 1472 if (!$chan->getMirror($ret) && $chan->getName() != $ret) { 1473 return $channel; // mirror does not exist 1474 } 1475 } 1476 1477 return $ret; 1478 } 1479 1480 if ($channel != $this->getDefaultChannel($layer)) { 1481 return $channel; // we must use the channel name as the preferred mirror 1482 // if the user has not chosen an alternate 1483 } 1484 1485 return $this->getDefaultChannel($layer); 1486 } 1487 1488 /** 1489 * Set a config value in a specific layer (defaults to 'user'). 1490 * Enforces the types defined in the configuration_info array. An 1491 * integer config variable will be cast to int, and a set config 1492 * variable will be validated against its legal values. 1493 * 1494 * @param string config key 1495 * @param string config value 1496 * @param string (optional) config layer 1497 * @param string channel to set this value for, or null for global value 1498 * @return bool TRUE on success, FALSE on failure 1499 */ 1500 function set($key, $value, $layer = 'user', $channel = false) 1501 { 1502 if ($key == '__channels') { 1503 return false; 1504 } 1505 1506 if (!isset($this->configuration[$layer])) { 1507 return false; 1508 } 1509 1510 if ($key == 'default_channel') { 1511 // can only set this value globally 1512 $channel = 'pear.php.net'; 1513 if ($value != 'pear.php.net') { 1514 $this->_lazyChannelSetup($layer); 1515 } 1516 } 1517 1518 if ($key == 'preferred_mirror') { 1519 if ($channel == '__uri') { 1520 return false; // can't set the __uri pseudo-channel's mirror 1521 } 1522 1523 $reg = &$this->getRegistry($layer); 1524 if (is_object($reg)) { 1525 $chan = $reg->getChannel($channel ? $channel : 'pear.php.net'); 1526 if (PEAR::isError($chan)) { 1527 return false; 1528 } 1529 1530 if (!$chan->getMirror($value) && $chan->getName() != $value) { 1531 return false; // mirror does not exist 1532 } 1533 } 1534 } 1535 1536 if (!isset($this->configuration_info[$key])) { 1537 return false; 1538 } 1539 1540 extract($this->configuration_info[$key]); 1541 switch ($type) { 1542 case 'integer': 1543 $value = (int)$value; 1544 break; 1545 case 'set': { 1546 // If a valid_set is specified, require the value to 1547 // be in the set. If there is no valid_set, accept 1548 // any value. 1549 if ($valid_set) { 1550 reset($valid_set); 1551 if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || 1552 (key($valid_set) !== 0 && empty($valid_set[$value]))) 1553 { 1554 return false; 1555 } 1556 } 1557 break; 1558 } 1559 } 1560 1561 if (!$channel) { 1562 $channel = $this->get('default_channel', null, 'pear.php.net'); 1563 } 1564 1565 if (!in_array($channel, $this->_channels)) { 1566 $this->_lazyChannelSetup($layer); 1567 $reg = &$this->getRegistry($layer); 1568 if ($reg) { 1569 $channel = $reg->channelName($channel); 1570 } 1571 1572 if (!in_array($channel, $this->_channels)) { 1573 return false; 1574 } 1575 } 1576 1577 if ($channel != 'pear.php.net') { 1578 if (in_array($key, $this->_channelConfigInfo)) { 1579 $this->configuration[$layer]['__channels'][$channel][$key] = $value; 1580 return true; 1581 } 1582 1583 return false; 1584 } 1585 1586 if ($key == 'default_channel') { 1587 if (!isset($reg)) { 1588 $reg = &$this->getRegistry($layer); 1589 if (!$reg) { 1590 $reg = &$this->getRegistry(); 1591 } 1592 } 1593 1594 if ($reg) { 1595 $value = $reg->channelName($value); 1596 } 1597 1598 if (!$value) { 1599 return false; 1600 } 1601 } 1602 1603 $this->configuration[$layer][$key] = $value; 1604 if ($key == 'php_dir' && !$this->_noRegistry) { 1605 if (!isset($this->_registry[$layer]) || 1606 $value != $this->_registry[$layer]->install_dir) { 1607 $this->_registry[$layer] = new PEAR_Registry($value); 1608 $this->_regInitialized[$layer] = false; 1609 $this->_registry[$layer]->setConfig($this, false); 1610 } 1611 } 1612 1613 return true; 1614 } 1615 1616 function _lazyChannelSetup($uselayer = false) 1617 { 1618 if ($this->_noRegistry) { 1619 return; 1620 } 1621 1622 $merge = false; 1623 foreach ($this->_registry as $layer => $p) { 1624 if ($uselayer && $uselayer != $layer) { 1625 continue; 1626 } 1627 1628 if (!$this->_regInitialized[$layer]) { 1629 if ($layer == 'default' && isset($this->_registry['user']) || 1630 isset($this->_registry['system'])) { 1631 // only use the default registry if there are no alternatives 1632 continue; 1633 } 1634 1635 if (!is_object($this->_registry[$layer])) { 1636 if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { 1637 $this->_registry[$layer] = new PEAR_Registry( 1638 $phpdir, false, false, 1639 $this->get('metadata_dir', $layer, 'pear.php.net')); 1640 $this->_registry[$layer]->setConfig($this, false); 1641 $this->_regInitialized[$layer] = false; 1642 } else { 1643 unset($this->_registry[$layer]); 1644 return; 1645 } 1646 } 1647 1648 $this->setChannels($this->_registry[$layer]->listChannels(), $merge); 1649 $this->_regInitialized[$layer] = true; 1650 $merge = true; 1651 } 1652 } 1653 } 1654 1655 /** 1656 * Set the list of channels. 1657 * 1658 * This should be set via a call to {@link PEAR_Registry::listChannels()} 1659 * @param array 1660 * @param bool 1661 * @return bool success of operation 1662 */ 1663 function setChannels($channels, $merge = false) 1664 { 1665 if (!is_array($channels)) { 1666 return false; 1667 } 1668 1669 if ($merge) { 1670 $this->_channels = array_merge($this->_channels, $channels); 1671 } else { 1672 $this->_channels = $channels; 1673 } 1674 1675 foreach ($channels as $channel) { 1676 $channel = strtolower($channel); 1677 if ($channel == 'pear.php.net') { 1678 continue; 1679 } 1680 1681 foreach ($this->layers as $layer) { 1682 if (!isset($this->configuration[$layer]['__channels'])) { 1683 $this->configuration[$layer]['__channels'] = array(); 1684 } 1685 if (!isset($this->configuration[$layer]['__channels'][$channel]) 1686 || !is_array($this->configuration[$layer]['__channels'][$channel])) { 1687 $this->configuration[$layer]['__channels'][$channel] = array(); 1688 } 1689 } 1690 } 1691 1692 return true; 1693 } 1694 1695 /** 1696 * Get the type of a config value. 1697 * 1698 * @param string config key 1699 * 1700 * @return string type, one of "string", "integer", "file", 1701 * "directory", "set" or "password". 1702 * 1703 * @access public 1704 * 1705 */ 1706 function getType($key) 1707 { 1708 if (isset($this->configuration_info[$key])) { 1709 return $this->configuration_info[$key]['type']; 1710 } 1711 return false; 1712 } 1713 1714 /** 1715 * Get the documentation for a config value. 1716 * 1717 * @param string config key 1718 * @return string documentation string 1719 * 1720 * @access public 1721 * 1722 */ 1723 function getDocs($key) 1724 { 1725 if (isset($this->configuration_info[$key])) { 1726 return $this->configuration_info[$key]['doc']; 1727 } 1728 1729 return false; 1730 } 1731 1732 /** 1733 * Get the short documentation for a config value. 1734 * 1735 * @param string config key 1736 * @return string short documentation string 1737 * 1738 * @access public 1739 * 1740 */ 1741 function getPrompt($key) 1742 { 1743 if (isset($this->configuration_info[$key])) { 1744 return $this->configuration_info[$key]['prompt']; 1745 } 1746 1747 return false; 1748 } 1749 1750 /** 1751 * Get the parameter group for a config key. 1752 * 1753 * @param string config key 1754 * @return string parameter group 1755 * 1756 * @access public 1757 * 1758 */ 1759 function getGroup($key) 1760 { 1761 if (isset($this->configuration_info[$key])) { 1762 return $this->configuration_info[$key]['group']; 1763 } 1764 1765 return false; 1766 } 1767 1768 /** 1769 * Get the list of parameter groups. 1770 * 1771 * @return array list of parameter groups 1772 * 1773 * @access public 1774 * 1775 */ 1776 function getGroups() 1777 { 1778 $tmp = array(); 1779 foreach ($this->configuration_info as $key => $info) { 1780 $tmp[$info['group']] = 1; 1781 } 1782 1783 return array_keys($tmp); 1784 } 1785 1786 /** 1787 * Get the list of the parameters in a group. 1788 * 1789 * @param string $group parameter group 1790 * @return array list of parameters in $group 1791 * 1792 * @access public 1793 * 1794 */ 1795 function getGroupKeys($group) 1796 { 1797 $keys = array(); 1798 foreach ($this->configuration_info as $key => $info) { 1799 if ($info['group'] == $group) { 1800 $keys[] = $key; 1801 } 1802 } 1803 1804 return $keys; 1805 } 1806 1807 /** 1808 * Get the list of allowed set values for a config value. Returns 1809 * NULL for config values that are not sets. 1810 * 1811 * @param string config key 1812 * @return array enumerated array of set values, or NULL if the 1813 * config key is unknown or not a set 1814 * 1815 * @access public 1816 * 1817 */ 1818 function getSetValues($key) 1819 { 1820 if (isset($this->configuration_info[$key]) && 1821 isset($this->configuration_info[$key]['type']) && 1822 $this->configuration_info[$key]['type'] == 'set') 1823 { 1824 $valid_set = $this->configuration_info[$key]['valid_set']; 1825 reset($valid_set); 1826 if (key($valid_set) === 0) { 1827 return $valid_set; 1828 } 1829 1830 return array_keys($valid_set); 1831 } 1832 1833 return null; 1834 } 1835 1836 /** 1837 * Get all the current config keys. 1838 * 1839 * @return array simple array of config keys 1840 * 1841 * @access public 1842 */ 1843 function getKeys() 1844 { 1845 $keys = array(); 1846 foreach ($this->layers as $layer) { 1847 $test = $this->configuration[$layer]; 1848 if (isset($test['__channels'])) { 1849 foreach ($test['__channels'] as $channel => $configs) { 1850 $keys = array_merge($keys, $configs); 1851 } 1852 } 1853 1854 unset($test['__channels']); 1855 $keys = array_merge($keys, $test); 1856 1857 } 1858 return array_keys($keys); 1859 } 1860 1861 /** 1862 * Remove the a config key from a specific config layer. 1863 * 1864 * @param string config key 1865 * @param string (optional) config layer 1866 * @param string (optional) channel (defaults to default channel) 1867 * @return bool TRUE on success, FALSE on failure 1868 * 1869 * @access public 1870 */ 1871 function remove($key, $layer = 'user', $channel = null) 1872 { 1873 if ($channel === null) { 1874 $channel = $this->getDefaultChannel(); 1875 } 1876 1877 if ($channel !== 'pear.php.net') { 1878 if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { 1879 unset($this->configuration[$layer]['__channels'][$channel][$key]); 1880 return true; 1881 } 1882 } 1883 1884 if (isset($this->configuration[$layer][$key])) { 1885 unset($this->configuration[$layer][$key]); 1886 return true; 1887 } 1888 1889 return false; 1890 } 1891 1892 /** 1893 * Temporarily remove an entire config layer. USE WITH CARE! 1894 * 1895 * @param string config key 1896 * @param string (optional) config layer 1897 * @return bool TRUE on success, FALSE on failure 1898 * 1899 * @access public 1900 */ 1901 function removeLayer($layer) 1902 { 1903 if (isset($this->configuration[$layer])) { 1904 $this->configuration[$layer] = array(); 1905 return true; 1906 } 1907 1908 return false; 1909 } 1910 1911 /** 1912 * Stores configuration data in a layer. 1913 * 1914 * @param string config layer to store 1915 * @return bool TRUE on success, or PEAR error on failure 1916 * 1917 * @access public 1918 */ 1919 function store($layer = 'user', $data = null) 1920 { 1921 return $this->writeConfigFile(null, $layer, $data); 1922 } 1923 1924 /** 1925 * Tells what config layer that gets to define a key. 1926 * 1927 * @param string config key 1928 * @param boolean return the defining channel 1929 * 1930 * @return string|array the config layer, or an empty string if not found. 1931 * 1932 * if $returnchannel, the return is an array array('layer' => layername, 1933 * 'channel' => channelname), or an empty string if not found 1934 * 1935 * @access public 1936 */ 1937 function definedBy($key, $returnchannel = false) 1938 { 1939 foreach ($this->layers as $layer) { 1940 $channel = $this->getDefaultChannel(); 1941 if ($channel !== 'pear.php.net') { 1942 if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { 1943 if ($returnchannel) { 1944 return array('layer' => $layer, 'channel' => $channel); 1945 } 1946 return $layer; 1947 } 1948 } 1949 1950 if (isset($this->configuration[$layer][$key])) { 1951 if ($returnchannel) { 1952 return array('layer' => $layer, 'channel' => 'pear.php.net'); 1953 } 1954 return $layer; 1955 } 1956 } 1957 1958 return ''; 1959 } 1960 1961 /** 1962 * Tells whether a given key exists as a config value. 1963 * 1964 * @param string config key 1965 * @return bool whether <config key> exists in this object 1966 * 1967 * @access public 1968 */ 1969 function isDefined($key) 1970 { 1971 foreach ($this->layers as $layer) { 1972 if (isset($this->configuration[$layer][$key])) { 1973 return true; 1974 } 1975 } 1976 1977 return false; 1978 } 1979 1980 /** 1981 * Tells whether a given config layer exists. 1982 * 1983 * @param string config layer 1984 * @return bool whether <config layer> exists in this object 1985 * 1986 * @access public 1987 */ 1988 function isDefinedLayer($layer) 1989 { 1990 return isset($this->configuration[$layer]); 1991 } 1992 1993 /** 1994 * Returns the layers defined (except the 'default' one) 1995 * 1996 * @return array of the defined layers 1997 */ 1998 function getLayers() 1999 { 2000 $cf = $this->configuration; 2001 unset($cf['default']); 2002 return array_keys($cf); 2003 } 2004 2005 function apiVersion() 2006 { 2007 return '1.1'; 2008 } 2009 2010 /** 2011 * @return PEAR_Registry 2012 */ 2013 function &getRegistry($use = null) 2014 { 2015 $layer = $use === null ? 'user' : $use; 2016 if (isset($this->_registry[$layer])) { 2017 return $this->_registry[$layer]; 2018 } elseif ($use === null && isset($this->_registry['system'])) { 2019 return $this->_registry['system']; 2020 } elseif ($use === null && isset($this->_registry['default'])) { 2021 return $this->_registry['default']; 2022 } elseif ($use) { 2023 $a = false; 2024 return $a; 2025 } 2026 2027 // only go here if null was passed in 2028 echo "CRITICAL ERROR: Registry could not be initialized from any value"; 2029 exit(1); 2030 } 2031 2032 /** 2033 * This is to allow customization like the use of installroot 2034 * @param PEAR_Registry 2035 * @return bool 2036 */ 2037 function setRegistry(&$reg, $layer = 'user') 2038 { 2039 if ($this->_noRegistry) { 2040 return false; 2041 } 2042 2043 if (!in_array($layer, array('user', 'system'))) { 2044 return false; 2045 } 2046 2047 $this->_registry[$layer] = &$reg; 2048 if (is_object($reg)) { 2049 $this->_registry[$layer]->setConfig($this, false); 2050 } 2051 2052 return true; 2053 } 2054 2055 function noRegistry() 2056 { 2057 $this->_noRegistry = true; 2058 } 2059 2060 /** 2061 * @return PEAR_REST 2062 */ 2063 function &getREST($version, $options = array()) 2064 { 2065 $version = str_replace('.', '', $version); 2066 if (!class_exists($class = 'PEAR_REST_' . $version)) { 2067 require_once 'PEAR/REST/' . $version . '.php'; 2068 } 2069 2070 $remote = new $class($this, $options); 2071 return $remote; 2072 } 2073 2074 /** 2075 * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a 2076 * remote configuration file has been specified 2077 * @return PEAR_FTP|false 2078 */ 2079 function &getFTP() 2080 { 2081 if (isset($this->_ftp)) { 2082 return $this->_ftp; 2083 } 2084 2085 $a = false; 2086 return $a; 2087 } 2088 2089 static function _prependPath($path, $prepend) 2090 { 2091 if (strlen($prepend) > 0) { 2092 if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { 2093 if (preg_match('/^[a-z]:/i', $prepend)) { 2094 $prepend = substr($prepend, 2); 2095 } elseif ($prepend{0} != '\\') { 2096 $prepend = "\\$prepend"; 2097 } 2098 $path = substr($path, 0, 2) . $prepend . substr($path, 2); 2099 } else { 2100 $path = $prepend . $path; 2101 } 2102 } 2103 return $path; 2104 } 2105 2106 /** 2107 * @param string|false installation directory to prepend to all _dir variables, or false to 2108 * disable 2109 */ 2110 function setInstallRoot($root) 2111 { 2112 if (substr($root, -1) == DIRECTORY_SEPARATOR) { 2113 $root = substr($root, 0, -1); 2114 } 2115 $old = $this->_installRoot; 2116 $this->_installRoot = $root; 2117 if (($old != $root) && !$this->_noRegistry) { 2118 foreach (array_keys($this->_registry) as $layer) { 2119 if ($layer == 'ftp' || !isset($this->_registry[$layer])) { 2120 continue; 2121 } 2122 $this->_registry[$layer] = 2123 new PEAR_Registry( 2124 $this->get('php_dir', $layer, 'pear.php.net'), false, false, 2125 $this->get('metadata_dir', $layer, 'pear.php.net')); 2126 $this->_registry[$layer]->setConfig($this, false); 2127 $this->_regInitialized[$layer] = false; 2128 } 2129 } 2130 } 2131} 2132