Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

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