source: branches/version-2_13-dev/data/module/PEAR/Config.php @ 23125

Revision 23125, 66.3 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

Line 
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 * @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
16 */
17
18/**
19 * Required for error handling
20 */
21require_once 'PEAR.php';
22require_once 'PEAR/Registry.php';
23require_once 'PEAR/Installer/Role.php';
24require_once 'System.php';
25
26/**
27 * Last created PEAR_Config instance.
28 * @var object
29 */
30$GLOBALS['_PEAR_Config_instance'] = null;
31if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
32    $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
33} else {
34    $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
35}
36
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_*.
42
43// default channel and preferred mirror is based on whether we are invoked through
44// the "pear" or the "pecl" command
45if (!defined('PEAR_RUNTYPE')) {
46    define('PEAR_RUNTYPE', 'pear');
47}
48
49if (PEAR_RUNTYPE == 'pear') {
50    define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
51} else {
52    define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
53}
54
55if (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'));
59} else {
60    define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
61}
62
63// Default for master_server
64if (getenv('PHP_PEAR_MASTER_SERVER')) {
65    define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
66} else {
67    define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
68}
69
70// Default for http_proxy
71if (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'));
75} else {
76    define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
77}
78
79// Default for php_dir
80if (getenv('PHP_PEAR_INSTALL_DIR')) {
81    define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
82} else {
83    if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
84        define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
85    } else {
86        define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
87    }
88}
89
90// Default for ext_dir
91if (getenv('PHP_PEAR_EXTENSION_DIR')) {
92    define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
93} else {
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);
101    } else {
102        define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
103    }
104}
105
106// Default for doc_dir
107if (getenv('PHP_PEAR_DOC_DIR')) {
108    define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
109} else {
110    define('PEAR_CONFIG_DEFAULT_DOC_DIR',
111           $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
112}
113
114// Default for bin_dir
115if (getenv('PHP_PEAR_BIN_DIR')) {
116    define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
117} else {
118    define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
119}
120
121// Default for data_dir
122if (getenv('PHP_PEAR_DATA_DIR')) {
123    define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
124} else {
125    define('PEAR_CONFIG_DEFAULT_DATA_DIR',
126           $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
127}
128
129// Default for cfg_dir
130if (getenv('PHP_PEAR_CFG_DIR')) {
131    define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
132} else {
133    define('PEAR_CONFIG_DEFAULT_CFG_DIR',
134           $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
135}
136
137// Default for www_dir
138if (getenv('PHP_PEAR_WWW_DIR')) {
139    define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
140} else {
141    define('PEAR_CONFIG_DEFAULT_WWW_DIR',
142           $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
143}
144
145// Default for test_dir
146if (getenv('PHP_PEAR_TEST_DIR')) {
147    define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
148} else {
149    define('PEAR_CONFIG_DEFAULT_TEST_DIR',
150           $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
151}
152
153// Default for temp_dir
154if (getenv('PHP_PEAR_TEMP_DIR')) {
155    define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
156} else {
157    define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
158           System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
159           DIRECTORY_SEPARATOR . 'temp');
160}
161
162// Default for cache_dir
163if (getenv('PHP_PEAR_CACHE_DIR')) {
164    define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
165} else {
166    define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
167           System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
168           DIRECTORY_SEPARATOR . 'cache');
169}
170
171// Default for download_dir
172if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
173    define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
174} else {
175    define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
176           System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
177           DIRECTORY_SEPARATOR . 'download');
178}
179
180// Default for php_bin
181if (getenv('PHP_PEAR_PHP_BIN')) {
182    define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
183} else {
184    define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
185           DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
186}
187
188// Default for verbose
189if (getenv('PHP_PEAR_VERBOSE')) {
190    define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
191} else {
192    define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
193}
194
195// Default for preferred_state
196if (getenv('PHP_PEAR_PREFERRED_STATE')) {
197    define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
198} else {
199    define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
200}
201
202// Default for umask
203if (getenv('PHP_PEAR_UMASK')) {
204    define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
205} else {
206    define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
207}
208
209// Default for cache_ttl
210if (getenv('PHP_PEAR_CACHE_TTL')) {
211    define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
212} else {
213    define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
214}
215
216// Default for sig_type
217if (getenv('PHP_PEAR_SIG_TYPE')) {
218    define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
219} else {
220    define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
221}
222
223// Default for sig_bin
224if (getenv('PHP_PEAR_SIG_BIN')) {
225    define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
226} else {
227    define('PEAR_CONFIG_DEFAULT_SIG_BIN',
228           System::which(
229               'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
230}
231
232// Default for sig_keydir
233if (getenv('PHP_PEAR_SIG_KEYDIR')) {
234    define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
235} else {
236    define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
237           PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
238}
239
240/**
241 * This is a class for storing configuration data, keeping track of
242 * which are system-defined, user-defined or defaulted.
243 * @category   pear
244 * @package    PEAR
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
252 */
253class PEAR_Config extends PEAR
254{
255    /**
256     * Array of config files used.
257     *
258     * @var array layer => config file
259     */
260    var $files = array(
261        'system' => '',
262        'user' => '',
263        );
264
265    var $layers = array();
266
267    /**
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.
271     *
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').
276     *
277     * @var array layer => array(keyname => value, ...)
278     */
279    var $configuration = array(
280        'user' => array(),
281        'system' => array(),
282        'default' => array(),
283        );
284
285    /**
286     * Configuration values that can be set for a channel
287     *
288     * All other configuration values can only have a global value
289     * @var array
290     * @access private
291     */
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'
296        );
297
298    /**
299     * Channels that can be accessed
300     * @see setChannels()
301     * @var array
302     * @access private
303     */
304    var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
305
306    /**
307     * This variable is used to control the directory values returned
308     * @see setInstallRoot();
309     * @var string|false
310     * @access private
311     */
312    var $_installRoot = false;
313
314    /**
315     * If requested, this will always refer to the registry
316     * contained in php_dir
317     * @var PEAR_Registry
318     */
319    var $_registry = array();
320
321    /**
322     * @var array
323     * @access private
324     */
325    var $_regInitialized = array();
326
327    /**
328     * @var bool
329     * @access private
330     */
331    var $_noRegistry = false;
332
333    /**
334     * amount of errors found while parsing config
335     * @var integer
336     * @access private
337     */
338    var $_errorsFound = 0;
339    var $_lastError = null;
340
341    /**
342     * Information about the configuration data.  Stores the type,
343     * default value and a documentation string for each configuration
344     * value.
345     *
346     * @var array layer => array(infotype => value, ...)
347     */
348    var $configuration_info = array(
349        // Channels/Internet Access
350        'default_channel' => array(
351            'type' => 'string',
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',
356            ),
357        'preferred_mirror' => array(
358            'type' => 'string',
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',
363            ),
364        'remote_config' => array(
365            'type' => 'password',
366            'default' => '',
367            'doc' => 'ftp url of remote configuration file to use for synchronized install',
368            'prompt' => 'Remote Configuration File',
369            'group' => 'Internet Access',
370            ),
371        'auto_discover' => array(
372            'type' => 'integer',
373            'default' => 0,
374            'doc' => 'whether to automatically discover new channels',
375            'prompt' => 'Auto-discover new Channels',
376            'group' => 'Internet Access',
377            ),
378        // Internet Access
379        'master_server' => array(
380            'type' => 'string',
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',
385            ),
386        'http_proxy' => array(
387            'type' => 'string',
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',
392            ),
393        // File Locations
394        'php_dir' => array(
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',
400            ),
401        'ext_dir' => array(
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',
407            ),
408        'doc_dir' => array(
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',
414            ),
415        'bin_dir' => array(
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',
421            ),
422        'data_dir' => array(
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)',
428            ),
429        'cfg_dir' => array(
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)',
435            ),
436        'www_dir' => array(
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)',
442            ),
443        'test_dir' => array(
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)',
449            ),
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)',
456            ),
457        'temp_dir' => array(
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)',
463            ),
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)',
470            ),
471        'php_bin' => array(
472            'type' => 'file',
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)',
477            ),
478        'php_prefix' => array(
479            'type' => 'string',
480            'default' => '',
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)',
484            ),
485        'php_suffix' => array(
486            'type' => 'string',
487            'default' => '',
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)',
491            ),
492        'php_ini' => array(
493            'type' => 'file',
494            'default' => '',
495            'doc' => 'location of php.ini in which to enable PECL extensions on install',
496            'prompt' => 'php.ini location',
497            'group' => 'File Locations (Advanced)',
498            ),
499        // Maintainers
500        'username' => array(
501            'type' => 'string',
502            'default' => '',
503            'doc' => '(maintainers) your PEAR account name',
504            'prompt' => 'PEAR username (for maintainers)',
505            'group' => 'Maintainers',
506            ),
507        'password' => array(
508            'type' => 'password',
509            'default' => '',
510            'doc' => '(maintainers) your PEAR account password',
511            'prompt' => 'PEAR password (for maintainers)',
512            'group' => 'Maintainers',
513            ),
514        // Advanced
515        'verbose' => array(
516            'type' => 'integer',
517            'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
518            'doc' => 'verbosity level
5190: really quiet
5201: somewhat quiet
5212: verbose
5223: debug',
523            'prompt' => 'Debug Log Level',
524            'group' => 'Advanced',
525            ),
526        'preferred_state' => array(
527            'type' => 'set',
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',
534            ),
535        'umask' => array(
536            'type' => 'mask',
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',
541            ),
542        'cache_ttl' => array(
543            'type' => 'integer',
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',
548            ),
549        'sig_type' => array(
550            'type' => 'set',
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',
556            ),
557        'sig_bin' => array(
558            'type' => 'string',
559            'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
560            'doc' => 'which package signature mechanism to use',
561            'prompt' => 'Signature Handling Program',
562            'group' => 'Maintainers',
563            ),
564        'sig_keyid' => array(
565            'type' => 'string',
566            'default' => '',
567            'doc' => 'which key to use for signing with',
568            'prompt' => 'Signature Key Id',
569            'group' => 'Maintainers',
570            ),
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',
577            ),
578        // __channels is reserved - used for channel-specific configuration
579        );
580
581    /**
582     * Constructor.
583     *
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
590     *
591     * @access public
592     *
593     * @see PEAR_Config::singleton
594     */
595    function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false,
596                         $strict = true)
597    {
598        $this->PEAR();
599        PEAR_Installer_Role::initializeConfig($this);
600        $sl = DIRECTORY_SEPARATOR;
601        if (empty($user_file)) {
602            if (OS_WINDOWS) {
603                $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
604            } else {
605                $user_file = getenv('HOME') . $sl . '.pearrc';
606            }
607        }
608
609        if (empty($system_file)) {
610            $system_file = PEAR_CONFIG_SYSCONFDIR . $sl;
611            if (OS_WINDOWS) {
612                $system_file .= 'pearsys.ini';
613            } else {
614                $system_file .= 'pear.conf';
615            }
616        }
617
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) {
626                return;
627            }
628        }
629
630        if ($system_file && @file_exists($system_file)) {
631            $this->mergeConfigFile($system_file, false, 'system', $strict);
632            if ($this->_errorsFound > 0) {
633                return;
634            }
635
636        }
637
638        if (!$ftp_file) {
639            $ftp_file = $this->get('remote_config');
640        }
641
642        if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
643            $this->readFTPConfigFile($ftp_file);
644        }
645
646        foreach ($this->configuration_info as $key => $info) {
647            $this->configuration['default'][$key] = $info['default'];
648        }
649
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;
654    }
655
656    /**
657     * Return the default locations of user and system configuration files
658     * @static
659     */
660    function getDefaultConfigFiles()
661    {
662        $sl = DIRECTORY_SEPARATOR;
663        if (OS_WINDOWS) {
664            return array(
665                'user'   => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
666                'system' =>  PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
667            );
668        }
669
670        return array(
671            'user'   => getenv('HOME') . $sl . '.pearrc',
672            'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
673        );
674    }
675
676    /**
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
680     * new object.
681     *
682     * @param string (optional) file to read user-defined options from
683     * @param string (optional) file to read system-wide defaults from
684     *
685     * @return object an existing or new PEAR_Config instance
686     *
687     * @access public
688     *
689     * @see PEAR_Config::PEAR_Config
690     */
691    function &singleton($user_file = '', $system_file = '', $strict = true)
692    {
693        if (is_object($GLOBALS['_PEAR_Config_instance'])) {
694            return $GLOBALS['_PEAR_Config_instance'];
695        }
696
697        $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict);
698        if ($t_conf->_errorsFound > 0) {
699             return $t_conf->lastError;
700        }
701
702        $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
703        return $GLOBALS['_PEAR_Config_instance'];
704    }
705
706    /**
707     * Determine whether any configuration files have been detected, and whether a
708     * registry object can be retrieved from this configuration.
709     * @return bool
710     * @since PEAR 1.4.0a1
711     */
712    function validConfiguration()
713    {
714        if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
715            return true;
716        }
717
718        return false;
719    }
720
721    /**
722     * Reads configuration data from a file.  All existing values in
723     * the config layer are discarded and replaced with data from the
724     * file.
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
729     */
730    function readConfigFile($file = null, $layer = 'user', $strict = true)
731    {
732        if (empty($this->files[$layer])) {
733            return $this->raiseError("unknown config layer `$layer'");
734        }
735
736        if ($file === null) {
737            $file = $this->files[$layer];
738        }
739
740        $data = $this->_readConfigDataFrom($file);
741        if (PEAR::isError($data)) {
742            if (!$strict) {
743                return true;
744            }
745
746            $this->_errorsFound++;
747            $this->lastError = $data;
748
749            return $data;
750        }
751
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;
760        } else {
761            unset($this->_registry[$layer]);
762        }
763        return true;
764    }
765
766    /**
767     * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
768     * @return true|PEAR_Error
769     */
770    function readFTPConfigFile($path)
771    {
772        do { // poor man's try
773            if (!class_exists('PEAR_FTP')) {
774                if (!class_exists('PEAR_Common')) {
775                    require_once 'PEAR/Common.php';
776                }
777                if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
778                    require_once 'PEAR/FTP.php';
779                }
780            }
781
782            if (!class_exists('PEAR_FTP')) {
783                return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
784            }
785
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();
791                return $e;
792            }
793
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();
800                return $e;
801            }
802
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)) {
809                return $e;
810            }
811
812            $fail = array();
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])) {
819                        $fail[] = $key;
820                    }
821                }
822            }
823
824            if (!count($fail)) {
825                return true;
826            }
827
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: ' .
833                $fail);
834        } while (false); // poor man's catch
835        unset($this->files['ftp']);
836        return PEAR::raiseError('no remote host specified');
837    }
838
839    /**
840     * Reads the existing configurations and creates the _channels array from it
841     */
842    function _setupChannels()
843    {
844        $set = array_flip(array_values($this->_channels));
845        foreach ($this->configuration as $layer => $data) {
846            $i = 1000;
847            if (isset($data['__channels']) && is_array($data['__channels'])) {
848                foreach ($data['__channels'] as $channel => $info) {
849                    $set[$channel] = $i++;
850                }
851            }
852        }
853        $this->_channels = array_values(array_flip($set));
854        $this->setChannels($this->_channels);
855    }
856
857    function deleteChannel($channel)
858    {
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]);
863            }
864        }
865
866        $this->_channels = array_flip($this->_channels);
867        unset($this->_channels[$ch]);
868        $this->_channels = array_flip($this->_channels);
869    }
870
871    /**
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
880     */
881    function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
882    {
883        if (empty($this->files[$layer])) {
884            return $this->raiseError("unknown config layer `$layer'");
885        }
886
887        if ($file === null) {
888            $file = $this->files[$layer];
889        }
890
891        $data = $this->_readConfigDataFrom($file);
892        if (PEAR::isError($data)) {
893            if (!$strict) {
894                return true;
895            }
896
897            $this->_errorsFound++;
898            $this->lastError = $data;
899
900            return $data;
901        }
902
903        $this->_decodeInput($data);
904        if ($override) {
905            $this->configuration[$layer] =
906                PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
907        } else {
908            $this->configuration[$layer] =
909                PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
910        }
911
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;
917        } else {
918            unset($this->_registry[$layer]);
919        }
920        return true;
921    }
922
923    /**
924     * @param array
925     * @param array
926     * @return array
927     * @static
928     */
929    function arrayMergeRecursive($arr2, $arr1)
930    {
931        $ret = array();
932        foreach ($arr2 as $key => $data) {
933            if (!isset($arr1[$key])) {
934                $ret[$key] = $data;
935                unset($arr1[$key]);
936                continue;
937            }
938            if (is_array($data)) {
939                if (!is_array($arr1[$key])) {
940                    $ret[$key] = $arr1[$key];
941                    unset($arr1[$key]);
942                    continue;
943                }
944                $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
945                unset($arr1[$key]);
946            }
947        }
948
949        return array_merge($ret, $arr1);
950    }
951
952    /**
953     * Writes data into a config layer from a file.
954     *
955     * @param string|null file to read from, or null for default
956     * @param string config layer to insert data into ('user' or
957     *               'system')
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
960     */
961    function writeConfigFile($file = null, $layer = 'user', $data = null)
962    {
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)) {
968                    return $err;
969                }
970            }
971            return true;
972        }
973
974        if (empty($this->files[$layer])) {
975            return $this->raiseError("unknown config file type `$layer'");
976        }
977
978        if ($file === null) {
979            $file = $this->files[$layer];
980        }
981
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));
987        }
988
989        if (file_exists($file) && is_file($file) && !is_writeable($file)) {
990            return $this->raiseError("no write access to $file!");
991        }
992
993        $fp = @fopen($file, "w");
994        if (!$fp) {
995            return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
996        }
997
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)");
1001        }
1002        return true;
1003    }
1004
1005    /**
1006     * Reads configuration data from a file and returns the parsed data
1007     * in an array.
1008     *
1009     * @param string file to read from
1010     * @return array configuration data or a PEAR error on failure
1011     * @access private
1012     */
1013    function _readConfigDataFrom($file)
1014    {
1015        $fp = false;
1016        if (file_exists($file)) {
1017            $fp = @fopen($file, "r");
1018        }
1019
1020        if (!$fp) {
1021            return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
1022        }
1023
1024        $size = filesize($file);
1025        $rt = get_magic_quotes_runtime();
1026        set_magic_quotes_runtime(0);
1027        fclose($fp);
1028        $contents = file_get_contents($file);
1029        if (empty($contents)) {
1030            return $this->raiseError('Configuration file "' . $file . '" is empty');
1031        }
1032
1033        set_magic_quotes_runtime($rt);
1034
1035        $version = false;
1036        if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
1037            $version = $matches[1];
1038            $contents = substr($contents, strlen($matches[0]));
1039        } else {
1040            // Museum config file
1041            if (substr($contents,0,2) == 'a:') {
1042                $version = '0.1';
1043            }
1044        }
1045
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);
1051
1052            if (!is_array($data) && !$data) {
1053                if ($contents == serialize(false)) {
1054                    $data = array();
1055                } else {
1056                    $err = $this->raiseError("PEAR_Config: bad data in $file");
1057                    return $err;
1058                }
1059            }
1060            if (!is_array($data)) {
1061                if (strlen(trim($contents)) > 0) {
1062                    $error = "PEAR_Config: bad data in $file";
1063                    $err = $this->raiseError($error);
1064                    return $err;
1065                }
1066
1067                $data = array();
1068            }
1069        // add parsing of newer formats here...
1070        } else {
1071            $err = $this->raiseError("$file: unknown version `$version'");
1072            return $err;
1073        }
1074
1075        return $data;
1076    }
1077
1078    /**
1079    * Gets the file used for storing the config for a layer
1080    *
1081    * @param string $layer 'user' or 'system'
1082    */
1083    function getConfFile($layer)
1084    {
1085        return $this->files[$layer];
1086    }
1087
1088    /**
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
1092     * @access private
1093     */
1094    function _addConfigVars($class, $vars)
1095    {
1096        static $called = array();
1097        if (isset($called[$class])) {
1098            return;
1099        }
1100
1101        $called[$class] = 1;
1102        if (count($vars) > 3) {
1103            return $this->raiseError('Roles can only define 3 new config variables or less');
1104        }
1105
1106        foreach ($vars as $name => $var) {
1107            if (!is_array($var)) {
1108                return $this->raiseError('Configuration information must be an array');
1109            }
1110
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');
1118            }
1119            if (!isset($var['default'])) {
1120                return $this->raiseError(
1121                    'Configuration information must contain a default value ("default" index)');
1122            }
1123
1124            if (is_array($var['default'])) {
1125                $real_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 "' .
1134                                $name . '"');
1135                        }
1136
1137                        $real_default .= constant($val);
1138                    } elseif (isset($this->configuration_info[$config_var])) {
1139                        $real_default .=
1140                            $this->configuration_info[$config_var]['default'];
1141                    } else {
1142                        return $this->raiseError(
1143                            'Unknown request for "' . $config_var . '" value in ' .
1144                            'default value for configuration variable "' .
1145                            $name . '"');
1146                    }
1147                }
1148                $var['default'] = $real_default;
1149            }
1150
1151            if ($var['type'] == 'integer') {
1152                $var['default'] = (integer) $var['default'];
1153            }
1154
1155            if (!isset($var['doc'])) {
1156                return $this->raiseError(
1157                    'Configuration information must contain a summary ("doc" index)');
1158            }
1159
1160            if (!isset($var['prompt'])) {
1161                return $this->raiseError(
1162                    'Configuration information must contain a simple prompt ("prompt" index)');
1163            }
1164
1165            if (!isset($var['group'])) {
1166                return $this->raiseError(
1167                    'Configuration information must contain a simple group ("group" index)');
1168            }
1169
1170            if (isset($this->configuration_info[$name])) {
1171                return $this->raiseError('Configuration variable "' . $name .
1172                    '" already exists');
1173            }
1174
1175            $this->configuration_info[$name] = $var;
1176            // fix bug #7351: setting custom config variable in a channel fails
1177            $this->_channelConfigInfo[] = $name;
1178        }
1179
1180        return true;
1181    }
1182
1183    /**
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.
1187     *
1188     * @param array (reference) array to encode values in
1189     * @return bool TRUE on success
1190     * @access private
1191     */
1192    function _encodeOutput(&$data)
1193    {
1194        foreach ($data as $key => $value) {
1195            if ($key == '__channels') {
1196                foreach ($data['__channels'] as $channel => $blah) {
1197                    $this->_encodeOutput($data['__channels'][$channel]);
1198                }
1199            }
1200
1201            if (!isset($this->configuration_info[$key])) {
1202                continue;
1203            }
1204
1205            $type = $this->configuration_info[$key]['type'];
1206            switch ($type) {
1207                // we base64-encode passwords so they are at least
1208                // not shown in plain by accident
1209                case 'password': {
1210                    $data[$key] = base64_encode($data[$key]);
1211                    break;
1212                }
1213                case 'mask': {
1214                    $data[$key] = octdec($data[$key]);
1215                    break;
1216                }
1217            }
1218        }
1219
1220        return true;
1221    }
1222
1223    /**
1224     * Decodes/unscrambles configuration data after reading from files.
1225     *
1226     * @param array (reference) array to encode values in
1227     * @return bool TRUE on success
1228     * @access private
1229     *
1230     * @see PEAR_Config::_encodeOutput
1231     */
1232    function _decodeInput(&$data)
1233    {
1234        if (!is_array($data)) {
1235            return true;
1236        }
1237
1238        foreach ($data as $key => $value) {
1239            if ($key == '__channels') {
1240                foreach ($data['__channels'] as $channel => $blah) {
1241                    $this->_decodeInput($data['__channels'][$channel]);
1242                }
1243            }
1244
1245            if (!isset($this->configuration_info[$key])) {
1246                continue;
1247            }
1248
1249            $type = $this->configuration_info[$key]['type'];
1250            switch ($type) {
1251                case 'password': {
1252                    $data[$key] = base64_decode($data[$key]);
1253                    break;
1254                }
1255                case 'mask': {
1256                    $data[$key] = decoct($data[$key]);
1257                    break;
1258                }
1259            }
1260        }
1261
1262        return true;
1263    }
1264
1265    /**
1266     * Retrieve the default channel.
1267     *
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
1272     */
1273    function getDefaultChannel($layer = null)
1274    {
1275        $ret = false;
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'];
1280                    break;
1281                }
1282            }
1283        } elseif (isset($this->configuration[$layer]['default_channel'])) {
1284            $ret = $this->configuration[$layer]['default_channel'];
1285        }
1286
1287        if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
1288            $ret = 'pecl.php.net';
1289        }
1290
1291        if ($ret) {
1292            if ($ret != 'pear.php.net') {
1293                $this->_lazyChannelSetup();
1294            }
1295
1296            return $ret;
1297        }
1298
1299        return PEAR_CONFIG_DEFAULT_CHANNEL;
1300    }
1301
1302    /**
1303     * Returns a configuration value, prioritizing layers as per the
1304     * layers property.
1305     *
1306     * @param string config key
1307     * @return mixed the config value, or NULL if not found
1308     * @access public
1309     */
1310    function get($key, $layer = null, $channel = false)
1311    {
1312        if (!isset($this->configuration_info[$key])) {
1313            return null;
1314        }
1315
1316        if ($key == '__channels') {
1317            return null;
1318        }
1319
1320        if ($key == 'default_channel') {
1321            return $this->getDefaultChannel($layer);
1322        }
1323
1324        if (!$channel) {
1325            $channel = $this->getDefaultChannel();
1326        } elseif ($channel != 'pear.php.net') {
1327            $this->_lazyChannelSetup();
1328        }
1329        $channel = strtolower($channel);
1330
1331        $test = (in_array($key, $this->_channelConfigInfo)) ?
1332            $this->_getChannelValue($key, $layer, $channel) :
1333            null;
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);
1340                }
1341            }
1342            return $test;
1343        }
1344
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);
1354                        }
1355                    }
1356
1357                    if ($key == 'preferred_mirror') {
1358                        $reg = &$this->getRegistry();
1359                        if (is_object($reg)) {
1360                            $chan = &$reg->getChannel($channel);
1361                            if (PEAR::isError($chan)) {
1362                                return $channel;
1363                            }
1364
1365                            if (!$chan->getMirror($test) && $chan->getName() != $test) {
1366                                return $channel; // mirror does not exist
1367                            }
1368                        }
1369                    }
1370                    return $test;
1371                }
1372            }
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);
1380                }
1381            }
1382
1383            if ($key == 'preferred_mirror') {
1384                $reg = &$this->getRegistry();
1385                if (is_object($reg)) {
1386                    $chan = &$reg->getChannel($channel);
1387                    if (PEAR::isError($chan)) {
1388                        return $channel;
1389                    }
1390
1391                    if (!$chan->getMirror($test) && $chan->getName() != $test) {
1392                        return $channel; // mirror does not exist
1393                    }
1394                }
1395            }
1396
1397            return $test;
1398        }
1399
1400        return null;
1401    }
1402
1403    /**
1404     * Returns a channel-specific configuration value, prioritizing layers as per the
1405     * layers property.
1406     *
1407     * @param string config key
1408     * @return mixed the config value, or NULL if not found
1409     * @access private
1410     */
1411    function _getChannelValue($key, $layer, $channel)
1412    {
1413        if ($key == '__channels' || $channel == 'pear.php.net') {
1414            return null;
1415        }
1416
1417        $ret = null;
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];
1422                    break;
1423                }
1424            }
1425        } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
1426            $ret = $this->configuration[$layer]['__channels'][$channel][$key];
1427        }
1428
1429        if ($key != 'preferred_mirror') {
1430            return $ret;
1431        }
1432
1433
1434        if ($ret !== null) {
1435            $reg = &$this->getRegistry($layer);
1436            if (is_object($reg)) {
1437                $chan = &$reg->getChannel($channel);
1438                if (PEAR::isError($chan)) {
1439                    return $channel;
1440                }
1441
1442                if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
1443                    return $channel; // mirror does not exist
1444                }
1445            }
1446
1447            return $ret;
1448        }
1449
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
1453        }
1454
1455        return $this->getDefaultChannel($layer);
1456    }
1457
1458    /**
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.
1463     *
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
1469     */
1470    function set($key, $value, $layer = 'user', $channel = false)
1471    {
1472        if ($key == '__channels') {
1473            return false;
1474        }
1475
1476        if (!isset($this->configuration[$layer])) {
1477            return false;
1478        }
1479
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);
1485            }
1486        }
1487
1488        if ($key == 'preferred_mirror') {
1489            if ($channel == '__uri') {
1490                return false; // can't set the __uri pseudo-channel's mirror
1491            }
1492
1493            $reg = &$this->getRegistry($layer);
1494            if (is_object($reg)) {
1495                $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net');
1496                if (PEAR::isError($chan)) {
1497                    return false;
1498                }
1499
1500                if (!$chan->getMirror($value) && $chan->getName() != $value) {
1501                    return false; // mirror does not exist
1502                }
1503            }
1504        }
1505
1506        if (!isset($this->configuration_info[$key])) {
1507            return false;
1508        }
1509
1510        extract($this->configuration_info[$key]);
1511        switch ($type) {
1512            case 'integer':
1513                $value = (int)$value;
1514                break;
1515            case 'set': {
1516                // If a valid_set is specified, require the value to
1517                // be in the set.  If there is no valid_set, accept
1518                // any value.
1519                if ($valid_set) {
1520                    reset($valid_set);
1521                    if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
1522                        (key($valid_set) !== 0 && empty($valid_set[$value])))
1523                    {
1524                        return false;
1525                    }
1526                }
1527                break;
1528            }
1529        }
1530
1531        if (!$channel) {
1532            $channel = $this->get('default_channel', null, 'pear.php.net');
1533        }
1534
1535        if (!in_array($channel, $this->_channels)) {
1536            $this->_lazyChannelSetup($layer);
1537            $reg = &$this->getRegistry($layer);
1538            if ($reg) {
1539                $channel = $reg->channelName($channel);
1540            }
1541
1542            if (!in_array($channel, $this->_channels)) {
1543                return false;
1544            }
1545        }
1546
1547        if ($channel != 'pear.php.net') {
1548            if (in_array($key, $this->_channelConfigInfo)) {
1549                $this->configuration[$layer]['__channels'][$channel][$key] = $value;
1550                return true;
1551            }
1552
1553            return false;
1554        }
1555
1556        if ($key == 'default_channel') {
1557            if (!isset($reg)) {
1558                $reg = &$this->getRegistry($layer);
1559                if (!$reg) {
1560                    $reg = &$this->getRegistry();
1561                }
1562            }
1563
1564            if ($reg) {
1565                $value = $reg->channelName($value);
1566            }
1567
1568            if (!$value) {
1569                return false;
1570            }
1571        }
1572
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);
1580            }
1581        }
1582
1583        return true;
1584    }
1585
1586    function _lazyChannelSetup($uselayer = false)
1587    {
1588        if ($this->_noRegistry) {
1589            return;
1590        }
1591
1592        $merge = false;
1593        foreach ($this->_registry as $layer => $p) {
1594            if ($uselayer && $uselayer != $layer) {
1595                continue;
1596            }
1597
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
1602                    continue;
1603                }
1604
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;
1610                    } else {
1611                        unset($this->_registry[$layer]);
1612                        return;
1613                    }
1614                }
1615
1616                $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
1617                $this->_regInitialized[$layer] = true;
1618                $merge = true;
1619            }
1620        }
1621    }
1622
1623    /**
1624     * Set the list of channels.
1625     *
1626     * This should be set via a call to {@link PEAR_Registry::listChannels()}
1627     * @param array
1628     * @param bool
1629     * @return bool success of operation
1630     */
1631    function setChannels($channels, $merge = false)
1632    {
1633        if (!is_array($channels)) {
1634            return false;
1635        }
1636
1637        if ($merge) {
1638            $this->_channels = array_merge($this->_channels, $channels);
1639        } else {
1640            $this->_channels = $channels;
1641        }
1642
1643        foreach ($channels as $channel) {
1644            $channel = strtolower($channel);
1645            if ($channel == 'pear.php.net') {
1646                continue;
1647            }
1648
1649            foreach ($this->layers as $layer) {
1650                if (!isset($this->configuration[$layer]['__channels'])) {
1651                    $this->configuration[$layer]['__channels'] = array();
1652                }
1653                if (!isset($this->configuration[$layer]['__channels'][$channel])
1654                      || !is_array($this->configuration[$layer]['__channels'][$channel])) {
1655                    $this->configuration[$layer]['__channels'][$channel] = array();
1656                }
1657            }
1658        }
1659
1660        return true;
1661    }
1662
1663    /**
1664     * Get the type of a config value.
1665     *
1666     * @param string  config key
1667     *
1668     * @return string type, one of "string", "integer", "file",
1669     * "directory", "set" or "password".
1670     *
1671     * @access public
1672     *
1673     */
1674    function getType($key)
1675    {
1676        if (isset($this->configuration_info[$key])) {
1677            return $this->configuration_info[$key]['type'];
1678        }
1679        return false;
1680    }
1681
1682    /**
1683     * Get the documentation for a config value.
1684     *
1685     * @param string  config key
1686     * @return string documentation string
1687     *
1688     * @access public
1689     *
1690     */
1691    function getDocs($key)
1692    {
1693        if (isset($this->configuration_info[$key])) {
1694            return $this->configuration_info[$key]['doc'];
1695        }
1696
1697        return false;
1698    }
1699
1700    /**
1701     * Get the short documentation for a config value.
1702     *
1703     * @param string  config key
1704     * @return string short documentation string
1705     *
1706     * @access public
1707     *
1708     */
1709    function getPrompt($key)
1710    {
1711        if (isset($this->configuration_info[$key])) {
1712            return $this->configuration_info[$key]['prompt'];
1713        }
1714
1715        return false;
1716    }
1717
1718    /**
1719     * Get the parameter group for a config key.
1720     *
1721     * @param string  config key
1722     * @return string parameter group
1723     *
1724     * @access public
1725     *
1726     */
1727    function getGroup($key)
1728    {
1729        if (isset($this->configuration_info[$key])) {
1730            return $this->configuration_info[$key]['group'];
1731        }
1732
1733        return false;
1734    }
1735
1736    /**
1737     * Get the list of parameter groups.
1738     *
1739     * @return array list of parameter groups
1740     *
1741     * @access public
1742     *
1743     */
1744    function getGroups()
1745    {
1746        $tmp = array();
1747        foreach ($this->configuration_info as $key => $info) {
1748            $tmp[$info['group']] = 1;
1749        }
1750
1751        return array_keys($tmp);
1752    }
1753
1754    /**
1755     * Get the list of the parameters in a group.
1756     *
1757     * @param string $group parameter group
1758     * @return array list of parameters in $group
1759     *
1760     * @access public
1761     *
1762     */
1763    function getGroupKeys($group)
1764    {
1765        $keys = array();
1766        foreach ($this->configuration_info as $key => $info) {
1767            if ($info['group'] == $group) {
1768                $keys[] = $key;
1769            }
1770        }
1771
1772        return $keys;
1773    }
1774
1775    /**
1776     * Get the list of allowed set values for a config value.  Returns
1777     * NULL for config values that are not sets.
1778     *
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
1782     *
1783     * @access public
1784     *
1785     */
1786    function getSetValues($key)
1787    {
1788        if (isset($this->configuration_info[$key]) &&
1789            isset($this->configuration_info[$key]['type']) &&
1790            $this->configuration_info[$key]['type'] == 'set')
1791        {
1792            $valid_set = $this->configuration_info[$key]['valid_set'];
1793            reset($valid_set);
1794            if (key($valid_set) === 0) {
1795                return $valid_set;
1796            }
1797
1798            return array_keys($valid_set);
1799        }
1800
1801        return null;
1802    }
1803
1804    /**
1805     * Get all the current config keys.
1806     *
1807     * @return array simple array of config keys
1808     *
1809     * @access public
1810     */
1811    function getKeys()
1812    {
1813        $keys = array();
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);
1819                }
1820            }
1821
1822            unset($test['__channels']);
1823            $keys = array_merge($keys, $test);
1824
1825        }
1826        return array_keys($keys);
1827    }
1828
1829    /**
1830     * Remove the a config key from a specific config layer.
1831     *
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
1836     *
1837     * @access public
1838     */
1839    function remove($key, $layer = 'user', $channel = null)
1840    {
1841        if ($channel === null) {
1842            $channel = $this->getDefaultChannel();
1843        }
1844
1845        if ($channel !== 'pear.php.net') {
1846            if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
1847                unset($this->configuration[$layer]['__channels'][$channel][$key]);
1848                return true;
1849            }
1850        }
1851
1852        if (isset($this->configuration[$layer][$key])) {
1853            unset($this->configuration[$layer][$key]);
1854            return true;
1855        }
1856
1857        return false;
1858    }
1859
1860    /**
1861     * Temporarily remove an entire config layer.  USE WITH CARE!
1862     *
1863     * @param string config key
1864     * @param string (optional) config layer
1865     * @return bool TRUE on success, FALSE on failure
1866     *
1867     * @access public
1868     */
1869    function removeLayer($layer)
1870    {
1871        if (isset($this->configuration[$layer])) {
1872            $this->configuration[$layer] = array();
1873            return true;
1874        }
1875
1876        return false;
1877    }
1878
1879    /**
1880     * Stores configuration data in a layer.
1881     *
1882     * @param string config layer to store
1883     * @return bool TRUE on success, or PEAR error on failure
1884     *
1885     * @access public
1886     */
1887    function store($layer = 'user', $data = null)
1888    {
1889        return $this->writeConfigFile(null, $layer, $data);
1890    }
1891
1892    /**
1893     * Tells what config layer that gets to define a key.
1894     *
1895     * @param string config key
1896     * @param boolean return the defining channel
1897     *
1898     * @return string|array the config layer, or an empty string if not found.
1899     *
1900     *         if $returnchannel, the return is an array array('layer' => layername,
1901     *         'channel' => channelname), or an empty string if not found
1902     *
1903     * @access public
1904     */
1905    function definedBy($key, $returnchannel = false)
1906    {
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);
1913                    }
1914                    return $layer;
1915                }
1916            }
1917
1918            if (isset($this->configuration[$layer][$key])) {
1919                if ($returnchannel) {
1920                    return array('layer' => $layer, 'channel' => 'pear.php.net');
1921                }
1922                return $layer;
1923            }
1924        }
1925
1926        return '';
1927    }
1928
1929    /**
1930     * Tells whether a given key exists as a config value.
1931     *
1932     * @param string config key
1933     * @return bool whether <config key> exists in this object
1934     *
1935     * @access public
1936     */
1937    function isDefined($key)
1938    {
1939        foreach ($this->layers as $layer) {
1940            if (isset($this->configuration[$layer][$key])) {
1941                return true;
1942            }
1943        }
1944
1945        return false;
1946    }
1947
1948    /**
1949     * Tells whether a given config layer exists.
1950     *
1951     * @param string config layer
1952     * @return bool whether <config layer> exists in this object
1953     *
1954     * @access public
1955     */
1956    function isDefinedLayer($layer)
1957    {
1958        return isset($this->configuration[$layer]);
1959    }
1960
1961    /**
1962     * Returns the layers defined (except the 'default' one)
1963     *
1964     * @return array of the defined layers
1965     */
1966    function getLayers()
1967    {
1968        $cf = $this->configuration;
1969        unset($cf['default']);
1970        return array_keys($cf);
1971    }
1972
1973    function apiVersion()
1974    {
1975        return '1.1';
1976    }
1977
1978    /**
1979     * @return PEAR_Registry
1980     */
1981    function &getRegistry($use = null)
1982    {
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'];
1990        } elseif ($use) {
1991            $a = false;
1992            return $a;
1993        }
1994
1995        // only go here if null was passed in
1996        echo "CRITICAL ERROR: Registry could not be initialized from any value";
1997        exit(1);
1998    }
1999
2000    /**
2001     * This is to allow customization like the use of installroot
2002     * @param PEAR_Registry
2003     * @return bool
2004     */
2005    function setRegistry(&$reg, $layer = 'user')
2006    {
2007        if ($this->_noRegistry) {
2008            return false;
2009        }
2010
2011        if (!in_array($layer, array('user', 'system'))) {
2012            return false;
2013        }
2014
2015        $this->_registry[$layer] = &$reg;
2016        if (is_object($reg)) {
2017            $this->_registry[$layer]->setConfig($this, false);
2018        }
2019
2020        return true;
2021    }
2022
2023    function noRegistry()
2024    {
2025        $this->_noRegistry = true;
2026    }
2027
2028    /**
2029     * @return PEAR_REST
2030     */
2031    function &getREST($version, $options = array())
2032    {
2033        $version = str_replace('.', '', $version);
2034        if (!class_exists($class = 'PEAR_REST_' . $version)) {
2035            require_once 'PEAR/REST/' . $version . '.php';
2036        }
2037
2038        $remote = &new $class($this, $options);
2039        return $remote;
2040    }
2041
2042    /**
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
2046     */
2047    function &getFTP()
2048    {
2049        if (isset($this->_ftp)) {
2050            return $this->_ftp;
2051        }
2052
2053        $a = false;
2054        return $a;
2055    }
2056
2057    function _prependPath($path, $prepend)
2058    {
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";
2065                }
2066                $path = substr($path, 0, 2) . $prepend . substr($path, 2);
2067            } else {
2068                $path = $prepend . $path;
2069            }
2070        }
2071        return $path;
2072    }
2073
2074    /**
2075     * @param string|false installation directory to prepend to all _dir variables, or false to
2076     *                     disable
2077     */
2078    function setInstallRoot($root)
2079    {
2080        if (substr($root, -1) == DIRECTORY_SEPARATOR) {
2081            $root = substr($root, 0, -1);
2082        }
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])) {
2088                    continue;
2089                }
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;
2094            }
2095        }
2096    }
2097}
Note: See TracBrowser for help on using the repository browser.