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