3  * PEAR_Config, customized configuration handling for the PEAR Installer
 
   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
 
  18  * Required for error handling
 
  20 require_once 'PEAR.php';
 
  21 require_once 'PEAR/Registry.php';
 
  22 require_once 'PEAR/Installer/Role.php';
 
  23 require_once 'System.php';
 
  26  * Last created PEAR_Config instance.
 
  29 $GLOBALS['_PEAR_Config_instance'] = null;
 
  30 if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
 
  31     $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
 
  33     $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
 
  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_*.
 
  42 // default channel and preferred mirror is based on whether we are invoked through
 
  43 // the "pear" or the "pecl" command
 
  44 if (!defined('PEAR_RUNTYPE')) {
 
  45     define('PEAR_RUNTYPE', 'pear');
 
  48 if (PEAR_RUNTYPE == 'pear') {
 
  49     define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
 
  51     define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
 
  54 if (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'));
 
  59     define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
 
  62 // Default for master_server
 
  63 if (getenv('PHP_PEAR_MASTER_SERVER')) {
 
  64     define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
 
  66     define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
 
  69 // Default for http_proxy
 
  70 if (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'));
 
  75     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
 
  78 // Default for php_dir
 
  79 if (getenv('PHP_PEAR_INSTALL_DIR')) {
 
  80     define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
 
  82     if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
 
  83         define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
 
  85         define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
 
  89 // Default for metadata_dir
 
  90 if (getenv('PHP_PEAR_METADATA_DIR')) {
 
  91     define('PEAR_CONFIG_DEFAULT_METADATA_DIR', getenv('PHP_PEAR_METADATA_DIR'));
 
  93     define('PEAR_CONFIG_DEFAULT_METADATA_DIR', '');
 
  96 // Default for ext_dir
 
  97 if (getenv('PHP_PEAR_EXTENSION_DIR')) {
 
  98     define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
 
 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);
 
 108         define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
 
 112 // Default for doc_dir
 
 113 if (getenv('PHP_PEAR_DOC_DIR')) {
 
 114     define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
 
 116     define('PEAR_CONFIG_DEFAULT_DOC_DIR',
 
 117            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
 
 120 // Default for bin_dir
 
 121 if (getenv('PHP_PEAR_BIN_DIR')) {
 
 122     define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
 
 124     define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
 
 127 // Default for data_dir
 
 128 if (getenv('PHP_PEAR_DATA_DIR')) {
 
 129     define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
 
 131     define('PEAR_CONFIG_DEFAULT_DATA_DIR',
 
 132            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
 
 135 // Default for cfg_dir
 
 136 if (getenv('PHP_PEAR_CFG_DIR')) {
 
 137     define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
 
 139     define('PEAR_CONFIG_DEFAULT_CFG_DIR',
 
 140            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
 
 143 // Default for www_dir
 
 144 if (getenv('PHP_PEAR_WWW_DIR')) {
 
 145     define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
 
 147     define('PEAR_CONFIG_DEFAULT_WWW_DIR',
 
 148            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
 
 151 // Default for man_dir
 
 152 if (getenv('PHP_PEAR_MAN_DIR')) {
 
 153     define('PEAR_CONFIG_DEFAULT_MAN_DIR', getenv('PHP_PEAR_MAN_DIR'));
 
 155     if (defined('PHP_MANDIR')) { // Added in PHP5.3.7
 
 156         define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_MANDIR);
 
 158         define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_PREFIX . DIRECTORY_SEPARATOR .
 
 159            'local' . DIRECTORY_SEPARATOR .'man');
 
 163 // Default for test_dir
 
 164 if (getenv('PHP_PEAR_TEST_DIR')) {
 
 165     define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
 
 167     define('PEAR_CONFIG_DEFAULT_TEST_DIR',
 
 168            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
 
 171 // Default for temp_dir
 
 172 if (getenv('PHP_PEAR_TEMP_DIR')) {
 
 173     define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
 
 175     define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
 
 176            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
 
 177            DIRECTORY_SEPARATOR . 'temp');
 
 180 // Default for cache_dir
 
 181 if (getenv('PHP_PEAR_CACHE_DIR')) {
 
 182     define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
 
 184     define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
 
 185            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
 
 186            DIRECTORY_SEPARATOR . 'cache');
 
 189 // Default for download_dir
 
 190 if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
 
 191     define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
 
 193     define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
 
 194            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
 
 195            DIRECTORY_SEPARATOR . 'download');
 
 198 // Default for php_bin
 
 199 if (getenv('PHP_PEAR_PHP_BIN')) {
 
 200     define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
 
 202     define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
 
 203            DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
 
 206 // Default for verbose
 
 207 if (getenv('PHP_PEAR_VERBOSE')) {
 
 208     define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
 
 210     define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
 
 213 // Default for preferred_state
 
 214 if (getenv('PHP_PEAR_PREFERRED_STATE')) {
 
 215     define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
 
 217     define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
 
 221 if (getenv('PHP_PEAR_UMASK')) {
 
 222     define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
 
 224     define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
 
 227 // Default for cache_ttl
 
 228 if (getenv('PHP_PEAR_CACHE_TTL')) {
 
 229     define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
 
 231     define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
 
 234 // Default for sig_type
 
 235 if (getenv('PHP_PEAR_SIG_TYPE')) {
 
 236     define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
 
 238     define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
 
 241 // Default for sig_bin
 
 242 if (getenv('PHP_PEAR_SIG_BIN')) {
 
 243     define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
 
 245     define('PEAR_CONFIG_DEFAULT_SIG_BIN',
 
 247                'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
 
 250 // Default for sig_keydir
 
 251 if (getenv('PHP_PEAR_SIG_KEYDIR')) {
 
 252     define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
 
 254     define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
 
 255            PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
 
 259  * This is a class for storing configuration data, keeping track of
 
 260  * which are system-defined, user-defined or defaulted.
 
 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: 1.10.1
 
 268  * @link       http://pear.php.net/package/PEAR
 
 269  * @since      Class available since Release 0.1
 
 271 class PEAR_Config extends PEAR
 
 274      * Array of config files used.
 
 276      * @var array layer => config file
 
 283     var $layers = array();
 
 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.
 
 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').
 
 295      * @var array layer => array(keyname => value, ...)
 
 297     var $configuration = array(
 
 300         'default' => array(),
 
 304      * Configuration values that can be set for a channel
 
 306      * All other configuration values can only have a global value
 
 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'
 
 317      * Channels that can be accessed
 
 322     var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
 
 325      * This variable is used to control the directory values returned
 
 326      * @see setInstallRoot();
 
 330     var $_installRoot = false;
 
 333      * If requested, this will always refer to the registry
 
 334      * contained in php_dir
 
 337     var $_registry = array();
 
 343     var $_regInitialized = array();
 
 349     var $_noRegistry = false;
 
 352      * amount of errors found while parsing config
 
 356     var $_errorsFound = 0;
 
 357     var $_lastError = null;
 
 360      * Information about the configuration data.  Stores the type,
 
 361      * default value and a documentation string for each configuration
 
 364      * @var array layer => array(infotype => value, ...)
 
 366     var $configuration_info = array(
 
 367         // Channels/Internet Access
 
 368         'default_channel' => array(
 
 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',
 
 375         'preferred_mirror' => array(
 
 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',
 
 382         'remote_config' => array(
 
 383             'type' => 'password',
 
 385             'doc' => 'ftp url of remote configuration file to use for synchronized install',
 
 386             'prompt' => 'Remote Configuration File',
 
 387             'group' => 'Internet Access',
 
 389         'auto_discover' => array(
 
 392             'doc' => 'whether to automatically discover new channels',
 
 393             'prompt' => 'Auto-discover new Channels',
 
 394             'group' => 'Internet Access',
 
 397         'master_server' => array(
 
 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',
 
 404         'http_proxy' => array(
 
 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',
 
 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',
 
 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',
 
 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',
 
 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',
 
 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)',
 
 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)',
 
 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)',
 
 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)',
 
 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)',
 
 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)',
 
 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)',
 
 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)',
 
 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)',
 
 503         'php_prefix' => array(
 
 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)',
 
 510         'php_suffix' => array(
 
 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)',
 
 520             'doc' => 'location of php.ini in which to enable PECL extensions on install',
 
 521             'prompt' => 'php.ini location',
 
 522             'group' => 'File Locations (Advanced)',
 
 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)',
 
 535             'doc' => '(maintainers) your PEAR account name',
 
 536             'prompt' => 'PEAR username (for maintainers)',
 
 537             'group' => 'Maintainers',
 
 540             'type' => 'password',
 
 542             'doc' => '(maintainers) your PEAR account password',
 
 543             'prompt' => 'PEAR password (for maintainers)',
 
 544             'group' => 'Maintainers',
 
 549             'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
 
 550             'doc' => 'verbosity level
 
 555             'prompt' => 'Debug Log Level',
 
 556             'group' => 'Advanced',
 
 558         'preferred_state' => array(
 
 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',
 
 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',
 
 574         'cache_ttl' => array(
 
 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',
 
 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',
 
 591             'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
 
 592             'doc' => 'which package signature mechanism to use',
 
 593             'prompt' => 'Signature Handling Program',
 
 594             'group' => 'Maintainers',
 
 596         'sig_keyid' => array(
 
 599             'doc' => 'which key to use for signing with',
 
 600             'prompt' => 'Signature Key Id',
 
 601             'group' => 'Maintainers',
 
 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',
 
 610         // __channels is reserved - used for channel-specific configuration
 
 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
 
 625      * @see PEAR_Config::singleton
 
 627     function __construct($user_file = '', $system_file = '', $ftp_file = false,
 
 630         parent::__construct();
 
 631         PEAR_Installer_Role::initializeConfig($this);
 
 632         $sl = DIRECTORY_SEPARATOR;
 
 633         if (empty($user_file)) {
 
 635                 $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
 
 637                 $user_file = getenv('HOME') . $sl . '.pearrc';
 
 641         if (empty($system_file)) {
 
 642             $system_file = PEAR_CONFIG_SYSCONFDIR . $sl;
 
 644                 $system_file .= 'pearsys.ini';
 
 646                 $system_file .= 'pear.conf';
 
 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) {
 
 662         if ($system_file && @file_exists($system_file)) {
 
 663             $this->mergeConfigFile($system_file, false, 'system', $strict);
 
 664             if ($this->_errorsFound > 0) {
 
 671             $ftp_file = $this->get('remote_config');
 
 674         if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
 
 675             $this->readFTPConfigFile($ftp_file);
 
 678         foreach ($this->configuration_info as $key => $info) {
 
 679             $this->configuration['default'][$key] = $info['default'];
 
 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;
 
 691      * Return the default locations of user and system configuration files
 
 693     public static function getDefaultConfigFiles()
 
 695         $sl = DIRECTORY_SEPARATOR;
 
 698                 'user'   => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
 
 699                 'system' =>  PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
 
 704             'user'   => getenv('HOME') . $sl . '.pearrc',
 
 705             'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
 
 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
 
 715      * @param string (optional) file to read user-defined options from
 
 716      * @param string (optional) file to read system-wide defaults from
 
 718      * @return object an existing or new PEAR_Config instance
 
 720      * @see PEAR_Config::PEAR_Config
 
 722     public static function &singleton($user_file = '', $system_file = '', $strict = true)
 
 724         if (is_object($GLOBALS['_PEAR_Config_instance'])) {
 
 725             return $GLOBALS['_PEAR_Config_instance'];
 
 728         $t_conf = new PEAR_Config($user_file, $system_file, false, $strict);
 
 729         if ($t_conf->_errorsFound > 0) {
 
 730              return $t_conf->lastError;
 
 733         $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
 
 734         return $GLOBALS['_PEAR_Config_instance'];
 
 738      * Determine whether any configuration files have been detected, and whether a
 
 739      * registry object can be retrieved from this configuration.
 
 741      * @since PEAR 1.4.0a1
 
 743     function validConfiguration()
 
 745         if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
 
 753      * Reads configuration data from a file.  All existing values in
 
 754      * the config layer are discarded and replaced with data from the
 
 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
 
 761     function readConfigFile($file = null, $layer = 'user', $strict = true)
 
 763         if (empty($this->files[$layer])) {
 
 764             return $this->raiseError("unknown config layer `$layer'");
 
 767         if ($file === null) {
 
 768             $file = $this->files[$layer];
 
 771         $data = $this->_readConfigDataFrom($file);
 
 772         if (PEAR::isError($data)) {
 
 777             $this->_errorsFound++;
 
 778             $this->lastError = $data;
 
 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;
 
 794             unset($this->_registry[$layer]);
 
 800      * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
 
 801      * @return true|PEAR_Error
 
 803     function readFTPConfigFile($path)
 
 805         do { // poor man's try
 
 806             if (!class_exists('PEAR_FTP')) {
 
 807                 if (!class_exists('PEAR_Common')) {
 
 808                     require_once 'PEAR/Common.php';
 
 810                 if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
 
 811                     require_once 'PEAR/FTP.php';
 
 815             if (!class_exists('PEAR_FTP')) {
 
 816                 return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
 
 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();
 
 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();
 
 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)) {
 
 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])) {
 
 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: ' .
 
 867         } while (false); // poor man's catch
 
 868         unset($this->files['ftp']);
 
 869         return PEAR::raiseError('no remote host specified');
 
 873      * Reads the existing configurations and creates the _channels array from it
 
 875     function _setupChannels()
 
 877         $set = array_flip(array_values($this->_channels));
 
 878         foreach ($this->configuration as $layer => $data) {
 
 880             if (isset($data['__channels']) && is_array($data['__channels'])) {
 
 881                 foreach ($data['__channels'] as $channel => $info) {
 
 882                     $set[$channel] = $i++;
 
 886         $this->_channels = array_values(array_flip($set));
 
 887         $this->setChannels($this->_channels);
 
 890     function deleteChannel($channel)
 
 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]);
 
 899         $this->_channels = array_flip($this->_channels);
 
 900         unset($this->_channels[$ch]);
 
 901         $this->_channels = array_flip($this->_channels);
 
 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
 
 914     function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
 
 916         if (empty($this->files[$layer])) {
 
 917             return $this->raiseError("unknown config layer `$layer'");
 
 920         if ($file === null) {
 
 921             $file = $this->files[$layer];
 
 924         $data = $this->_readConfigDataFrom($file);
 
 925         if (PEAR::isError($data)) {
 
 930             $this->_errorsFound++;
 
 931             $this->lastError = $data;
 
 936         $this->_decodeInput($data);
 
 938             $this->configuration[$layer] =
 
 939                 PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
 
 941             $this->configuration[$layer] =
 
 942                 PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
 
 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;
 
 953             unset($this->_registry[$layer]);
 
 963     public static function arrayMergeRecursive($arr2, $arr1)
 
 966         foreach ($arr2 as $key => $data) {
 
 967             if (!isset($arr1[$key])) {
 
 972             if (is_array($data)) {
 
 973                 if (!is_array($arr1[$key])) {
 
 974                     $ret[$key] = $arr1[$key];
 
 978                 $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
 
 983         return array_merge($ret, $arr1);
 
 987      * Writes data into a config layer from a file.
 
 989      * @param string|null file to read from, or null for default
 
 990      * @param string config layer to insert data into ('user' or
 
 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
 
 995     function writeConfigFile($file = null, $layer = 'user', $data = null)
 
 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)) {
 
1008         if (empty($this->files[$layer])) {
 
1009             return $this->raiseError("unknown config file type `$layer'");
 
1012         if ($file === null) {
 
1013             $file = $this->files[$layer];
 
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));
 
1023         if (file_exists($file) && is_file($file) && !is_writeable($file)) {
 
1024             return $this->raiseError("no write access to $file!");
 
1027         $fp = @fopen($file, "w");
 
1029             return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
 
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)");
 
1040      * Reads configuration data from a file and returns the parsed data
 
1043      * @param string file to read from
 
1044      * @return array configuration data or a PEAR error on failure
 
1047     function _readConfigDataFrom($file)
 
1050         if (file_exists($file)) {
 
1051             $fp = @fopen($file, "r");
 
1055             return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
 
1058         $size = filesize($file);
 
1060         $contents = file_get_contents($file);
 
1061         if (empty($contents)) {
 
1062             return $this->raiseError('Configuration file "' . $file . '" is empty');
 
1066         if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
 
1067             $version = $matches[1];
 
1068             $contents = substr($contents, strlen($matches[0]));
 
1070             // Museum config file
 
1071             if (substr($contents,0,2) == 'a:') {
 
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);
 
1082             if (!is_array($data) && !$data) {
 
1083                 if ($contents == serialize(false)) {
 
1086                     $err = $this->raiseError("PEAR_Config: bad data in $file");
 
1090             if (!is_array($data)) {
 
1091                 if (strlen(trim($contents)) > 0) {
 
1092                     $error = "PEAR_Config: bad data in $file";
 
1093                     $err = $this->raiseError($error);
 
1099         // add parsing of newer formats here...
 
1101             $err = $this->raiseError("$file: unknown version `$version'");
 
1109     * Gets the file used for storing the config for a layer
 
1111     * @param string $layer 'user' or 'system'
 
1113     function getConfFile($layer)
 
1115         return $this->files[$layer];
 
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
 
1124     function _addConfigVars($class, $vars)
 
1126         static $called = array();
 
1127         if (isset($called[$class])) {
 
1131         $called[$class] = 1;
 
1132         if (count($vars) > 3) {
 
1133             return $this->raiseError('Roles can only define 3 new config variables or less');
 
1136         foreach ($vars as $name => $var) {
 
1137             if (!is_array($var)) {
 
1138                 return $this->raiseError('Configuration information must be an array');
 
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');
 
1149             if (!isset($var['default'])) {
 
1150                 return $this->raiseError(
 
1151                     'Configuration information must contain a default value ("default" index)');
 
1154             if (is_array($var['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 "' .
 
1167                         $real_default .= constant($val);
 
1168                     } elseif (isset($this->configuration_info[$config_var])) {
 
1170                             $this->configuration_info[$config_var]['default'];
 
1172                         return $this->raiseError(
 
1173                             'Unknown request for "' . $config_var . '" value in ' .
 
1174                             'default value for configuration variable "' .
 
1178                 $var['default'] = $real_default;
 
1181             if ($var['type'] == 'integer') {
 
1182                 $var['default'] = (integer) $var['default'];
 
1185             if (!isset($var['doc'])) {
 
1186                 return $this->raiseError(
 
1187                     'Configuration information must contain a summary ("doc" index)');
 
1190             if (!isset($var['prompt'])) {
 
1191                 return $this->raiseError(
 
1192                     'Configuration information must contain a simple prompt ("prompt" index)');
 
1195             if (!isset($var['group'])) {
 
1196                 return $this->raiseError(
 
1197                     'Configuration information must contain a simple group ("group" index)');
 
1200             if (isset($this->configuration_info[$name])) {
 
1201                 return $this->raiseError('Configuration variable "' . $name .
 
1202                     '" already exists');
 
1205             $this->configuration_info[$name] = $var;
 
1206             // fix bug #7351: setting custom config variable in a channel fails
 
1207             $this->_channelConfigInfo[] = $name;
 
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.
 
1218      * @param array (reference) array to encode values in
 
1219      * @return bool TRUE on success
 
1222     function _encodeOutput(&$data)
 
1224         foreach ($data as $key => $value) {
 
1225             if ($key == '__channels') {
 
1226                 foreach ($data['__channels'] as $channel => $blah) {
 
1227                     $this->_encodeOutput($data['__channels'][$channel]);
 
1231             if (!isset($this->configuration_info[$key])) {
 
1235             $type = $this->configuration_info[$key]['type'];
 
1237                 // we base64-encode passwords so they are at least
 
1238                 // not shown in plain by accident
 
1240                     $data[$key] = base64_encode($data[$key]);
 
1244                     $data[$key] = octdec($data[$key]);
 
1254      * Decodes/unscrambles configuration data after reading from files.
 
1256      * @param array (reference) array to encode values in
 
1257      * @return bool TRUE on success
 
1260      * @see PEAR_Config::_encodeOutput
 
1262     function _decodeInput(&$data)
 
1264         if (!is_array($data)) {
 
1268         foreach ($data as $key => $value) {
 
1269             if ($key == '__channels') {
 
1270                 foreach ($data['__channels'] as $channel => $blah) {
 
1271                     $this->_decodeInput($data['__channels'][$channel]);
 
1275             if (!isset($this->configuration_info[$key])) {
 
1279             $type = $this->configuration_info[$key]['type'];
 
1282                     $data[$key] = base64_decode($data[$key]);
 
1286                     $data[$key] = decoct($data[$key]);
 
1296      * Retrieve the default channel.
 
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
 
1303     function getDefaultChannel($layer = null)
 
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'];
 
1313         } elseif (isset($this->configuration[$layer]['default_channel'])) {
 
1314             $ret = $this->configuration[$layer]['default_channel'];
 
1317         if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
 
1318             $ret = 'pecl.php.net';
 
1322             if ($ret != 'pear.php.net') {
 
1323                 $this->_lazyChannelSetup();
 
1329         return PEAR_CONFIG_DEFAULT_CHANNEL;
 
1333      * Returns a configuration value, prioritizing layers as per the
 
1336      * @param string config key
 
1337      * @return mixed the config value, or NULL if not found
 
1340     function get($key, $layer = null, $channel = false)
 
1342         if (!isset($this->configuration_info[$key])) {
 
1346         if ($key == '__channels') {
 
1350         if ($key == 'default_channel') {
 
1351             return $this->getDefaultChannel($layer);
 
1355             $channel = $this->getDefaultChannel();
 
1356         } elseif ($channel != 'pear.php.net') {
 
1357             $this->_lazyChannelSetup();
 
1359         $channel = strtolower($channel);
 
1361         $test = (in_array($key, $this->_channelConfigInfo)) ?
 
1362             $this->_getChannelValue($key, $layer, $channel) :
 
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);
 
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);
 
1387                     if ($key == 'preferred_mirror') {
 
1388                         $reg = &$this->getRegistry();
 
1389                         if (is_object($reg)) {
 
1390                             $chan = $reg->getChannel($channel);
 
1391                             if (PEAR::isError($chan)) {
 
1395                             if (!$chan->getMirror($test) && $chan->getName() != $test) {
 
1396                                 return $channel; // mirror does not exist
 
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);
 
1413             if ($key == 'preferred_mirror') {
 
1414                 $reg = &$this->getRegistry();
 
1415                 if (is_object($reg)) {
 
1416                     $chan = $reg->getChannel($channel);
 
1417                     if (PEAR::isError($chan)) {
 
1421                     if (!$chan->getMirror($test) && $chan->getName() != $test) {
 
1422                         return $channel; // mirror does not exist
 
1434      * Returns a channel-specific configuration value, prioritizing layers as per the
 
1437      * @param string config key
 
1438      * @return mixed the config value, or NULL if not found
 
1441     function _getChannelValue($key, $layer, $channel)
 
1443         if ($key == '__channels' || $channel == 'pear.php.net') {
 
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];
 
1455         } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
 
1456             $ret = $this->configuration[$layer]['__channels'][$channel][$key];
 
1459         if ($key != 'preferred_mirror') {
 
1464         if ($ret !== null) {
 
1465             $reg = &$this->getRegistry($layer);
 
1466             if (is_object($reg)) {
 
1467                 $chan = $reg->getChannel($channel);
 
1468                 if (PEAR::isError($chan)) {
 
1472                 if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
 
1473                     return $channel; // mirror does not exist
 
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
 
1485         return $this->getDefaultChannel($layer);
 
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.
 
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
 
1500     function set($key, $value, $layer = 'user', $channel = false)
 
1502         if ($key == '__channels') {
 
1506         if (!isset($this->configuration[$layer])) {
 
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);
 
1518         if ($key == 'preferred_mirror') {
 
1519             if ($channel == '__uri') {
 
1520                 return false; // can't set the __uri pseudo-channel's mirror
 
1523             $reg = &$this->getRegistry($layer);
 
1524             if (is_object($reg)) {
 
1525                 $chan = $reg->getChannel($channel ? $channel : 'pear.php.net');
 
1526                 if (PEAR::isError($chan)) {
 
1530                 if (!$chan->getMirror($value) && $chan->getName() != $value) {
 
1531                     return false; // mirror does not exist
 
1536         if (!isset($this->configuration_info[$key])) {
 
1540         extract($this->configuration_info[$key]);
 
1543                 $value = (int)$value;
 
1546                 // If a valid_set is specified, require the value to
 
1547                 // be in the set.  If there is no valid_set, accept
 
1551                     if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
 
1552                         (key($valid_set) !== 0 && empty($valid_set[$value])))
 
1562             $channel = $this->get('default_channel', null, 'pear.php.net');
 
1565         if (!in_array($channel, $this->_channels)) {
 
1566             $this->_lazyChannelSetup($layer);
 
1567             $reg = &$this->getRegistry($layer);
 
1569                 $channel = $reg->channelName($channel);
 
1572             if (!in_array($channel, $this->_channels)) {
 
1577         if ($channel != 'pear.php.net') {
 
1578             if (in_array($key, $this->_channelConfigInfo)) {
 
1579                 $this->configuration[$layer]['__channels'][$channel][$key] = $value;
 
1586         if ($key == 'default_channel') {
 
1588                 $reg = &$this->getRegistry($layer);
 
1590                     $reg = &$this->getRegistry();
 
1595                 $value = $reg->channelName($value);
 
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);
 
1616     function _lazyChannelSetup($uselayer = false)
 
1618         if ($this->_noRegistry) {
 
1623         foreach ($this->_registry as $layer => $p) {
 
1624             if ($uselayer && $uselayer != $layer) {
 
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
 
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;
 
1643                         unset($this->_registry[$layer]);
 
1648                 $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
 
1649                 $this->_regInitialized[$layer] = true;
 
1656      * Set the list of channels.
 
1658      * This should be set via a call to {@link PEAR_Registry::listChannels()}
 
1661      * @return bool success of operation
 
1663     function setChannels($channels, $merge = false)
 
1665         if (!is_array($channels)) {
 
1670             $this->_channels = array_merge($this->_channels, $channels);
 
1672             $this->_channels = $channels;
 
1675         foreach ($channels as $channel) {
 
1676             $channel = strtolower($channel);
 
1677             if ($channel == 'pear.php.net') {
 
1681             foreach ($this->layers as $layer) {
 
1682                 if (!isset($this->configuration[$layer]['__channels'])) {
 
1683                     $this->configuration[$layer]['__channels'] = array();
 
1685                 if (!isset($this->configuration[$layer]['__channels'][$channel])
 
1686                       || !is_array($this->configuration[$layer]['__channels'][$channel])) {
 
1687                     $this->configuration[$layer]['__channels'][$channel] = array();
 
1696      * Get the type of a config value.
 
1698      * @param string  config key
 
1700      * @return string type, one of "string", "integer", "file",
 
1701      * "directory", "set" or "password".
 
1706     function getType($key)
 
1708         if (isset($this->configuration_info[$key])) {
 
1709             return $this->configuration_info[$key]['type'];
 
1715      * Get the documentation for a config value.
 
1717      * @param string  config key
 
1718      * @return string documentation string
 
1723     function getDocs($key)
 
1725         if (isset($this->configuration_info[$key])) {
 
1726             return $this->configuration_info[$key]['doc'];
 
1733      * Get the short documentation for a config value.
 
1735      * @param string  config key
 
1736      * @return string short documentation string
 
1741     function getPrompt($key)
 
1743         if (isset($this->configuration_info[$key])) {
 
1744             return $this->configuration_info[$key]['prompt'];
 
1751      * Get the parameter group for a config key.
 
1753      * @param string  config key
 
1754      * @return string parameter group
 
1759     function getGroup($key)
 
1761         if (isset($this->configuration_info[$key])) {
 
1762             return $this->configuration_info[$key]['group'];
 
1769      * Get the list of parameter groups.
 
1771      * @return array list of parameter groups
 
1776     function getGroups()
 
1779         foreach ($this->configuration_info as $key => $info) {
 
1780             $tmp[$info['group']] = 1;
 
1783         return array_keys($tmp);
 
1787      * Get the list of the parameters in a group.
 
1789      * @param string $group parameter group
 
1790      * @return array list of parameters in $group
 
1795     function getGroupKeys($group)
 
1798         foreach ($this->configuration_info as $key => $info) {
 
1799             if ($info['group'] == $group) {
 
1808      * Get the list of allowed set values for a config value.  Returns
 
1809      * NULL for config values that are not sets.
 
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
 
1818     function getSetValues($key)
 
1820         if (isset($this->configuration_info[$key]) &&
 
1821             isset($this->configuration_info[$key]['type']) &&
 
1822             $this->configuration_info[$key]['type'] == 'set')
 
1824             $valid_set = $this->configuration_info[$key]['valid_set'];
 
1826             if (key($valid_set) === 0) {
 
1830             return array_keys($valid_set);
 
1837      * Get all the current config keys.
 
1839      * @return array simple array of config keys
 
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);
 
1854             unset($test['__channels']);
 
1855             $keys = array_merge($keys, $test);
 
1858         return array_keys($keys);
 
1862      * Remove the a config key from a specific config layer.
 
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
 
1871     function remove($key, $layer = 'user', $channel = null)
 
1873         if ($channel === null) {
 
1874             $channel = $this->getDefaultChannel();
 
1877         if ($channel !== 'pear.php.net') {
 
1878             if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
 
1879                 unset($this->configuration[$layer]['__channels'][$channel][$key]);
 
1884         if (isset($this->configuration[$layer][$key])) {
 
1885             unset($this->configuration[$layer][$key]);
 
1893      * Temporarily remove an entire config layer.  USE WITH CARE!
 
1895      * @param string config key
 
1896      * @param string (optional) config layer
 
1897      * @return bool TRUE on success, FALSE on failure
 
1901     function removeLayer($layer)
 
1903         if (isset($this->configuration[$layer])) {
 
1904             $this->configuration[$layer] = array();
 
1912      * Stores configuration data in a layer.
 
1914      * @param string config layer to store
 
1915      * @return bool TRUE on success, or PEAR error on failure
 
1919     function store($layer = 'user', $data = null)
 
1921         return $this->writeConfigFile(null, $layer, $data);
 
1925      * Tells what config layer that gets to define a key.
 
1927      * @param string config key
 
1928      * @param boolean return the defining channel
 
1930      * @return string|array the config layer, or an empty string if not found.
 
1932      *         if $returnchannel, the return is an array array('layer' => layername,
 
1933      *         'channel' => channelname), or an empty string if not found
 
1937     function definedBy($key, $returnchannel = false)
 
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);
 
1950             if (isset($this->configuration[$layer][$key])) {
 
1951                 if ($returnchannel) {
 
1952                     return array('layer' => $layer, 'channel' => 'pear.php.net');
 
1962      * Tells whether a given key exists as a config value.
 
1964      * @param string config key
 
1965      * @return bool whether <config key> exists in this object
 
1969     function isDefined($key)
 
1971         foreach ($this->layers as $layer) {
 
1972             if (isset($this->configuration[$layer][$key])) {
 
1981      * Tells whether a given config layer exists.
 
1983      * @param string config layer
 
1984      * @return bool whether <config layer> exists in this object
 
1988     function isDefinedLayer($layer)
 
1990         return isset($this->configuration[$layer]);
 
1994      * Returns the layers defined (except the 'default' one)
 
1996      * @return array of the defined layers
 
1998     function getLayers()
 
2000         $cf = $this->configuration;
 
2001         unset($cf['default']);
 
2002         return array_keys($cf);
 
2005     function apiVersion()
 
2011      * @return PEAR_Registry
 
2013     function &getRegistry($use = null)
 
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'];
 
2027         // only go here if null was passed in
 
2028         echo "CRITICAL ERROR: Registry could not be initialized from any value";
 
2033      * This is to allow customization like the use of installroot
 
2034      * @param PEAR_Registry
 
2037     function setRegistry(&$reg, $layer = 'user')
 
2039         if ($this->_noRegistry) {
 
2043         if (!in_array($layer, array('user', 'system'))) {
 
2047         $this->_registry[$layer] = &$reg;
 
2048         if (is_object($reg)) {
 
2049             $this->_registry[$layer]->setConfig($this, false);
 
2055     function noRegistry()
 
2057         $this->_noRegistry = true;
 
2063     function &getREST($version, $options = array())
 
2065         $version = str_replace('.', '', $version);
 
2066         if (!class_exists($class = 'PEAR_REST_' . $version)) {
 
2067             require_once 'PEAR/REST/' . $version . '.php';
 
2070         $remote = new $class($this, $options);
 
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
 
2081         if (isset($this->_ftp)) {
 
2089     function _prependPath($path, $prepend)
 
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";
 
2098                 $path = substr($path, 0, 2) . $prepend . substr($path, 2);
 
2100                 $path = $prepend . $path;
 
2107      * @param string|false installation directory to prepend to all _dir variables, or false to
 
2110     function setInstallRoot($root)
 
2112         if (substr($root, -1) == DIRECTORY_SEPARATOR) {
 
2113             $root = substr($root, 0, -1);
 
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])) {
 
2122                 $this->_registry[$layer] =
 
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;