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 * @version CVS: $Id: Config.php 313023 2011-07-06 19:17:11Z dufuz $
14 * @link http://pear.php.net/package/PEAR
15 * @since File available since Release 0.1
19 * Required for error handling
21 require_once 'PEAR.php';
22 require_once 'PEAR/Registry.php';
23 require_once 'PEAR/Installer/Role.php';
24 require_once 'System.php';
27 * Last created PEAR_Config instance.
30 $GLOBALS['_PEAR_Config_instance'] = null;
31 if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
32 $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
34 $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
37 // Below we define constants with default values for all configuration
38 // parameters except username/password. All of them can have their
39 // defaults set through environment variables. The reason we use the
40 // PHP_ prefix is for some security, PHP protects environment
41 // variables starting with PHP_*.
43 // default channel and preferred mirror is based on whether we are invoked through
44 // the "pear" or the "pecl" command
45 if (!defined('PEAR_RUNTYPE')) {
46 define('PEAR_RUNTYPE', 'pear');
49 if (PEAR_RUNTYPE == 'pear') {
50 define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
52 define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
55 if (getenv('PHP_PEAR_SYSCONF_DIR')) {
56 define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
57 } elseif (getenv('SystemRoot')) {
58 define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
60 define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
63 // Default for master_server
64 if (getenv('PHP_PEAR_MASTER_SERVER')) {
65 define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
67 define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
70 // Default for http_proxy
71 if (getenv('PHP_PEAR_HTTP_PROXY')) {
72 define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
73 } elseif (getenv('http_proxy')) {
74 define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
76 define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
79 // Default for php_dir
80 if (getenv('PHP_PEAR_INSTALL_DIR')) {
81 define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
83 if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
84 define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
86 define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
90 // Default for ext_dir
91 if (getenv('PHP_PEAR_EXTENSION_DIR')) {
92 define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
94 if (ini_get('extension_dir')) {
95 define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
96 } elseif (defined('PEAR_EXTENSION_DIR') &&
97 file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
98 define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
99 } elseif (defined('PHP_EXTENSION_DIR')) {
100 define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
102 define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
106 // Default for doc_dir
107 if (getenv('PHP_PEAR_DOC_DIR')) {
108 define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
110 define('PEAR_CONFIG_DEFAULT_DOC_DIR',
111 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
114 // Default for bin_dir
115 if (getenv('PHP_PEAR_BIN_DIR')) {
116 define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
118 define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
121 // Default for data_dir
122 if (getenv('PHP_PEAR_DATA_DIR')) {
123 define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
125 define('PEAR_CONFIG_DEFAULT_DATA_DIR',
126 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
129 // Default for cfg_dir
130 if (getenv('PHP_PEAR_CFG_DIR')) {
131 define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
133 define('PEAR_CONFIG_DEFAULT_CFG_DIR',
134 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
137 // Default for www_dir
138 if (getenv('PHP_PEAR_WWW_DIR')) {
139 define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
141 define('PEAR_CONFIG_DEFAULT_WWW_DIR',
142 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
145 // Default for test_dir
146 if (getenv('PHP_PEAR_TEST_DIR')) {
147 define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
149 define('PEAR_CONFIG_DEFAULT_TEST_DIR',
150 $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
153 // Default for temp_dir
154 if (getenv('PHP_PEAR_TEMP_DIR')) {
155 define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
157 define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
158 System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
159 DIRECTORY_SEPARATOR . 'temp');
162 // Default for cache_dir
163 if (getenv('PHP_PEAR_CACHE_DIR')) {
164 define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
166 define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
167 System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
168 DIRECTORY_SEPARATOR . 'cache');
171 // Default for download_dir
172 if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
173 define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
175 define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
176 System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
177 DIRECTORY_SEPARATOR . 'download');
180 // Default for php_bin
181 if (getenv('PHP_PEAR_PHP_BIN')) {
182 define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
184 define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
185 DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
188 // Default for verbose
189 if (getenv('PHP_PEAR_VERBOSE')) {
190 define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
192 define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
195 // Default for preferred_state
196 if (getenv('PHP_PEAR_PREFERRED_STATE')) {
197 define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
199 define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
203 if (getenv('PHP_PEAR_UMASK')) {
204 define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
206 define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
209 // Default for cache_ttl
210 if (getenv('PHP_PEAR_CACHE_TTL')) {
211 define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
213 define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
216 // Default for sig_type
217 if (getenv('PHP_PEAR_SIG_TYPE')) {
218 define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
220 define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
223 // Default for sig_bin
224 if (getenv('PHP_PEAR_SIG_BIN')) {
225 define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
227 define('PEAR_CONFIG_DEFAULT_SIG_BIN',
229 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
232 // Default for sig_keydir
233 if (getenv('PHP_PEAR_SIG_KEYDIR')) {
234 define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
236 define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
237 PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
241 * This is a class for storing configuration data, keeping track of
242 * which are system-defined, user-defined or defaulted.
245 * @author Stig Bakken <ssb@php.net>
246 * @author Greg Beaver <cellog@php.net>
247 * @copyright 1997-2009 The Authors
248 * @license http://opensource.org/licenses/bsd-license.php New BSD License
249 * @version Release: 1.9.4
250 * @link http://pear.php.net/package/PEAR
251 * @since Class available since Release 0.1
253 class PEAR_Config extends PEAR
256 * Array of config files used.
258 * @var array layer => config file
265 var $layers = array();
268 * Configuration data, two-dimensional array where the first
269 * dimension is the config layer ('user', 'system' and 'default'),
270 * and the second dimension is keyname => value.
272 * The order in the first dimension is important! Earlier
273 * layers will shadow later ones when a config value is
274 * requested (if a 'user' value exists, it will be returned first,
275 * then 'system' and finally 'default').
277 * @var array layer => array(keyname => value, ...)
279 var $configuration = array(
282 'default' => array(),
286 * Configuration values that can be set for a channel
288 * All other configuration values can only have a global value
292 var $_channelConfigInfo = array(
293 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir',
294 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username',
295 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini'
299 * Channels that can be accessed
304 var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
307 * This variable is used to control the directory values returned
308 * @see setInstallRoot();
312 var $_installRoot = false;
315 * If requested, this will always refer to the registry
316 * contained in php_dir
319 var $_registry = array();
325 var $_regInitialized = array();
331 var $_noRegistry = false;
334 * amount of errors found while parsing config
338 var $_errorsFound = 0;
339 var $_lastError = null;
342 * Information about the configuration data. Stores the type,
343 * default value and a documentation string for each configuration
346 * @var array layer => array(infotype => value, ...)
348 var $configuration_info = array(
349 // Channels/Internet Access
350 'default_channel' => array(
352 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
353 'doc' => 'the default channel to use for all non explicit commands',
354 'prompt' => 'Default Channel',
355 'group' => 'Internet Access',
357 'preferred_mirror' => array(
359 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
360 'doc' => 'the default server or mirror to use for channel actions',
361 'prompt' => 'Default Channel Mirror',
362 'group' => 'Internet Access',
364 'remote_config' => array(
365 'type' => 'password',
367 'doc' => 'ftp url of remote configuration file to use for synchronized install',
368 'prompt' => 'Remote Configuration File',
369 'group' => 'Internet Access',
371 'auto_discover' => array(
374 'doc' => 'whether to automatically discover new channels',
375 'prompt' => 'Auto-discover new Channels',
376 'group' => 'Internet Access',
379 'master_server' => array(
381 'default' => 'pear.php.net',
382 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
383 'prompt' => 'PEAR server [DEPRECATED]',
384 'group' => 'Internet Access',
386 'http_proxy' => array(
388 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
389 'doc' => 'HTTP proxy (host:port) to use when downloading packages',
390 'prompt' => 'HTTP Proxy Server Address',
391 'group' => 'Internet Access',
395 'type' => 'directory',
396 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
397 'doc' => 'directory where .php files are installed',
398 'prompt' => 'PEAR directory',
399 'group' => 'File Locations',
402 'type' => 'directory',
403 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
404 'doc' => 'directory where loadable extensions are installed',
405 'prompt' => 'PHP extension directory',
406 'group' => 'File Locations',
409 'type' => 'directory',
410 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
411 'doc' => 'directory where documentation is installed',
412 'prompt' => 'PEAR documentation directory',
413 'group' => 'File Locations',
416 'type' => 'directory',
417 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
418 'doc' => 'directory where executables are installed',
419 'prompt' => 'PEAR executables directory',
420 'group' => 'File Locations',
423 'type' => 'directory',
424 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
425 'doc' => 'directory where data files are installed',
426 'prompt' => 'PEAR data directory',
427 'group' => 'File Locations (Advanced)',
430 'type' => 'directory',
431 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR,
432 'doc' => 'directory where modifiable configuration files are installed',
433 'prompt' => 'PEAR configuration file directory',
434 'group' => 'File Locations (Advanced)',
437 'type' => 'directory',
438 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR,
439 'doc' => 'directory where www frontend files (html/js) are installed',
440 'prompt' => 'PEAR www files directory',
441 'group' => 'File Locations (Advanced)',
444 'type' => 'directory',
445 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
446 'doc' => 'directory where regression tests are installed',
447 'prompt' => 'PEAR test directory',
448 'group' => 'File Locations (Advanced)',
450 'cache_dir' => array(
451 'type' => 'directory',
452 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
453 'doc' => 'directory which is used for web service cache',
454 'prompt' => 'PEAR Installer cache directory',
455 'group' => 'File Locations (Advanced)',
458 'type' => 'directory',
459 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
460 'doc' => 'directory which is used for all temp files',
461 'prompt' => 'PEAR Installer temp directory',
462 'group' => 'File Locations (Advanced)',
464 'download_dir' => array(
465 'type' => 'directory',
466 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR,
467 'doc' => 'directory which is used for all downloaded files',
468 'prompt' => 'PEAR Installer download directory',
469 'group' => 'File Locations (Advanced)',
473 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
474 'doc' => 'PHP CLI/CGI binary for executing scripts',
475 'prompt' => 'PHP CLI/CGI binary',
476 'group' => 'File Locations (Advanced)',
478 'php_prefix' => array(
481 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs',
482 'prompt' => '--program-prefix passed to PHP\'s ./configure',
483 'group' => 'File Locations (Advanced)',
485 'php_suffix' => array(
488 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs',
489 'prompt' => '--program-suffix passed to PHP\'s ./configure',
490 'group' => 'File Locations (Advanced)',
495 'doc' => 'location of php.ini in which to enable PECL extensions on install',
496 'prompt' => 'php.ini location',
497 'group' => 'File Locations (Advanced)',
503 'doc' => '(maintainers) your PEAR account name',
504 'prompt' => 'PEAR username (for maintainers)',
505 'group' => 'Maintainers',
508 'type' => 'password',
510 'doc' => '(maintainers) your PEAR account password',
511 'prompt' => 'PEAR password (for maintainers)',
512 'group' => 'Maintainers',
517 'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
518 'doc' => 'verbosity level
523 'prompt' => 'Debug Log Level',
524 'group' => 'Advanced',
526 'preferred_state' => array(
528 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
529 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
530 'valid_set' => array(
531 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
532 'prompt' => 'Preferred Package State',
533 'group' => 'Advanced',
537 'default' => PEAR_CONFIG_DEFAULT_UMASK,
538 'doc' => 'umask used when creating files (Unix-like systems only)',
539 'prompt' => 'Unix file mask',
540 'group' => 'Advanced',
542 'cache_ttl' => array(
544 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
545 'doc' => 'amount of secs where the local cache is used and not updated',
546 'prompt' => 'Cache TimeToLive',
547 'group' => 'Advanced',
551 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
552 'doc' => 'which package signature mechanism to use',
553 'valid_set' => array('gpg'),
554 'prompt' => 'Package Signature Type',
555 'group' => 'Maintainers',
559 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
560 'doc' => 'which package signature mechanism to use',
561 'prompt' => 'Signature Handling Program',
562 'group' => 'Maintainers',
564 'sig_keyid' => array(
567 'doc' => 'which key to use for signing with',
568 'prompt' => 'Signature Key Id',
569 'group' => 'Maintainers',
571 'sig_keydir' => array(
572 'type' => 'directory',
573 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
574 'doc' => 'directory where signature keys are located',
575 'prompt' => 'Signature Key Directory',
576 'group' => 'Maintainers',
578 // __channels is reserved - used for channel-specific configuration
584 * @param string file to read user-defined options from
585 * @param string file to read system-wide defaults from
586 * @param bool determines whether a registry object "follows"
587 * the value of php_dir (is automatically created
588 * and moved when php_dir is changed)
589 * @param bool if true, fails if configuration files cannot be loaded
593 * @see PEAR_Config::singleton
595 function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false,
599 PEAR_Installer_Role::initializeConfig($this);
600 $sl = DIRECTORY_SEPARATOR;
601 if (empty($user_file)) {
603 $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
605 $user_file = getenv('HOME') . $sl . '.pearrc';
609 if (empty($system_file)) {
610 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl;
612 $system_file .= 'pearsys.ini';
614 $system_file .= 'pear.conf';
618 $this->layers = array_keys($this->configuration);
619 $this->files['user'] = $user_file;
620 $this->files['system'] = $system_file;
621 if ($user_file && file_exists($user_file)) {
622 $this->pushErrorHandling(PEAR_ERROR_RETURN);
623 $this->readConfigFile($user_file, 'user', $strict);
624 $this->popErrorHandling();
625 if ($this->_errorsFound > 0) {
630 if ($system_file && @file_exists($system_file)) {
631 $this->mergeConfigFile($system_file, false, 'system', $strict);
632 if ($this->_errorsFound > 0) {
639 $ftp_file = $this->get('remote_config');
642 if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
643 $this->readFTPConfigFile($ftp_file);
646 foreach ($this->configuration_info as $key => $info) {
647 $this->configuration['default'][$key] = $info['default'];
650 $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']);
651 $this->_registry['default']->setConfig($this, false);
652 $this->_regInitialized['default'] = false;
653 //$GLOBALS['_PEAR_Config_instance'] = &$this;
657 * Return the default locations of user and system configuration files
660 function getDefaultConfigFiles()
662 $sl = DIRECTORY_SEPARATOR;
665 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
666 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
671 'user' => getenv('HOME') . $sl . '.pearrc',
672 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
677 * Static singleton method. If you want to keep only one instance
678 * of this class in use, this method will give you a reference to
679 * the last created PEAR_Config object if one exists, or create a
682 * @param string (optional) file to read user-defined options from
683 * @param string (optional) file to read system-wide defaults from
685 * @return object an existing or new PEAR_Config instance
689 * @see PEAR_Config::PEAR_Config
691 function &singleton($user_file = '', $system_file = '', $strict = true)
693 if (is_object($GLOBALS['_PEAR_Config_instance'])) {
694 return $GLOBALS['_PEAR_Config_instance'];
697 $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict);
698 if ($t_conf->_errorsFound > 0) {
699 return $t_conf->lastError;
702 $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
703 return $GLOBALS['_PEAR_Config_instance'];
707 * Determine whether any configuration files have been detected, and whether a
708 * registry object can be retrieved from this configuration.
710 * @since PEAR 1.4.0a1
712 function validConfiguration()
714 if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
722 * Reads configuration data from a file. All existing values in
723 * the config layer are discarded and replaced with data from the
725 * @param string file to read from, if NULL or not specified, the
726 * last-used file for the same layer (second param) is used
727 * @param string config layer to insert data into ('user' or 'system')
728 * @return bool TRUE on success or a PEAR error on failure
730 function readConfigFile($file = null, $layer = 'user', $strict = true)
732 if (empty($this->files[$layer])) {
733 return $this->raiseError("unknown config layer `$layer'");
736 if ($file === null) {
737 $file = $this->files[$layer];
740 $data = $this->_readConfigDataFrom($file);
741 if (PEAR::isError($data)) {
746 $this->_errorsFound++;
747 $this->lastError = $data;
752 $this->files[$layer] = $file;
753 $this->_decodeInput($data);
754 $this->configuration[$layer] = $data;
755 $this->_setupChannels();
756 if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
757 $this->_registry[$layer] = &new PEAR_Registry($phpdir);
758 $this->_registry[$layer]->setConfig($this, false);
759 $this->_regInitialized[$layer] = false;
761 unset($this->_registry[$layer]);
767 * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
768 * @return true|PEAR_Error
770 function readFTPConfigFile($path)
772 do { // poor man's try
773 if (!class_exists('PEAR_FTP')) {
774 if (!class_exists('PEAR_Common')) {
775 require_once 'PEAR/Common.php';
777 if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
778 require_once 'PEAR/FTP.php';
782 if (!class_exists('PEAR_FTP')) {
783 return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
786 $this->_ftp = &new PEAR_FTP;
787 $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
788 $e = $this->_ftp->init($path);
789 if (PEAR::isError($e)) {
790 $this->_ftp->popErrorHandling();
794 $tmp = System::mktemp('-d');
795 PEAR_Common::addTempFile($tmp);
796 $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
797 'pear.ini', false, FTP_BINARY);
798 if (PEAR::isError($e)) {
799 $this->_ftp->popErrorHandling();
803 PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
804 $this->_ftp->disconnect();
805 $this->_ftp->popErrorHandling();
806 $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
807 $e = $this->readConfigFile(null, 'ftp');
808 if (PEAR::isError($e)) {
813 foreach ($this->configuration_info as $key => $val) {
814 if (in_array($this->getGroup($key),
815 array('File Locations', 'File Locations (Advanced)')) &&
816 $this->getType($key) == 'directory') {
817 // any directory configs must be set for this to work
818 if (!isset($this->configuration['ftp'][$key])) {
828 $fail = '"' . implode('", "', $fail) . '"';
829 unset($this->files['ftp']);
830 unset($this->configuration['ftp']);
831 return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
832 'directory configuration variables. These variables were not set: ' .
834 } while (false); // poor man's catch
835 unset($this->files['ftp']);
836 return PEAR::raiseError('no remote host specified');
840 * Reads the existing configurations and creates the _channels array from it
842 function _setupChannels()
844 $set = array_flip(array_values($this->_channels));
845 foreach ($this->configuration as $layer => $data) {
847 if (isset($data['__channels']) && is_array($data['__channels'])) {
848 foreach ($data['__channels'] as $channel => $info) {
849 $set[$channel] = $i++;
853 $this->_channels = array_values(array_flip($set));
854 $this->setChannels($this->_channels);
857 function deleteChannel($channel)
859 $ch = strtolower($channel);
860 foreach ($this->configuration as $layer => $data) {
861 if (isset($data['__channels']) && isset($data['__channels'][$ch])) {
862 unset($this->configuration[$layer]['__channels'][$ch]);
866 $this->_channels = array_flip($this->_channels);
867 unset($this->_channels[$ch]);
868 $this->_channels = array_flip($this->_channels);
872 * Merges data into a config layer from a file. Does the same
873 * thing as readConfigFile, except it does not replace all
874 * existing values in the config layer.
875 * @param string file to read from
876 * @param bool whether to overwrite existing data (default TRUE)
877 * @param string config layer to insert data into ('user' or 'system')
878 * @param string if true, errors are returned if file opening fails
879 * @return bool TRUE on success or a PEAR error on failure
881 function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
883 if (empty($this->files[$layer])) {
884 return $this->raiseError("unknown config layer `$layer'");
887 if ($file === null) {
888 $file = $this->files[$layer];
891 $data = $this->_readConfigDataFrom($file);
892 if (PEAR::isError($data)) {
897 $this->_errorsFound++;
898 $this->lastError = $data;
903 $this->_decodeInput($data);
905 $this->configuration[$layer] =
906 PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
908 $this->configuration[$layer] =
909 PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
912 $this->_setupChannels();
913 if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
914 $this->_registry[$layer] = &new PEAR_Registry($phpdir);
915 $this->_registry[$layer]->setConfig($this, false);
916 $this->_regInitialized[$layer] = false;
918 unset($this->_registry[$layer]);
929 function arrayMergeRecursive($arr2, $arr1)
932 foreach ($arr2 as $key => $data) {
933 if (!isset($arr1[$key])) {
938 if (is_array($data)) {
939 if (!is_array($arr1[$key])) {
940 $ret[$key] = $arr1[$key];
944 $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
949 return array_merge($ret, $arr1);
953 * Writes data into a config layer from a file.
955 * @param string|null file to read from, or null for default
956 * @param string config layer to insert data into ('user' or
958 * @param string|null data to write to config file or null for internal data [DEPRECATED]
959 * @return bool TRUE on success or a PEAR error on failure
961 function writeConfigFile($file = null, $layer = 'user', $data = null)
963 $this->_lazyChannelSetup($layer);
964 if ($layer == 'both' || $layer == 'all') {
965 foreach ($this->files as $type => $file) {
966 $err = $this->writeConfigFile($file, $type, $data);
967 if (PEAR::isError($err)) {
974 if (empty($this->files[$layer])) {
975 return $this->raiseError("unknown config file type `$layer'");
978 if ($file === null) {
979 $file = $this->files[$layer];
982 $data = ($data === null) ? $this->configuration[$layer] : $data;
983 $this->_encodeOutput($data);
984 $opt = array('-p', dirname($file));
985 if (!@System::mkDir($opt)) {
986 return $this->raiseError("could not create directory: " . dirname($file));
989 if (file_exists($file) && is_file($file) && !is_writeable($file)) {
990 return $this->raiseError("no write access to $file!");
993 $fp = @fopen($file, "w");
995 return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
998 $contents = "#PEAR_Config 0.9\n" . serialize($data);
999 if (!@fwrite($fp, $contents)) {
1000 return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
1006 * Reads configuration data from a file and returns the parsed data
1009 * @param string file to read from
1010 * @return array configuration data or a PEAR error on failure
1013 function _readConfigDataFrom($file)
1016 if (file_exists($file)) {
1017 $fp = @fopen($file, "r");
1021 return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
1024 $size = filesize($file);
1025 $rt = get_magic_quotes_runtime();
1026 set_magic_quotes_runtime(0);
1028 $contents = file_get_contents($file);
1029 if (empty($contents)) {
1030 return $this->raiseError('Configuration file "' . $file . '" is empty');
1033 set_magic_quotes_runtime($rt);
1036 if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
1037 $version = $matches[1];
1038 $contents = substr($contents, strlen($matches[0]));
1040 // Museum config file
1041 if (substr($contents,0,2) == 'a:') {
1046 if ($version && version_compare("$version", '1', '<')) {
1047 // no '@', it is possible that unserialize
1048 // raises a notice but it seems to block IO to
1049 // STDOUT if a '@' is used and a notice is raise
1050 $data = unserialize($contents);
1052 if (!is_array($data) && !$data) {
1053 if ($contents == serialize(false)) {
1056 $err = $this->raiseError("PEAR_Config: bad data in $file");
1060 if (!is_array($data)) {
1061 if (strlen(trim($contents)) > 0) {
1062 $error = "PEAR_Config: bad data in $file";
1063 $err = $this->raiseError($error);
1069 // add parsing of newer formats here...
1071 $err = $this->raiseError("$file: unknown version `$version'");
1079 * Gets the file used for storing the config for a layer
1081 * @param string $layer 'user' or 'system'
1083 function getConfFile($layer)
1085 return $this->files[$layer];
1089 * @param string Configuration class name, used for detecting duplicate calls
1090 * @param array information on a role as parsed from its xml file
1091 * @return true|PEAR_Error
1094 function _addConfigVars($class, $vars)
1096 static $called = array();
1097 if (isset($called[$class])) {
1101 $called[$class] = 1;
1102 if (count($vars) > 3) {
1103 return $this->raiseError('Roles can only define 3 new config variables or less');
1106 foreach ($vars as $name => $var) {
1107 if (!is_array($var)) {
1108 return $this->raiseError('Configuration information must be an array');
1111 if (!isset($var['type'])) {
1112 return $this->raiseError('Configuration information must contain a type');
1113 } elseif (!in_array($var['type'],
1114 array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
1115 return $this->raiseError(
1116 'Configuration type must be one of directory, file, string, ' .
1117 'mask, set, or password');
1119 if (!isset($var['default'])) {
1120 return $this->raiseError(
1121 'Configuration information must contain a default value ("default" index)');
1124 if (is_array($var['default'])) {
1126 foreach ($var['default'] as $config_var => $val) {
1127 if (strpos($config_var, 'text') === 0) {
1128 $real_default .= $val;
1129 } elseif (strpos($config_var, 'constant') === 0) {
1130 if (!defined($val)) {
1131 return $this->raiseError(
1132 'Unknown constant "' . $val . '" requested in ' .
1133 'default value for configuration variable "' .
1137 $real_default .= constant($val);
1138 } elseif (isset($this->configuration_info[$config_var])) {
1140 $this->configuration_info[$config_var]['default'];
1142 return $this->raiseError(
1143 'Unknown request for "' . $config_var . '" value in ' .
1144 'default value for configuration variable "' .
1148 $var['default'] = $real_default;
1151 if ($var['type'] == 'integer') {
1152 $var['default'] = (integer) $var['default'];
1155 if (!isset($var['doc'])) {
1156 return $this->raiseError(
1157 'Configuration information must contain a summary ("doc" index)');
1160 if (!isset($var['prompt'])) {
1161 return $this->raiseError(
1162 'Configuration information must contain a simple prompt ("prompt" index)');
1165 if (!isset($var['group'])) {
1166 return $this->raiseError(
1167 'Configuration information must contain a simple group ("group" index)');
1170 if (isset($this->configuration_info[$name])) {
1171 return $this->raiseError('Configuration variable "' . $name .
1172 '" already exists');
1175 $this->configuration_info[$name] = $var;
1176 // fix bug #7351: setting custom config variable in a channel fails
1177 $this->_channelConfigInfo[] = $name;
1184 * Encodes/scrambles configuration data before writing to files.
1185 * Currently, 'password' values will be base64-encoded as to avoid
1186 * that people spot cleartext passwords by accident.
1188 * @param array (reference) array to encode values in
1189 * @return bool TRUE on success
1192 function _encodeOutput(&$data)
1194 foreach ($data as $key => $value) {
1195 if ($key == '__channels') {
1196 foreach ($data['__channels'] as $channel => $blah) {
1197 $this->_encodeOutput($data['__channels'][$channel]);
1201 if (!isset($this->configuration_info[$key])) {
1205 $type = $this->configuration_info[$key]['type'];
1207 // we base64-encode passwords so they are at least
1208 // not shown in plain by accident
1210 $data[$key] = base64_encode($data[$key]);
1214 $data[$key] = octdec($data[$key]);
1224 * Decodes/unscrambles configuration data after reading from files.
1226 * @param array (reference) array to encode values in
1227 * @return bool TRUE on success
1230 * @see PEAR_Config::_encodeOutput
1232 function _decodeInput(&$data)
1234 if (!is_array($data)) {
1238 foreach ($data as $key => $value) {
1239 if ($key == '__channels') {
1240 foreach ($data['__channels'] as $channel => $blah) {
1241 $this->_decodeInput($data['__channels'][$channel]);
1245 if (!isset($this->configuration_info[$key])) {
1249 $type = $this->configuration_info[$key]['type'];
1252 $data[$key] = base64_decode($data[$key]);
1256 $data[$key] = decoct($data[$key]);
1266 * Retrieve the default channel.
1268 * On startup, channels are not initialized, so if the default channel is not
1269 * pear.php.net, then initialize the config.
1270 * @param string registry layer
1271 * @return string|false
1273 function getDefaultChannel($layer = null)
1276 if ($layer === null) {
1277 foreach ($this->layers as $layer) {
1278 if (isset($this->configuration[$layer]['default_channel'])) {
1279 $ret = $this->configuration[$layer]['default_channel'];
1283 } elseif (isset($this->configuration[$layer]['default_channel'])) {
1284 $ret = $this->configuration[$layer]['default_channel'];
1287 if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
1288 $ret = 'pecl.php.net';
1292 if ($ret != 'pear.php.net') {
1293 $this->_lazyChannelSetup();
1299 return PEAR_CONFIG_DEFAULT_CHANNEL;
1303 * Returns a configuration value, prioritizing layers as per the
1306 * @param string config key
1307 * @return mixed the config value, or NULL if not found
1310 function get($key, $layer = null, $channel = false)
1312 if (!isset($this->configuration_info[$key])) {
1316 if ($key == '__channels') {
1320 if ($key == 'default_channel') {
1321 return $this->getDefaultChannel($layer);
1325 $channel = $this->getDefaultChannel();
1326 } elseif ($channel != 'pear.php.net') {
1327 $this->_lazyChannelSetup();
1329 $channel = strtolower($channel);
1331 $test = (in_array($key, $this->_channelConfigInfo)) ?
1332 $this->_getChannelValue($key, $layer, $channel) :
1334 if ($test !== null) {
1335 if ($this->_installRoot) {
1336 if (in_array($this->getGroup($key),
1337 array('File Locations', 'File Locations (Advanced)')) &&
1338 $this->getType($key) == 'directory') {
1339 return $this->_prependPath($test, $this->_installRoot);
1345 if ($layer === null) {
1346 foreach ($this->layers as $layer) {
1347 if (isset($this->configuration[$layer][$key])) {
1348 $test = $this->configuration[$layer][$key];
1349 if ($this->_installRoot) {
1350 if (in_array($this->getGroup($key),
1351 array('File Locations', 'File Locations (Advanced)')) &&
1352 $this->getType($key) == 'directory') {
1353 return $this->_prependPath($test, $this->_installRoot);
1357 if ($key == 'preferred_mirror') {
1358 $reg = &$this->getRegistry();
1359 if (is_object($reg)) {
1360 $chan = &$reg->getChannel($channel);
1361 if (PEAR::isError($chan)) {
1365 if (!$chan->getMirror($test) && $chan->getName() != $test) {
1366 return $channel; // mirror does not exist
1373 } elseif (isset($this->configuration[$layer][$key])) {
1374 $test = $this->configuration[$layer][$key];
1375 if ($this->_installRoot) {
1376 if (in_array($this->getGroup($key),
1377 array('File Locations', 'File Locations (Advanced)')) &&
1378 $this->getType($key) == 'directory') {
1379 return $this->_prependPath($test, $this->_installRoot);
1383 if ($key == 'preferred_mirror') {
1384 $reg = &$this->getRegistry();
1385 if (is_object($reg)) {
1386 $chan = &$reg->getChannel($channel);
1387 if (PEAR::isError($chan)) {
1391 if (!$chan->getMirror($test) && $chan->getName() != $test) {
1392 return $channel; // mirror does not exist
1404 * Returns a channel-specific configuration value, prioritizing layers as per the
1407 * @param string config key
1408 * @return mixed the config value, or NULL if not found
1411 function _getChannelValue($key, $layer, $channel)
1413 if ($key == '__channels' || $channel == 'pear.php.net') {
1418 if ($layer === null) {
1419 foreach ($this->layers as $ilayer) {
1420 if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
1421 $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
1425 } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
1426 $ret = $this->configuration[$layer]['__channels'][$channel][$key];
1429 if ($key != 'preferred_mirror') {
1434 if ($ret !== null) {
1435 $reg = &$this->getRegistry($layer);
1436 if (is_object($reg)) {
1437 $chan = &$reg->getChannel($channel);
1438 if (PEAR::isError($chan)) {
1442 if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
1443 return $channel; // mirror does not exist
1450 if ($channel != $this->getDefaultChannel($layer)) {
1451 return $channel; // we must use the channel name as the preferred mirror
1452 // if the user has not chosen an alternate
1455 return $this->getDefaultChannel($layer);
1459 * Set a config value in a specific layer (defaults to 'user').
1460 * Enforces the types defined in the configuration_info array. An
1461 * integer config variable will be cast to int, and a set config
1462 * variable will be validated against its legal values.
1464 * @param string config key
1465 * @param string config value
1466 * @param string (optional) config layer
1467 * @param string channel to set this value for, or null for global value
1468 * @return bool TRUE on success, FALSE on failure
1470 function set($key, $value, $layer = 'user', $channel = false)
1472 if ($key == '__channels') {
1476 if (!isset($this->configuration[$layer])) {
1480 if ($key == 'default_channel') {
1481 // can only set this value globally
1482 $channel = 'pear.php.net';
1483 if ($value != 'pear.php.net') {
1484 $this->_lazyChannelSetup($layer);
1488 if ($key == 'preferred_mirror') {
1489 if ($channel == '__uri') {
1490 return false; // can't set the __uri pseudo-channel's mirror
1493 $reg = &$this->getRegistry($layer);
1494 if (is_object($reg)) {
1495 $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net');
1496 if (PEAR::isError($chan)) {
1500 if (!$chan->getMirror($value) && $chan->getName() != $value) {
1501 return false; // mirror does not exist
1506 if (!isset($this->configuration_info[$key])) {
1510 extract($this->configuration_info[$key]);
1513 $value = (int)$value;
1516 // If a valid_set is specified, require the value to
1517 // be in the set. If there is no valid_set, accept
1521 if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
1522 (key($valid_set) !== 0 && empty($valid_set[$value])))
1532 $channel = $this->get('default_channel', null, 'pear.php.net');
1535 if (!in_array($channel, $this->_channels)) {
1536 $this->_lazyChannelSetup($layer);
1537 $reg = &$this->getRegistry($layer);
1539 $channel = $reg->channelName($channel);
1542 if (!in_array($channel, $this->_channels)) {
1547 if ($channel != 'pear.php.net') {
1548 if (in_array($key, $this->_channelConfigInfo)) {
1549 $this->configuration[$layer]['__channels'][$channel][$key] = $value;
1556 if ($key == 'default_channel') {
1558 $reg = &$this->getRegistry($layer);
1560 $reg = &$this->getRegistry();
1565 $value = $reg->channelName($value);
1573 $this->configuration[$layer][$key] = $value;
1574 if ($key == 'php_dir' && !$this->_noRegistry) {
1575 if (!isset($this->_registry[$layer]) ||
1576 $value != $this->_registry[$layer]->install_dir) {
1577 $this->_registry[$layer] = &new PEAR_Registry($value);
1578 $this->_regInitialized[$layer] = false;
1579 $this->_registry[$layer]->setConfig($this, false);
1586 function _lazyChannelSetup($uselayer = false)
1588 if ($this->_noRegistry) {
1593 foreach ($this->_registry as $layer => $p) {
1594 if ($uselayer && $uselayer != $layer) {
1598 if (!$this->_regInitialized[$layer]) {
1599 if ($layer == 'default' && isset($this->_registry['user']) ||
1600 isset($this->_registry['system'])) {
1601 // only use the default registry if there are no alternatives
1605 if (!is_object($this->_registry[$layer])) {
1606 if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
1607 $this->_registry[$layer] = &new PEAR_Registry($phpdir);
1608 $this->_registry[$layer]->setConfig($this, false);
1609 $this->_regInitialized[$layer] = false;
1611 unset($this->_registry[$layer]);
1616 $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
1617 $this->_regInitialized[$layer] = true;
1624 * Set the list of channels.
1626 * This should be set via a call to {@link PEAR_Registry::listChannels()}
1629 * @return bool success of operation
1631 function setChannels($channels, $merge = false)
1633 if (!is_array($channels)) {
1638 $this->_channels = array_merge($this->_channels, $channels);
1640 $this->_channels = $channels;
1643 foreach ($channels as $channel) {
1644 $channel = strtolower($channel);
1645 if ($channel == 'pear.php.net') {
1649 foreach ($this->layers as $layer) {
1650 if (!isset($this->configuration[$layer]['__channels'])) {
1651 $this->configuration[$layer]['__channels'] = array();
1653 if (!isset($this->configuration[$layer]['__channels'][$channel])
1654 || !is_array($this->configuration[$layer]['__channels'][$channel])) {
1655 $this->configuration[$layer]['__channels'][$channel] = array();
1664 * Get the type of a config value.
1666 * @param string config key
1668 * @return string type, one of "string", "integer", "file",
1669 * "directory", "set" or "password".
1674 function getType($key)
1676 if (isset($this->configuration_info[$key])) {
1677 return $this->configuration_info[$key]['type'];
1683 * Get the documentation for a config value.
1685 * @param string config key
1686 * @return string documentation string
1691 function getDocs($key)
1693 if (isset($this->configuration_info[$key])) {
1694 return $this->configuration_info[$key]['doc'];
1701 * Get the short documentation for a config value.
1703 * @param string config key
1704 * @return string short documentation string
1709 function getPrompt($key)
1711 if (isset($this->configuration_info[$key])) {
1712 return $this->configuration_info[$key]['prompt'];
1719 * Get the parameter group for a config key.
1721 * @param string config key
1722 * @return string parameter group
1727 function getGroup($key)
1729 if (isset($this->configuration_info[$key])) {
1730 return $this->configuration_info[$key]['group'];
1737 * Get the list of parameter groups.
1739 * @return array list of parameter groups
1744 function getGroups()
1747 foreach ($this->configuration_info as $key => $info) {
1748 $tmp[$info['group']] = 1;
1751 return array_keys($tmp);
1755 * Get the list of the parameters in a group.
1757 * @param string $group parameter group
1758 * @return array list of parameters in $group
1763 function getGroupKeys($group)
1766 foreach ($this->configuration_info as $key => $info) {
1767 if ($info['group'] == $group) {
1776 * Get the list of allowed set values for a config value. Returns
1777 * NULL for config values that are not sets.
1779 * @param string config key
1780 * @return array enumerated array of set values, or NULL if the
1781 * config key is unknown or not a set
1786 function getSetValues($key)
1788 if (isset($this->configuration_info[$key]) &&
1789 isset($this->configuration_info[$key]['type']) &&
1790 $this->configuration_info[$key]['type'] == 'set')
1792 $valid_set = $this->configuration_info[$key]['valid_set'];
1794 if (key($valid_set) === 0) {
1798 return array_keys($valid_set);
1805 * Get all the current config keys.
1807 * @return array simple array of config keys
1814 foreach ($this->layers as $layer) {
1815 $test = $this->configuration[$layer];
1816 if (isset($test['__channels'])) {
1817 foreach ($test['__channels'] as $channel => $configs) {
1818 $keys = array_merge($keys, $configs);
1822 unset($test['__channels']);
1823 $keys = array_merge($keys, $test);
1826 return array_keys($keys);
1830 * Remove the a config key from a specific config layer.
1832 * @param string config key
1833 * @param string (optional) config layer
1834 * @param string (optional) channel (defaults to default channel)
1835 * @return bool TRUE on success, FALSE on failure
1839 function remove($key, $layer = 'user', $channel = null)
1841 if ($channel === null) {
1842 $channel = $this->getDefaultChannel();
1845 if ($channel !== 'pear.php.net') {
1846 if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
1847 unset($this->configuration[$layer]['__channels'][$channel][$key]);
1852 if (isset($this->configuration[$layer][$key])) {
1853 unset($this->configuration[$layer][$key]);
1861 * Temporarily remove an entire config layer. USE WITH CARE!
1863 * @param string config key
1864 * @param string (optional) config layer
1865 * @return bool TRUE on success, FALSE on failure
1869 function removeLayer($layer)
1871 if (isset($this->configuration[$layer])) {
1872 $this->configuration[$layer] = array();
1880 * Stores configuration data in a layer.
1882 * @param string config layer to store
1883 * @return bool TRUE on success, or PEAR error on failure
1887 function store($layer = 'user', $data = null)
1889 return $this->writeConfigFile(null, $layer, $data);
1893 * Tells what config layer that gets to define a key.
1895 * @param string config key
1896 * @param boolean return the defining channel
1898 * @return string|array the config layer, or an empty string if not found.
1900 * if $returnchannel, the return is an array array('layer' => layername,
1901 * 'channel' => channelname), or an empty string if not found
1905 function definedBy($key, $returnchannel = false)
1907 foreach ($this->layers as $layer) {
1908 $channel = $this->getDefaultChannel();
1909 if ($channel !== 'pear.php.net') {
1910 if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
1911 if ($returnchannel) {
1912 return array('layer' => $layer, 'channel' => $channel);
1918 if (isset($this->configuration[$layer][$key])) {
1919 if ($returnchannel) {
1920 return array('layer' => $layer, 'channel' => 'pear.php.net');
1930 * Tells whether a given key exists as a config value.
1932 * @param string config key
1933 * @return bool whether <config key> exists in this object
1937 function isDefined($key)
1939 foreach ($this->layers as $layer) {
1940 if (isset($this->configuration[$layer][$key])) {
1949 * Tells whether a given config layer exists.
1951 * @param string config layer
1952 * @return bool whether <config layer> exists in this object
1956 function isDefinedLayer($layer)
1958 return isset($this->configuration[$layer]);
1962 * Returns the layers defined (except the 'default' one)
1964 * @return array of the defined layers
1966 function getLayers()
1968 $cf = $this->configuration;
1969 unset($cf['default']);
1970 return array_keys($cf);
1973 function apiVersion()
1979 * @return PEAR_Registry
1981 function &getRegistry($use = null)
1983 $layer = $use === null ? 'user' : $use;
1984 if (isset($this->_registry[$layer])) {
1985 return $this->_registry[$layer];
1986 } elseif ($use === null && isset($this->_registry['system'])) {
1987 return $this->_registry['system'];
1988 } elseif ($use === null && isset($this->_registry['default'])) {
1989 return $this->_registry['default'];
1995 // only go here if null was passed in
1996 echo "CRITICAL ERROR: Registry could not be initialized from any value";
2001 * This is to allow customization like the use of installroot
2002 * @param PEAR_Registry
2005 function setRegistry(&$reg, $layer = 'user')
2007 if ($this->_noRegistry) {
2011 if (!in_array($layer, array('user', 'system'))) {
2015 $this->_registry[$layer] = &$reg;
2016 if (is_object($reg)) {
2017 $this->_registry[$layer]->setConfig($this, false);
2023 function noRegistry()
2025 $this->_noRegistry = true;
2031 function &getREST($version, $options = array())
2033 $version = str_replace('.', '', $version);
2034 if (!class_exists($class = 'PEAR_REST_' . $version)) {
2035 require_once 'PEAR/REST/' . $version . '.php';
2038 $remote = &new $class($this, $options);
2043 * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a
2044 * remote configuration file has been specified
2045 * @return PEAR_FTP|false
2049 if (isset($this->_ftp)) {
2057 function _prependPath($path, $prepend)
2059 if (strlen($prepend) > 0) {
2060 if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
2061 if (preg_match('/^[a-z]:/i', $prepend)) {
2062 $prepend = substr($prepend, 2);
2063 } elseif ($prepend{0} != '\\') {
2064 $prepend = "\\$prepend";
2066 $path = substr($path, 0, 2) . $prepend . substr($path, 2);
2068 $path = $prepend . $path;
2075 * @param string|false installation directory to prepend to all _dir variables, or false to
2078 function setInstallRoot($root)
2080 if (substr($root, -1) == DIRECTORY_SEPARATOR) {
2081 $root = substr($root, 0, -1);
2083 $old = $this->_installRoot;
2084 $this->_installRoot = $root;
2085 if (($old != $root) && !$this->_noRegistry) {
2086 foreach (array_keys($this->_registry) as $layer) {
2087 if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
2090 $this->_registry[$layer] =
2091 &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net'));
2092 $this->_registry[$layer]->setConfig($this, false);
2093 $this->_regInitialized[$layer] = false;