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