Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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
 */
21
require_once 'PEAR.php';
22
require_once 'PEAR/Registry.php';
23
require_once 'PEAR/Installer/Role.php';
24
require_once 'System.php';
25
 
26
/**
27
 * Last created PEAR_Config instance.
28
 * @var object
29
 */
30
$GLOBALS['_PEAR_Config_instance'] = null;
31
if (!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
45
if (!defined('PEAR_RUNTYPE')) {
46
    define('PEAR_RUNTYPE', 'pear');
47
}
48
 
49
if (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
 
55
if (getenv('PHP_PEAR_SYSCONF_DIR')) {
56
    define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
57
} elseif (getenv('SystemRoot')) {
58
    define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
59
} else {
60
    define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
61
}
62
 
63
// Default for master_server
64
if (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
71
if (getenv('PHP_PEAR_HTTP_PROXY')) {
72
    define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
73
} elseif (getenv('http_proxy')) {
74
    define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
75
} else {
76
    define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
77
}
78
 
79
// Default for php_dir
80
if (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
91
if (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
107
if (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
115
if (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
122
if (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
130
if (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
138
if (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
146
if (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
154
if (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
163
if (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
172
if (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
181
if (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
189
if (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
196
if (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
203
if (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
210
if (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
217
if (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
224
if (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
233
if (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
 */
253
class 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
519
0: really quiet
520
1: somewhat quiet
521
2: verbose
522
3: 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
}