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_PackageFile_v2, package.xml version 2.0
4
 *
5
 * PHP versions 4 and 5
6
 *
7
 * @category   pear
8
 * @package    PEAR
9
 * @author     Greg Beaver <cellog@php.net>
10
 * @copyright  1997-2009 The Authors
11
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
12
 * @version    CVS: $Id: v2.php 313023 2011-07-06 19:17:11Z dufuz $
13
 * @link       http://pear.php.net/package/PEAR
14
 * @since      File available since Release 1.4.0a1
15
 */
16
/**
17
 * For error handling
18
 */
19
require_once 'PEAR/ErrorStack.php';
20
/**
21
 * @category   pear
22
 * @package    PEAR
23
 * @author     Greg Beaver <cellog@php.net>
24
 * @copyright  1997-2009 The Authors
25
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
26
 * @version    Release: 1.9.4
27
 * @link       http://pear.php.net/package/PEAR
28
 * @since      Class available since Release 1.4.0a1
29
 */
30
class PEAR_PackageFile_v2
31
{
32
 
33
    /**
34
     * Parsed package information
35
     * @var array
36
     * @access private
37
     */
38
    var $_packageInfo = array();
39
 
40
    /**
41
     * path to package .tgz or false if this is a local/extracted package.xml
42
     * @var string|false
43
     * @access private
44
     */
45
    var $_archiveFile;
46
 
47
    /**
48
     * path to package .xml or false if this is an abstract parsed-from-string xml
49
     * @var string|false
50
     * @access private
51
     */
52
    var $_packageFile;
53
 
54
    /**
55
     * This is used by file analysis routines to log progress information
56
     * @var PEAR_Common
57
     * @access protected
58
     */
59
    var $_logger;
60
 
61
    /**
62
     * This is set to the highest validation level that has been validated
63
     *
64
     * If the package.xml is invalid or unknown, this is set to 0.  If
65
     * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL.  If
66
     * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING
67
     * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING.  This allows validation
68
     * "caching" to occur, which is particularly important for package validation, so
69
     * that PHP files are not validated twice
70
     * @var int
71
     * @access private
72
     */
73
    var $_isValid = 0;
74
 
75
    /**
76
     * True if the filelist has been validated
77
     * @param bool
78
     */
79
    var $_filesValid = false;
80
 
81
    /**
82
     * @var PEAR_Registry
83
     * @access protected
84
     */
85
    var $_registry;
86
 
87
    /**
88
     * @var PEAR_Config
89
     * @access protected
90
     */
91
    var $_config;
92
 
93
    /**
94
     * Optional Dependency group requested for installation
95
     * @var string
96
     * @access private
97
     */
98
    var $_requestedGroup = false;
99
 
100
    /**
101
     * @var PEAR_ErrorStack
102
     * @access protected
103
     */
104
    var $_stack;
105
 
106
    /**
107
     * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible
108
     */
109
    var $_tasksNs;
110
 
111
    /**
112
     * Determines whether this packagefile was initialized only with partial package info
113
     *
114
     * If this package file was constructed via parsing REST, it will only contain
115
     *
116
     * - package name
117
     * - channel name
118
     * - dependencies
119
     * @var boolean
120
     * @access private
121
     */
122
    var $_incomplete = true;
123
 
124
    /**
125
     * @var PEAR_PackageFile_v2_Validator
126
     */
127
    var $_v2Validator;
128
 
129
    /**
130
     * The constructor merely sets up the private error stack
131
     */
132
    function PEAR_PackageFile_v2()
133
    {
134
        $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null);
135
        $this->_isValid = false;
136
    }
137
 
138
    /**
139
     * To make unit-testing easier
140
     * @param PEAR_Frontend_*
141
     * @param array options
142
     * @param PEAR_Config
143
     * @return PEAR_Downloader
144
     * @access protected
145
     */
146
    function &getPEARDownloader(&$i, $o, &$c)
147
    {
148
        $z = &new PEAR_Downloader($i, $o, $c);
149
        return $z;
150
    }
151
 
152
    /**
153
     * To make unit-testing easier
154
     * @param PEAR_Config
155
     * @param array options
156
     * @param array package name as returned from {@link PEAR_Registry::parsePackageName()}
157
     * @param int PEAR_VALIDATE_* constant
158
     * @return PEAR_Dependency2
159
     * @access protected
160
     */
161
    function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING)
162
    {
163
        if (!class_exists('PEAR_Dependency2')) {
164
            require_once 'PEAR/Dependency2.php';
165
        }
166
        $z = &new PEAR_Dependency2($c, $o, $p, $s);
167
        return $z;
168
    }
169
 
170
    function getInstalledBinary()
171
    {
172
        return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] :
173
            false;
174
    }
175
 
176
    /**
177
     * Installation of source package has failed, attempt to download and install the
178
     * binary version of this package.
179
     * @param PEAR_Installer
180
     * @return array|false
181
     */
182
    function installBinary(&$installer)
183
    {
184
        if (!OS_WINDOWS) {
185
            $a = false;
186
            return $a;
187
        }
188
        if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
189
            $releasetype = $this->getPackageType() . 'release';
190
            if (!is_array($installer->getInstallPackages())) {
191
                $a = false;
192
                return $a;
193
            }
194
            foreach ($installer->getInstallPackages() as $p) {
195
                if ($p->isExtension($this->_packageInfo['providesextension'])) {
196
                    if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') {
197
                        $a = false;
198
                        return $a; // the user probably downloaded it separately
199
                    }
200
                }
201
            }
202
            if (isset($this->_packageInfo[$releasetype]['binarypackage'])) {
203
                $installer->log(0, 'Attempting to download binary version of extension "' .
204
                    $this->_packageInfo['providesextension'] . '"');
205
                $params = $this->_packageInfo[$releasetype]['binarypackage'];
206
                if (!is_array($params) || !isset($params[0])) {
207
                    $params = array($params);
208
                }
209
                if (isset($this->_packageInfo['channel'])) {
210
                    foreach ($params as $i => $param) {
211
                        $params[$i] = array('channel' => $this->_packageInfo['channel'],
212
                            'package' => $param, 'version' => $this->getVersion());
213
                    }
214
                }
215
                $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(),
216
                    $installer->config);
217
                $verbose = $dl->config->get('verbose');
218
                $dl->config->set('verbose', -1);
219
                foreach ($params as $param) {
220
                    PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
221
                    $ret = $dl->download(array($param));
222
                    PEAR::popErrorHandling();
223
                    if (is_array($ret) && count($ret)) {
224
                        break;
225
                    }
226
                }
227
                $dl->config->set('verbose', $verbose);
228
                if (is_array($ret)) {
229
                    if (count($ret) == 1) {
230
                        $pf = $ret[0]->getPackageFile();
231
                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
232
                        $err = $installer->install($ret[0]);
233
                        PEAR::popErrorHandling();
234
                        if (is_array($err)) {
235
                            $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage();
236
                            // "install" self, so all dependencies will work transparently
237
                            $this->_registry->addPackage2($this);
238
                            $installer->log(0, 'Download and install of binary extension "' .
239
                                $this->_registry->parsedPackageNameToString(
240
                                    array('channel' => $pf->getChannel(),
241
                                          'package' => $pf->getPackage()), true) . '" successful');
242
                            $a = array($ret[0], $err);
243
                            return $a;
244
                        }
245
                        $installer->log(0, 'Download and install of binary extension "' .
246
                            $this->_registry->parsedPackageNameToString(
247
                                    array('channel' => $pf->getChannel(),
248
                                          'package' => $pf->getPackage()), true) . '" failed');
249
                    }
250
                }
251
            }
252
        }
253
        $a = false;
254
        return $a;
255
    }
256
 
257
    /**
258
     * @return string|false Extension name
259
     */
260
    function getProvidesExtension()
261
    {
262
        if (in_array($this->getPackageType(),
263
              array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
264
            if (isset($this->_packageInfo['providesextension'])) {
265
                return $this->_packageInfo['providesextension'];
266
            }
267
        }
268
        return false;
269
    }
270
 
271
    /**
272
     * @param string Extension name
273
     * @return bool
274
     */
275
    function isExtension($extension)
276
    {
277
        if (in_array($this->getPackageType(),
278
              array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
279
            return $this->_packageInfo['providesextension'] == $extension;
280
        }
281
        return false;
282
    }
283
 
284
    /**
285
     * Tests whether every part of the package.xml 1.0 is represented in
286
     * this package.xml 2.0
287
     * @param PEAR_PackageFile_v1
288
     * @return bool
289
     */
290
    function isEquivalent($pf1)
291
    {
292
        if (!$pf1) {
293
            return true;
294
        }
295
        if ($this->getPackageType() == 'bundle') {
296
            return false;
297
        }
298
        $this->_stack->getErrors(true);
299
        if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) {
300
            return false;
301
        }
302
        $pass = true;
303
        if ($pf1->getPackage() != $this->getPackage()) {
304
            $this->_differentPackage($pf1->getPackage());
305
            $pass = false;
306
        }
307
        if ($pf1->getVersion() != $this->getVersion()) {
308
            $this->_differentVersion($pf1->getVersion());
309
            $pass = false;
310
        }
311
        if (trim($pf1->getSummary()) != $this->getSummary()) {
312
            $this->_differentSummary($pf1->getSummary());
313
            $pass = false;
314
        }
315
        if (preg_replace('/\s+/', '', $pf1->getDescription()) !=
316
              preg_replace('/\s+/', '', $this->getDescription())) {
317
            $this->_differentDescription($pf1->getDescription());
318
            $pass = false;
319
        }
320
        if ($pf1->getState() != $this->getState()) {
321
            $this->_differentState($pf1->getState());
322
            $pass = false;
323
        }
324
        if (!strstr(preg_replace('/\s+/', '', $this->getNotes()),
325
              preg_replace('/\s+/', '', $pf1->getNotes()))) {
326
            $this->_differentNotes($pf1->getNotes());
327
            $pass = false;
328
        }
329
        $mymaintainers = $this->getMaintainers();
330
        $yourmaintainers = $pf1->getMaintainers();
331
        for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) {
332
            $reset = false;
333
            for ($i2 = 0; $i2 < count($mymaintainers); $i2++) {
334
                if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) {
335
                    if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) {
336
                        $this->_differentRole($mymaintainers[$i2]['handle'],
337
                            $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']);
338
                        $pass = false;
339
                    }
340
                    if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) {
341
                        $this->_differentEmail($mymaintainers[$i2]['handle'],
342
                            $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']);
343
                        $pass = false;
344
                    }
345
                    if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) {
346
                        $this->_differentName($mymaintainers[$i2]['handle'],
347
                            $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']);
348
                        $pass = false;
349
                    }
350
                    unset($mymaintainers[$i2]);
351
                    $mymaintainers = array_values($mymaintainers);
352
                    unset($yourmaintainers[$i1]);
353
                    $yourmaintainers = array_values($yourmaintainers);
354
                    $reset = true;
355
                    break;
356
                }
357
            }
358
            if ($reset) {
359
                $i1 = -1;
360
            }
361
        }
362
        $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers);
363
        $filelist = $this->getFilelist();
364
        foreach ($pf1->getFilelist() as $file => $atts) {
365
            if (!isset($filelist[$file])) {
366
                $this->_missingFile($file);
367
                $pass = false;
368
            }
369
        }
370
        return $pass;
371
    }
372
 
373
    function _differentPackage($package)
374
    {
375
        $this->_stack->push(__FUNCTION__, 'error', array('package' => $package,
376
            'self' => $this->getPackage()),
377
            'package.xml 1.0 package "%package%" does not match "%self%"');
378
    }
379
 
380
    function _differentVersion($version)
381
    {
382
        $this->_stack->push(__FUNCTION__, 'error', array('version' => $version,
383
            'self' => $this->getVersion()),
384
            'package.xml 1.0 version "%version%" does not match "%self%"');
385
    }
386
 
387
    function _differentState($state)
388
    {
389
        $this->_stack->push(__FUNCTION__, 'error', array('state' => $state,
390
            'self' => $this->getState()),
391
            'package.xml 1.0 state "%state%" does not match "%self%"');
392
    }
393
 
394
    function _differentRole($handle, $role, $selfrole)
395
    {
396
        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
397
            'role' => $role, 'self' => $selfrole),
398
            'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"');
399
    }
400
 
401
    function _differentEmail($handle, $email, $selfemail)
402
    {
403
        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
404
            'email' => $email, 'self' => $selfemail),
405
            'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"');
406
    }
407
 
408
    function _differentName($handle, $name, $selfname)
409
    {
410
        $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
411
            'name' => $name, 'self' => $selfname),
412
            'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"');
413
    }
414
 
415
    function _unmatchedMaintainers($my, $yours)
416
    {
417
        if ($my) {
418
            array_walk($my, create_function('&$i, $k', '$i = $i["handle"];'));
419
            $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my),
420
                'package.xml 2.0 has unmatched extra maintainers "%handles%"');
421
        }
422
        if ($yours) {
423
            array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];'));
424
            $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours),
425
                'package.xml 1.0 has unmatched extra maintainers "%handles%"');
426
        }
427
    }
428
 
429
    function _differentNotes($notes)
430
    {
431
        $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...';
432
        $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() :
433
            substr($this->getNotes(), 0, 24) . '...';
434
        $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes,
435
            'self' => $truncmynotes),
436
            'package.xml 1.0 release notes "%notes%" do not match "%self%"');
437
    }
438
 
439
    function _differentSummary($summary)
440
    {
441
        $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...';
442
        $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() :
443
            substr($this->getsummary(), 0, 24) . '...';
444
        $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary,
445
            'self' => $truncmysummary),
446
            'package.xml 1.0 summary "%summary%" does not match "%self%"');
447
    }
448
 
449
    function _differentDescription($description)
450
    {
451
        $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...');
452
        $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() :
453
            substr($this->getdescription(), 0, 24) . '...');
454
        $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription,
455
            'self' => $truncmydescription),
456
            'package.xml 1.0 description "%description%" does not match "%self%"');
457
    }
458
 
459
    function _missingFile($file)
460
    {
461
        $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
462
            'package.xml 1.0 file "%file%" is not present in <contents>');
463
    }
464
 
465
    /**
466
     * WARNING - do not use this function unless you know what you're doing
467
     */
468
    function setRawState($state)
469
    {
470
        if (!isset($this->_packageInfo['stability'])) {
471
            $this->_packageInfo['stability'] = array();
472
        }
473
        $this->_packageInfo['stability']['release'] = $state;
474
    }
475
 
476
    /**
477
     * WARNING - do not use this function unless you know what you're doing
478
     */
479
    function setRawCompatible($compatible)
480
    {
481
        $this->_packageInfo['compatible'] = $compatible;
482
    }
483
 
484
    /**
485
     * WARNING - do not use this function unless you know what you're doing
486
     */
487
    function setRawPackage($package)
488
    {
489
        $this->_packageInfo['name'] = $package;
490
    }
491
 
492
    /**
493
     * WARNING - do not use this function unless you know what you're doing
494
     */
495
    function setRawChannel($channel)
496
    {
497
        $this->_packageInfo['channel'] = $channel;
498
    }
499
 
500
    function setRequestedGroup($group)
501
    {
502
        $this->_requestedGroup = $group;
503
    }
504
 
505
    function getRequestedGroup()
506
    {
507
        if (isset($this->_requestedGroup)) {
508
            return $this->_requestedGroup;
509
        }
510
        return false;
511
    }
512
 
513
    /**
514
     * For saving in the registry.
515
     *
516
     * Set the last version that was installed
517
     * @param string
518
     */
519
    function setLastInstalledVersion($version)
520
    {
521
        $this->_packageInfo['_lastversion'] = $version;
522
    }
523
 
524
    /**
525
     * @return string|false
526
     */
527
    function getLastInstalledVersion()
528
    {
529
        if (isset($this->_packageInfo['_lastversion'])) {
530
            return $this->_packageInfo['_lastversion'];
531
        }
532
        return false;
533
    }
534
 
535
    /**
536
     * Determines whether this package.xml has post-install scripts or not
537
     * @return array|false
538
     */
539
    function listPostinstallScripts()
540
    {
541
        $filelist = $this->getFilelist();
542
        $contents = $this->getContents();
543
        $contents = $contents['dir']['file'];
544
        if (!is_array($contents) || !isset($contents[0])) {
545
            $contents = array($contents);
546
        }
547
        $taskfiles = array();
548
        foreach ($contents as $file) {
549
            $atts = $file['attribs'];
550
            unset($file['attribs']);
551
            if (count($file)) {
552
                $taskfiles[$atts['name']] = $file;
553
            }
554
        }
555
        $common = new PEAR_Common;
556
        $common->debug = $this->_config->get('verbose');
557
        $this->_scripts = array();
558
        $ret = array();
559
        foreach ($taskfiles as $name => $tasks) {
560
            if (!isset($filelist[$name])) {
561
                // ignored files will not be in the filelist
562
                continue;
563
            }
564
            $atts = $filelist[$name];
565
            foreach ($tasks as $tag => $raw) {
566
                $task = $this->getTask($tag);
567
                $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL);
568
                if ($task->isScript()) {
569
                    $ret[] = $filelist[$name]['installed_as'];
570
                }
571
            }
572
        }
573
        if (count($ret)) {
574
            return $ret;
575
        }
576
        return false;
577
    }
578
 
579
    /**
580
     * Initialize post-install scripts for running
581
     *
582
     * This method can be used to detect post-install scripts, as the return value
583
     * indicates whether any exist
584
     * @return bool
585
     */
586
    function initPostinstallScripts()
587
    {
588
        $filelist = $this->getFilelist();
589
        $contents = $this->getContents();
590
        $contents = $contents['dir']['file'];
591
        if (!is_array($contents) || !isset($contents[0])) {
592
            $contents = array($contents);
593
        }
594
        $taskfiles = array();
595
        foreach ($contents as $file) {
596
            $atts = $file['attribs'];
597
            unset($file['attribs']);
598
            if (count($file)) {
599
                $taskfiles[$atts['name']] = $file;
600
            }
601
        }
602
        $common = new PEAR_Common;
603
        $common->debug = $this->_config->get('verbose');
604
        $this->_scripts = array();
605
        foreach ($taskfiles as $name => $tasks) {
606
            if (!isset($filelist[$name])) {
607
                // file was not installed due to installconditions
608
                continue;
609
            }
610
            $atts = $filelist[$name];
611
            foreach ($tasks as $tag => $raw) {
612
                $taskname = $this->getTask($tag);
613
                $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL);
614
                if (!$task->isScript()) {
615
                    continue; // scripts are only handled after installation
616
                }
617
                $lastversion = isset($this->_packageInfo['_lastversion']) ?
618
                    $this->_packageInfo['_lastversion'] : null;
619
                $task->init($raw, $atts, $lastversion);
620
                $res = $task->startSession($this, $atts['installed_as']);
621
                if (!$res) {
622
                    continue; // skip this file
623
                }
624
                if (PEAR::isError($res)) {
625
                    return $res;
626
                }
627
                $assign = &$task;
628
                $this->_scripts[] = &$assign;
629
            }
630
        }
631
        if (count($this->_scripts)) {
632
            return true;
633
        }
634
        return false;
635
    }
636
 
637
    function runPostinstallScripts()
638
    {
639
        if ($this->initPostinstallScripts()) {
640
            $ui = &PEAR_Frontend::singleton();
641
            if ($ui) {
642
                $ui->runPostinstallScripts($this->_scripts, $this);
643
            }
644
        }
645
    }
646
 
647
 
648
    /**
649
     * Convert a recursive set of <dir> and <file> tags into a single <dir> tag with
650
     * <file> tags.
651
     */
652
    function flattenFilelist()
653
    {
654
        if (isset($this->_packageInfo['bundle'])) {
655
            return;
656
        }
657
        $filelist = array();
658
        if (isset($this->_packageInfo['contents']['dir']['dir'])) {
659
            $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']);
660
            if (!isset($filelist[1])) {
661
                $filelist = $filelist[0];
662
            }
663
            $this->_packageInfo['contents']['dir']['file'] = $filelist;
664
            unset($this->_packageInfo['contents']['dir']['dir']);
665
        } else {
666
            // else already flattened but check for baseinstalldir propagation
667
            if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) {
668
                if (isset($this->_packageInfo['contents']['dir']['file'][0])) {
669
                    foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) {
670
                        if (isset($file['attribs']['baseinstalldir'])) {
671
                            continue;
672
                        }
673
                        $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir']
674
                            = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
675
                    }
676
                } else {
677
                    if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) {
678
                       $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir']
679
                            = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
680
                    }
681
                }
682
            }
683
        }
684
    }
685
 
686
    /**
687
     * @param array the final flattened file list
688
     * @param array the current directory being processed
689
     * @param string|false any recursively inherited baeinstalldir attribute
690
     * @param string private recursion variable
691
     * @return array
692
     * @access protected
693
     */
694
    function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '')
695
    {
696
        if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) {
697
            $baseinstall = $dir['attribs']['baseinstalldir'];
698
        }
699
        if (isset($dir['dir'])) {
700
            if (!isset($dir['dir'][0])) {
701
                $dir['dir'] = array($dir['dir']);
702
            }
703
            foreach ($dir['dir'] as $subdir) {
704
                if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) {
705
                    $name = '*unknown*';
706
                } else {
707
                    $name = $subdir['attribs']['name'];
708
                }
709
                $newpath = empty($path) ? $name :
710
                    $path . '/' . $name;
711
                $this->_getFlattenedFilelist($files, $subdir,
712
                    $baseinstall, $newpath);
713
            }
714
        }
715
        if (isset($dir['file'])) {
716
            if (!isset($dir['file'][0])) {
717
                $dir['file'] = array($dir['file']);
718
            }
719
            foreach ($dir['file'] as $file) {
720
                $attrs = $file['attribs'];
721
                $name = $attrs['name'];
722
                if ($baseinstall && !isset($attrs['baseinstalldir'])) {
723
                    $attrs['baseinstalldir'] = $baseinstall;
724
                }
725
                $attrs['name'] = empty($path) ? $name : $path . '/' . $name;
726
                $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
727
                    $attrs['name']);
728
                $file['attribs'] = $attrs;
729
                $files[] = $file;
730
            }
731
        }
732
    }
733
 
734
    function setConfig(&$config)
735
    {
736
        $this->_config = &$config;
737
        $this->_registry = &$config->getRegistry();
738
    }
739
 
740
    function setLogger(&$logger)
741
    {
742
        if (!is_object($logger) || !method_exists($logger, 'log')) {
743
            return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
744
        }
745
        $this->_logger = &$logger;
746
    }
747
 
748
    /**
749
     * WARNING - do not use this function directly unless you know what you're doing
750
     */
751
    function setDeps($deps)
752
    {
753
        $this->_packageInfo['dependencies'] = $deps;
754
    }
755
 
756
    /**
757
     * WARNING - do not use this function directly unless you know what you're doing
758
     */
759
    function setCompatible($compat)
760
    {
761
        $this->_packageInfo['compatible'] = $compat;
762
    }
763
 
764
    function setPackagefile($file, $archive = false)
765
    {
766
        $this->_packageFile = $file;
767
        $this->_archiveFile = $archive ? $archive : $file;
768
    }
769
 
770
    /**
771
     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
772
     * @param boolean determines whether to purge the error stack after retrieving
773
     * @return array
774
     */
775
    function getValidationWarnings($purge = true)
776
    {
777
        return $this->_stack->getErrors($purge);
778
    }
779
 
780
    function getPackageFile()
781
    {
782
        return $this->_packageFile;
783
    }
784
 
785
    function getArchiveFile()
786
    {
787
        return $this->_archiveFile;
788
    }
789
 
790
 
791
    /**
792
     * Directly set the array that defines this packagefile
793
     *
794
     * WARNING: no validation.  This should only be performed by internal methods
795
     * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2
796
     * @param array
797
     */
798
    function fromArray($pinfo)
799
    {
800
        unset($pinfo['old']);
801
        unset($pinfo['xsdversion']);
802
        // If the changelog isn't an array then it was passed in as an empty tag
803
        if (isset($pinfo['changelog']) && !is_array($pinfo['changelog'])) {
804
          unset($pinfo['changelog']);
805
        }
806
        $this->_incomplete = false;
807
        $this->_packageInfo = $pinfo;
808
    }
809
 
810
    function isIncomplete()
811
    {
812
        return $this->_incomplete;
813
    }
814
 
815
    /**
816
     * @return array
817
     */
818
    function toArray($forreg = false)
819
    {
820
        if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
821
            return false;
822
        }
823
        return $this->getArray($forreg);
824
    }
825
 
826
    function getArray($forReg = false)
827
    {
828
        if ($forReg) {
829
            $arr = $this->_packageInfo;
830
            $arr['old'] = array();
831
            $arr['old']['version'] = $this->getVersion();
832
            $arr['old']['release_date'] = $this->getDate();
833
            $arr['old']['release_state'] = $this->getState();
834
            $arr['old']['release_license'] = $this->getLicense();
835
            $arr['old']['release_notes'] = $this->getNotes();
836
            $arr['old']['release_deps'] = $this->getDeps();
837
            $arr['old']['maintainers'] = $this->getMaintainers();
838
            $arr['xsdversion'] = '2.0';
839
            return $arr;
840
        } else {
841
            $info = $this->_packageInfo;
842
            unset($info['dirtree']);
843
            if (isset($info['_lastversion'])) {
844
                unset($info['_lastversion']);
845
            }
846
            if (isset($info['#binarypackage'])) {
847
                unset($info['#binarypackage']);
848
            }
849
            return $info;
850
        }
851
    }
852
 
853
    function packageInfo($field)
854
    {
855
        $arr = $this->getArray(true);
856
        if ($field == 'state') {
857
            return $arr['stability']['release'];
858
        }
859
        if ($field == 'api-version') {
860
            return $arr['version']['api'];
861
        }
862
        if ($field == 'api-state') {
863
            return $arr['stability']['api'];
864
        }
865
        if (isset($arr['old'][$field])) {
866
            if (!is_string($arr['old'][$field])) {
867
                return null;
868
            }
869
            return $arr['old'][$field];
870
        }
871
        if (isset($arr[$field])) {
872
            if (!is_string($arr[$field])) {
873
                return null;
874
            }
875
            return $arr[$field];
876
        }
877
        return null;
878
    }
879
 
880
    function getName()
881
    {
882
        return $this->getPackage();
883
    }
884
 
885
    function getPackage()
886
    {
887
        if (isset($this->_packageInfo['name'])) {
888
            return $this->_packageInfo['name'];
889
        }
890
        return false;
891
    }
892
 
893
    function getChannel()
894
    {
895
        if (isset($this->_packageInfo['uri'])) {
896
            return '__uri';
897
        }
898
        if (isset($this->_packageInfo['channel'])) {
899
            return strtolower($this->_packageInfo['channel']);
900
        }
901
        return false;
902
    }
903
 
904
    function getUri()
905
    {
906
        if (isset($this->_packageInfo['uri'])) {
907
            return $this->_packageInfo['uri'];
908
        }
909
        return false;
910
    }
911
 
912
    function getExtends()
913
    {
914
        if (isset($this->_packageInfo['extends'])) {
915
            return $this->_packageInfo['extends'];
916
        }
917
        return false;
918
    }
919
 
920
    function getSummary()
921
    {
922
        if (isset($this->_packageInfo['summary'])) {
923
            return $this->_packageInfo['summary'];
924
        }
925
        return false;
926
    }
927
 
928
    function getDescription()
929
    {
930
        if (isset($this->_packageInfo['description'])) {
931
            return $this->_packageInfo['description'];
932
        }
933
        return false;
934
    }
935
 
936
    function getMaintainers($raw = false)
937
    {
938
        if (!isset($this->_packageInfo['lead'])) {
939
            return false;
940
        }
941
        if ($raw) {
942
            $ret = array('lead' => $this->_packageInfo['lead']);
943
            (isset($this->_packageInfo['developer'])) ?
944
                $ret['developer'] = $this->_packageInfo['developer'] :null;
945
            (isset($this->_packageInfo['contributor'])) ?
946
                $ret['contributor'] = $this->_packageInfo['contributor'] :null;
947
            (isset($this->_packageInfo['helper'])) ?
948
                $ret['helper'] = $this->_packageInfo['helper'] :null;
949
            return $ret;
950
        } else {
951
            $ret = array();
952
            $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] :
953
                array($this->_packageInfo['lead']);
954
            foreach ($leads as $lead) {
955
                $s = $lead;
956
                $s['handle'] = $s['user'];
957
                unset($s['user']);
958
                $s['role'] = 'lead';
959
                $ret[] = $s;
960
            }
961
            if (isset($this->_packageInfo['developer'])) {
962
                $leads = isset($this->_packageInfo['developer'][0]) ?
963
                    $this->_packageInfo['developer'] :
964
                    array($this->_packageInfo['developer']);
965
                foreach ($leads as $maintainer) {
966
                    $s = $maintainer;
967
                    $s['handle'] = $s['user'];
968
                    unset($s['user']);
969
                    $s['role'] = 'developer';
970
                    $ret[] = $s;
971
                }
972
            }
973
            if (isset($this->_packageInfo['contributor'])) {
974
                $leads = isset($this->_packageInfo['contributor'][0]) ?
975
                    $this->_packageInfo['contributor'] :
976
                    array($this->_packageInfo['contributor']);
977
                foreach ($leads as $maintainer) {
978
                    $s = $maintainer;
979
                    $s['handle'] = $s['user'];
980
                    unset($s['user']);
981
                    $s['role'] = 'contributor';
982
                    $ret[] = $s;
983
                }
984
            }
985
            if (isset($this->_packageInfo['helper'])) {
986
                $leads = isset($this->_packageInfo['helper'][0]) ?
987
                    $this->_packageInfo['helper'] :
988
                    array($this->_packageInfo['helper']);
989
                foreach ($leads as $maintainer) {
990
                    $s = $maintainer;
991
                    $s['handle'] = $s['user'];
992
                    unset($s['user']);
993
                    $s['role'] = 'helper';
994
                    $ret[] = $s;
995
                }
996
            }
997
            return $ret;
998
        }
999
        return false;
1000
    }
1001
 
1002
    function getLeads()
1003
    {
1004
        if (isset($this->_packageInfo['lead'])) {
1005
            return $this->_packageInfo['lead'];
1006
        }
1007
        return false;
1008
    }
1009
 
1010
    function getDevelopers()
1011
    {
1012
        if (isset($this->_packageInfo['developer'])) {
1013
            return $this->_packageInfo['developer'];
1014
        }
1015
        return false;
1016
    }
1017
 
1018
    function getContributors()
1019
    {
1020
        if (isset($this->_packageInfo['contributor'])) {
1021
            return $this->_packageInfo['contributor'];
1022
        }
1023
        return false;
1024
    }
1025
 
1026
    function getHelpers()
1027
    {
1028
        if (isset($this->_packageInfo['helper'])) {
1029
            return $this->_packageInfo['helper'];
1030
        }
1031
        return false;
1032
    }
1033
 
1034
    function setDate($date)
1035
    {
1036
        if (!isset($this->_packageInfo['date'])) {
1037
            // ensure that the extends tag is set up in the right location
1038
            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
1039
                array('time', 'version',
1040
                    'stability', 'license', 'notes', 'contents', 'compatible',
1041
                    'dependencies', 'providesextension', 'srcpackage', 'srcuri',
1042
                    'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
1043
                    'zendextbinrelease', 'bundle', 'changelog'), array(), 'date');
1044
        }
1045
        $this->_packageInfo['date'] = $date;
1046
        $this->_isValid = 0;
1047
    }
1048
 
1049
    function setTime($time)
1050
    {
1051
        $this->_isValid = 0;
1052
        if (!isset($this->_packageInfo['time'])) {
1053
            // ensure that the time tag is set up in the right location
1054
            $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
1055
                    array('version',
1056
                    'stability', 'license', 'notes', 'contents', 'compatible',
1057
                    'dependencies', 'providesextension', 'srcpackage', 'srcuri',
1058
                    'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
1059
                    'zendextbinrelease', 'bundle', 'changelog'), $time, 'time');
1060
        }
1061
        $this->_packageInfo['time'] = $time;
1062
    }
1063
 
1064
    function getDate()
1065
    {
1066
        if (isset($this->_packageInfo['date'])) {
1067
            return $this->_packageInfo['date'];
1068
        }
1069
        return false;
1070
    }
1071
 
1072
    function getTime()
1073
    {
1074
        if (isset($this->_packageInfo['time'])) {
1075
            return $this->_packageInfo['time'];
1076
        }
1077
        return false;
1078
    }
1079
 
1080
    /**
1081
     * @param package|api version category to return
1082
     */
1083
    function getVersion($key = 'release')
1084
    {
1085
        if (isset($this->_packageInfo['version'][$key])) {
1086
            return $this->_packageInfo['version'][$key];
1087
        }
1088
        return false;
1089
    }
1090
 
1091
    function getStability()
1092
    {
1093
        if (isset($this->_packageInfo['stability'])) {
1094
            return $this->_packageInfo['stability'];
1095
        }
1096
        return false;
1097
    }
1098
 
1099
    function getState($key = 'release')
1100
    {
1101
        if (isset($this->_packageInfo['stability'][$key])) {
1102
            return $this->_packageInfo['stability'][$key];
1103
        }
1104
        return false;
1105
    }
1106
 
1107
    function getLicense($raw = false)
1108
    {
1109
        if (isset($this->_packageInfo['license'])) {
1110
            if ($raw) {
1111
                return $this->_packageInfo['license'];
1112
            }
1113
            if (is_array($this->_packageInfo['license'])) {
1114
                return $this->_packageInfo['license']['_content'];
1115
            } else {
1116
                return $this->_packageInfo['license'];
1117
            }
1118
        }
1119
        return false;
1120
    }
1121
 
1122
    function getLicenseLocation()
1123
    {
1124
        if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) {
1125
            return false;
1126
        }
1127
        return $this->_packageInfo['license']['attribs'];
1128
    }
1129
 
1130
    function getNotes()
1131
    {
1132
        if (isset($this->_packageInfo['notes'])) {
1133
            return $this->_packageInfo['notes'];
1134
        }
1135
        return false;
1136
    }
1137
 
1138
    /**
1139
     * Return the <usesrole> tag contents, if any
1140
     * @return array|false
1141
     */
1142
    function getUsesrole()
1143
    {
1144
        if (isset($this->_packageInfo['usesrole'])) {
1145
            return $this->_packageInfo['usesrole'];
1146
        }
1147
        return false;
1148
    }
1149
 
1150
    /**
1151
     * Return the <usestask> tag contents, if any
1152
     * @return array|false
1153
     */
1154
    function getUsestask()
1155
    {
1156
        if (isset($this->_packageInfo['usestask'])) {
1157
            return $this->_packageInfo['usestask'];
1158
        }
1159
        return false;
1160
    }
1161
 
1162
    /**
1163
     * This should only be used to retrieve filenames and install attributes
1164
     */
1165
    function getFilelist($preserve = false)
1166
    {
1167
        if (isset($this->_packageInfo['filelist']) && !$preserve) {
1168
            return $this->_packageInfo['filelist'];
1169
        }
1170
        $this->flattenFilelist();
1171
        if ($contents = $this->getContents()) {
1172
            $ret = array();
1173
            if (!isset($contents['dir'])) {
1174
                return false;
1175
            }
1176
            if (!isset($contents['dir']['file'][0])) {
1177
                $contents['dir']['file'] = array($contents['dir']['file']);
1178
            }
1179
            foreach ($contents['dir']['file'] as $file) {
1180
                $name = $file['attribs']['name'];
1181
                if (!$preserve) {
1182
                    $file = $file['attribs'];
1183
                }
1184
                $ret[$name] = $file;
1185
            }
1186
            if (!$preserve) {
1187
                $this->_packageInfo['filelist'] = $ret;
1188
            }
1189
            return $ret;
1190
        }
1191
        return false;
1192
    }
1193
 
1194
    /**
1195
     * Return configure options array, if any
1196
     *
1197
     * @return array|false
1198
     */
1199
    function getConfigureOptions()
1200
    {
1201
        if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
1202
            return false;
1203
        }
1204
 
1205
        $releases = $this->getReleases();
1206
        if (isset($releases[0])) {
1207
            $releases = $releases[0];
1208
        }
1209
 
1210
        if (isset($releases['configureoption'])) {
1211
            if (!isset($releases['configureoption'][0])) {
1212
                $releases['configureoption'] = array($releases['configureoption']);
1213
            }
1214
 
1215
            for ($i = 0; $i < count($releases['configureoption']); $i++) {
1216
                $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs'];
1217
            }
1218
 
1219
            return $releases['configureoption'];
1220
        }
1221
 
1222
        return false;
1223
    }
1224
 
1225
    /**
1226
     * This is only used at install-time, after all serialization
1227
     * is over.
1228
     */
1229
    function resetFilelist()
1230
    {
1231
        $this->_packageInfo['filelist'] = array();
1232
    }
1233
 
1234
    /**
1235
     * Retrieve a list of files that should be installed on this computer
1236
     * @return array
1237
     */
1238
    function getInstallationFilelist($forfilecheck = false)
1239
    {
1240
        $contents = $this->getFilelist(true);
1241
        if (isset($contents['dir']['attribs']['baseinstalldir'])) {
1242
            $base = $contents['dir']['attribs']['baseinstalldir'];
1243
        }
1244
        if (isset($this->_packageInfo['bundle'])) {
1245
            return PEAR::raiseError(
1246
                'Exception: bundles should be handled in download code only');
1247
        }
1248
        $release = $this->getReleases();
1249
        if ($release) {
1250
            if (!isset($release[0])) {
1251
                if (!isset($release['installconditions']) && !isset($release['filelist'])) {
1252
                    if ($forfilecheck) {
1253
                        return $this->getFilelist();
1254
                    }
1255
                    return $contents;
1256
                }
1257
                $release = array($release);
1258
            }
1259
            $depchecker = &$this->getPEARDependency2($this->_config, array(),
1260
                array('channel' => $this->getChannel(), 'package' => $this->getPackage()),
1261
                PEAR_VALIDATE_INSTALLING);
1262
            foreach ($release as $instance) {
1263
                if (isset($instance['installconditions'])) {
1264
                    $installconditions = $instance['installconditions'];
1265
                    if (is_array($installconditions)) {
1266
                        PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
1267
                        foreach ($installconditions as $type => $conditions) {
1268
                            if (!isset($conditions[0])) {
1269
                                $conditions = array($conditions);
1270
                            }
1271
                            foreach ($conditions as $condition) {
1272
                                $ret = $depchecker->{"validate{$type}Dependency"}($condition);
1273
                                if (PEAR::isError($ret)) {
1274
                                    PEAR::popErrorHandling();
1275
                                    continue 3; // skip this release
1276
                                }
1277
                            }
1278
                        }
1279
                        PEAR::popErrorHandling();
1280
                    }
1281
                }
1282
                // this is the release to use
1283
                if (isset($instance['filelist'])) {
1284
                    // ignore files
1285
                    if (isset($instance['filelist']['ignore'])) {
1286
                        $ignore = isset($instance['filelist']['ignore'][0]) ?
1287
                            $instance['filelist']['ignore'] :
1288
                            array($instance['filelist']['ignore']);
1289
                        foreach ($ignore as $ig) {
1290
                            unset ($contents[$ig['attribs']['name']]);
1291
                        }
1292
                    }
1293
                    // install files as this name
1294
                    if (isset($instance['filelist']['install'])) {
1295
                        $installas = isset($instance['filelist']['install'][0]) ?
1296
                            $instance['filelist']['install'] :
1297
                            array($instance['filelist']['install']);
1298
                        foreach ($installas as $as) {
1299
                            $contents[$as['attribs']['name']]['attribs']['install-as'] =
1300
                                $as['attribs']['as'];
1301
                        }
1302
                    }
1303
                }
1304
                if ($forfilecheck) {
1305
                    foreach ($contents as $file => $attrs) {
1306
                        $contents[$file] = $attrs['attribs'];
1307
                    }
1308
                }
1309
                return $contents;
1310
            }
1311
        } else { // simple release - no installconditions or install-as
1312
            if ($forfilecheck) {
1313
                return $this->getFilelist();
1314
            }
1315
            return $contents;
1316
        }
1317
        // no releases matched
1318
        return PEAR::raiseError('No releases in package.xml matched the existing operating ' .
1319
            'system, extensions installed, or architecture, cannot install');
1320
    }
1321
 
1322
    /**
1323
     * This is only used at install-time, after all serialization
1324
     * is over.
1325
     * @param string file name
1326
     * @param string installed path
1327
     */
1328
    function setInstalledAs($file, $path)
1329
    {
1330
        if ($path) {
1331
            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
1332
        }
1333
        unset($this->_packageInfo['filelist'][$file]['installed_as']);
1334
    }
1335
 
1336
    function getInstalledLocation($file)
1337
    {
1338
        if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) {
1339
            return $this->_packageInfo['filelist'][$file]['installed_as'];
1340
        }
1341
        return false;
1342
    }
1343
 
1344
    /**
1345
     * This is only used at install-time, after all serialization
1346
     * is over.
1347
     */
1348
    function installedFile($file, $atts)
1349
    {
1350
        if (isset($this->_packageInfo['filelist'][$file])) {
1351
            $this->_packageInfo['filelist'][$file] =
1352
                array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
1353
        } else {
1354
            $this->_packageInfo['filelist'][$file] = $atts['attribs'];
1355
        }
1356
    }
1357
 
1358
    /**
1359
     * Retrieve the contents tag
1360
     */
1361
    function getContents()
1362
    {
1363
        if (isset($this->_packageInfo['contents'])) {
1364
            return $this->_packageInfo['contents'];
1365
        }
1366
        return false;
1367
    }
1368
 
1369
    /**
1370
     * @param string full path to file
1371
     * @param string attribute name
1372
     * @param string attribute value
1373
     * @param int risky but fast - use this to choose a file based on its position in the list
1374
     *            of files.  Index is zero-based like PHP arrays.
1375
     * @return bool success of operation
1376
     */
1377
    function setFileAttribute($filename, $attr, $value, $index = false)
1378
    {
1379
        $this->_isValid = 0;
1380
        if (in_array($attr, array('role', 'name', 'baseinstalldir'))) {
1381
            $this->_filesValid = false;
1382
        }
1383
        if ($index !== false &&
1384
              isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) {
1385
            $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value;
1386
            return true;
1387
        }
1388
        if (!isset($this->_packageInfo['contents']['dir']['file'])) {
1389
            return false;
1390
        }
1391
        $files = $this->_packageInfo['contents']['dir']['file'];
1392
        if (!isset($files[0])) {
1393
            $files = array($files);
1394
            $ind = false;
1395
        } else {
1396
            $ind = true;
1397
        }
1398
        foreach ($files as $i => $file) {
1399
            if (isset($file['attribs'])) {
1400
                if ($file['attribs']['name'] == $filename) {
1401
                    if ($ind) {
1402
                        $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value;
1403
                    } else {
1404
                        $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value;
1405
                    }
1406
                    return true;
1407
                }
1408
            }
1409
        }
1410
        return false;
1411
    }
1412
 
1413
    function setDirtree($path)
1414
    {
1415
        if (!isset($this->_packageInfo['dirtree'])) {
1416
            $this->_packageInfo['dirtree'] = array();
1417
        }
1418
        $this->_packageInfo['dirtree'][$path] = true;
1419
    }
1420
 
1421
    function getDirtree()
1422
    {
1423
        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
1424
            return $this->_packageInfo['dirtree'];
1425
        }
1426
        return false;
1427
    }
1428
 
1429
    function resetDirtree()
1430
    {
1431
        unset($this->_packageInfo['dirtree']);
1432
    }
1433
 
1434
    /**
1435
     * Determines whether this package claims it is compatible with the version of
1436
     * the package that has a recommended version dependency
1437
     * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package
1438
     * @return boolean
1439
     */
1440
    function isCompatible($pf)
1441
    {
1442
        if (!isset($this->_packageInfo['compatible'])) {
1443
            return false;
1444
        }
1445
        if (!isset($this->_packageInfo['channel'])) {
1446
            return false;
1447
        }
1448
        $me = $pf->getVersion();
1449
        $compatible = $this->_packageInfo['compatible'];
1450
        if (!isset($compatible[0])) {
1451
            $compatible = array($compatible);
1452
        }
1453
        $found = false;
1454
        foreach ($compatible as $info) {
1455
            if (strtolower($info['name']) == strtolower($pf->getPackage())) {
1456
                if (strtolower($info['channel']) == strtolower($pf->getChannel())) {
1457
                    $found = true;
1458
                    break;
1459
                }
1460
            }
1461
        }
1462
        if (!$found) {
1463
            return false;
1464
        }
1465
        if (isset($info['exclude'])) {
1466
            if (!isset($info['exclude'][0])) {
1467
                $info['exclude'] = array($info['exclude']);
1468
            }
1469
            foreach ($info['exclude'] as $exclude) {
1470
                if (version_compare($me, $exclude, '==')) {
1471
                    return false;
1472
                }
1473
            }
1474
        }
1475
        if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) {
1476
            return true;
1477
        }
1478
        return false;
1479
    }
1480
 
1481
    /**
1482
     * @return array|false
1483
     */
1484
    function getCompatible()
1485
    {
1486
        if (isset($this->_packageInfo['compatible'])) {
1487
            return $this->_packageInfo['compatible'];
1488
        }
1489
        return false;
1490
    }
1491
 
1492
    function getDependencies()
1493
    {
1494
        if (isset($this->_packageInfo['dependencies'])) {
1495
            return $this->_packageInfo['dependencies'];
1496
        }
1497
        return false;
1498
    }
1499
 
1500
    function isSubpackageOf($p)
1501
    {
1502
        return $p->isSubpackage($this);
1503
    }
1504
 
1505
    /**
1506
     * Determines whether the passed in package is a subpackage of this package.
1507
     *
1508
     * No version checking is done, only name verification.
1509
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
1510
     * @return bool
1511
     */
1512
    function isSubpackage($p)
1513
    {
1514
        $sub = array();
1515
        if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) {
1516
            $sub = $this->_packageInfo['dependencies']['required']['subpackage'];
1517
            if (!isset($sub[0])) {
1518
                $sub = array($sub);
1519
            }
1520
        }
1521
        if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) {
1522
            $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage'];
1523
            if (!isset($sub1[0])) {
1524
                $sub1 = array($sub1);
1525
            }
1526
            $sub = array_merge($sub, $sub1);
1527
        }
1528
        if (isset($this->_packageInfo['dependencies']['group'])) {
1529
            $group = $this->_packageInfo['dependencies']['group'];
1530
            if (!isset($group[0])) {
1531
                $group = array($group);
1532
            }
1533
            foreach ($group as $deps) {
1534
                if (isset($deps['subpackage'])) {
1535
                    $sub2 = $deps['subpackage'];
1536
                    if (!isset($sub2[0])) {
1537
                        $sub2 = array($sub2);
1538
                    }
1539
                    $sub = array_merge($sub, $sub2);
1540
                }
1541
            }
1542
        }
1543
        foreach ($sub as $dep) {
1544
            if (strtolower($dep['name']) == strtolower($p->getPackage())) {
1545
                if (isset($dep['channel'])) {
1546
                    if (strtolower($dep['channel']) == strtolower($p->getChannel())) {
1547
                        return true;
1548
                    }
1549
                } else {
1550
                    if ($dep['uri'] == $p->getURI()) {
1551
                        return true;
1552
                    }
1553
                }
1554
            }
1555
        }
1556
        return false;
1557
    }
1558
 
1559
    function dependsOn($package, $channel)
1560
    {
1561
        if (!($deps = $this->getDependencies())) {
1562
            return false;
1563
        }
1564
        foreach (array('package', 'subpackage') as $type) {
1565
            foreach (array('required', 'optional') as $needed) {
1566
                if (isset($deps[$needed][$type])) {
1567
                    if (!isset($deps[$needed][$type][0])) {
1568
                        $deps[$needed][$type] = array($deps[$needed][$type]);
1569
                    }
1570
                    foreach ($deps[$needed][$type] as $dep) {
1571
                        $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
1572
                        if (strtolower($dep['name']) == strtolower($package) &&
1573
                              $depchannel == $channel) {
1574
                            return true;
1575
                        }
1576
                    }
1577
                }
1578
            }
1579
            if (isset($deps['group'])) {
1580
                if (!isset($deps['group'][0])) {
1581
                    $dep['group'] = array($deps['group']);
1582
                }
1583
                foreach ($deps['group'] as $group) {
1584
                    if (isset($group[$type])) {
1585
                        if (!is_array($group[$type])) {
1586
                            $group[$type] = array($group[$type]);
1587
                        }
1588
                        foreach ($group[$type] as $dep) {
1589
                            $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
1590
                            if (strtolower($dep['name']) == strtolower($package) &&
1591
                                  $depchannel == $channel) {
1592
                                return true;
1593
                            }
1594
                        }
1595
                    }
1596
                }
1597
            }
1598
        }
1599
        return false;
1600
    }
1601
 
1602
    /**
1603
     * Get the contents of a dependency group
1604
     * @param string
1605
     * @return array|false
1606
     */
1607
    function getDependencyGroup($name)
1608
    {
1609
        $name = strtolower($name);
1610
        if (!isset($this->_packageInfo['dependencies']['group'])) {
1611
            return false;
1612
        }
1613
        $groups = $this->_packageInfo['dependencies']['group'];
1614
        if (!isset($groups[0])) {
1615
            $groups = array($groups);
1616
        }
1617
        foreach ($groups as $group) {
1618
            if (strtolower($group['attribs']['name']) == $name) {
1619
                return $group;
1620
            }
1621
        }
1622
        return false;
1623
    }
1624
 
1625
    /**
1626
     * Retrieve a partial package.xml 1.0 representation of dependencies
1627
     *
1628
     * a very limited representation of dependencies is returned by this method.
1629
     * The <exclude> tag for excluding certain versions of a dependency is
1630
     * completely ignored.  In addition, dependency groups are ignored, with the
1631
     * assumption that all dependencies in dependency groups are also listed in
1632
     * the optional group that work with all dependency groups
1633
     * @param boolean return package.xml 2.0 <dependencies> tag
1634
     * @return array|false
1635
     */
1636
    function getDeps($raw = false, $nopearinstaller = false)
1637
    {
1638
        if (isset($this->_packageInfo['dependencies'])) {
1639
            if ($raw) {
1640
                return $this->_packageInfo['dependencies'];
1641
            }
1642
            $ret = array();
1643
            $map = array(
1644
                'php' => 'php',
1645
                'package' => 'pkg',
1646
                'subpackage' => 'pkg',
1647
                'extension' => 'ext',
1648
                'os' => 'os',
1649
                'pearinstaller' => 'pkg',
1650
                );
1651
            foreach (array('required', 'optional') as $type) {
1652
                $optional = ($type == 'optional') ? 'yes' : 'no';
1653
                if (!isset($this->_packageInfo['dependencies'][$type])
1654
                    || empty($this->_packageInfo['dependencies'][$type])) {
1655
                    continue;
1656
                }
1657
                foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) {
1658
                    if ($dtype == 'pearinstaller' && $nopearinstaller) {
1659
                        continue;
1660
                    }
1661
                    if (!isset($deps[0])) {
1662
                        $deps = array($deps);
1663
                    }
1664
                    foreach ($deps as $dep) {
1665
                        if (!isset($map[$dtype])) {
1666
                            // no support for arch type
1667
                            continue;
1668
                        }
1669
                        if ($dtype == 'pearinstaller') {
1670
                            $dep['name'] = 'PEAR';
1671
                            $dep['channel'] = 'pear.php.net';
1672
                        }
1673
                        $s = array('type' => $map[$dtype]);
1674
                        if (isset($dep['channel'])) {
1675
                            $s['channel'] = $dep['channel'];
1676
                        }
1677
                        if (isset($dep['uri'])) {
1678
                            $s['uri'] = $dep['uri'];
1679
                        }
1680
                        if (isset($dep['name'])) {
1681
                            $s['name'] = $dep['name'];
1682
                        }
1683
                        if (isset($dep['conflicts'])) {
1684
                            $s['rel'] = 'not';
1685
                        } else {
1686
                            if (!isset($dep['min']) &&
1687
                                  !isset($dep['max'])) {
1688
                                $s['rel'] = 'has';
1689
                                $s['optional'] = $optional;
1690
                            } elseif (isset($dep['min']) &&
1691
                                  isset($dep['max'])) {
1692
                                $s['rel'] = 'ge';
1693
                                $s1 = $s;
1694
                                $s1['rel'] = 'le';
1695
                                $s['version'] = $dep['min'];
1696
                                $s1['version'] = $dep['max'];
1697
                                if (isset($dep['channel'])) {
1698
                                    $s1['channel'] = $dep['channel'];
1699
                                }
1700
                                if ($dtype != 'php') {
1701
                                    $s['name'] = $dep['name'];
1702
                                    $s1['name'] = $dep['name'];
1703
                                }
1704
                                $s['optional'] = $optional;
1705
                                $s1['optional'] = $optional;
1706
                                $ret[] = $s1;
1707
                            } elseif (isset($dep['min'])) {
1708
                                if (isset($dep['exclude']) &&
1709
                                      $dep['exclude'] == $dep['min']) {
1710
                                    $s['rel'] = 'gt';
1711
                                } else {
1712
                                    $s['rel'] = 'ge';
1713
                                }
1714
                                $s['version'] = $dep['min'];
1715
                                $s['optional'] = $optional;
1716
                                if ($dtype != 'php') {
1717
                                    $s['name'] = $dep['name'];
1718
                                }
1719
                            } elseif (isset($dep['max'])) {
1720
                                if (isset($dep['exclude']) &&
1721
                                      $dep['exclude'] == $dep['max']) {
1722
                                    $s['rel'] = 'lt';
1723
                                } else {
1724
                                    $s['rel'] = 'le';
1725
                                }
1726
                                $s['version'] = $dep['max'];
1727
                                $s['optional'] = $optional;
1728
                                if ($dtype != 'php') {
1729
                                    $s['name'] = $dep['name'];
1730
                                }
1731
                            }
1732
                        }
1733
                        $ret[] = $s;
1734
                    }
1735
                }
1736
            }
1737
            if (count($ret)) {
1738
                return $ret;
1739
            }
1740
        }
1741
        return false;
1742
    }
1743
 
1744
    /**
1745
     * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false
1746
     */
1747
    function getPackageType()
1748
    {
1749
        if (isset($this->_packageInfo['phprelease'])) {
1750
            return 'php';
1751
        }
1752
        if (isset($this->_packageInfo['extsrcrelease'])) {
1753
            return 'extsrc';
1754
        }
1755
        if (isset($this->_packageInfo['extbinrelease'])) {
1756
            return 'extbin';
1757
        }
1758
        if (isset($this->_packageInfo['zendextsrcrelease'])) {
1759
            return 'zendextsrc';
1760
        }
1761
        if (isset($this->_packageInfo['zendextbinrelease'])) {
1762
            return 'zendextbin';
1763
        }
1764
        if (isset($this->_packageInfo['bundle'])) {
1765
            return 'bundle';
1766
        }
1767
        return false;
1768
    }
1769
 
1770
    /**
1771
     * @return array|false
1772
     */
1773
    function getReleases()
1774
    {
1775
        $type = $this->getPackageType();
1776
        if ($type != 'bundle') {
1777
            $type .= 'release';
1778
        }
1779
        if ($this->getPackageType() && isset($this->_packageInfo[$type])) {
1780
            return $this->_packageInfo[$type];
1781
        }
1782
        return false;
1783
    }
1784
 
1785
    /**
1786
     * @return array
1787
     */
1788
    function getChangelog()
1789
    {
1790
        if (isset($this->_packageInfo['changelog'])) {
1791
            return $this->_packageInfo['changelog'];
1792
        }
1793
        return false;
1794
    }
1795
 
1796
    function hasDeps()
1797
    {
1798
        return isset($this->_packageInfo['dependencies']);
1799
    }
1800
 
1801
    function getPackagexmlVersion()
1802
    {
1803
        if (isset($this->_packageInfo['zendextsrcrelease'])) {
1804
            return '2.1';
1805
        }
1806
        if (isset($this->_packageInfo['zendextbinrelease'])) {
1807
            return '2.1';
1808
        }
1809
        return '2.0';
1810
    }
1811
 
1812
    /**
1813
     * @return array|false
1814
     */
1815
    function getSourcePackage()
1816
    {
1817
        if (isset($this->_packageInfo['extbinrelease']) ||
1818
              isset($this->_packageInfo['zendextbinrelease'])) {
1819
            return array('channel' => $this->_packageInfo['srcchannel'],
1820
                         'package' => $this->_packageInfo['srcpackage']);
1821
        }
1822
        return false;
1823
    }
1824
 
1825
    function getBundledPackages()
1826
    {
1827
        if (isset($this->_packageInfo['bundle'])) {
1828
            return $this->_packageInfo['contents']['bundledpackage'];
1829
        }
1830
        return false;
1831
    }
1832
 
1833
    function getLastModified()
1834
    {
1835
        if (isset($this->_packageInfo['_lastmodified'])) {
1836
            return $this->_packageInfo['_lastmodified'];
1837
        }
1838
        return false;
1839
    }
1840
 
1841
    /**
1842
     * Get the contents of a file listed within the package.xml
1843
     * @param string
1844
     * @return string
1845
     */
1846
    function getFileContents($file)
1847
    {
1848
        if ($this->_archiveFile == $this->_packageFile) { // unpacked
1849
            $dir = dirname($this->_packageFile);
1850
            $file = $dir . DIRECTORY_SEPARATOR . $file;
1851
            $file = str_replace(array('/', '\\'),
1852
                array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
1853
            if (file_exists($file) && is_readable($file)) {
1854
                return implode('', file($file));
1855
            }
1856
        } else { // tgz
1857
            $tar = &new Archive_Tar($this->_archiveFile);
1858
            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
1859
            if ($file != 'package.xml' && $file != 'package2.xml') {
1860
                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
1861
            }
1862
            $file = $tar->extractInString($file);
1863
            $tar->popErrorHandling();
1864
            if (PEAR::isError($file)) {
1865
                return PEAR::raiseError("Cannot locate file '$file' in archive");
1866
            }
1867
            return $file;
1868
        }
1869
    }
1870
 
1871
    function &getRW()
1872
    {
1873
        if (!class_exists('PEAR_PackageFile_v2_rw')) {
1874
            require_once 'PEAR/PackageFile/v2/rw.php';
1875
        }
1876
        $a = new PEAR_PackageFile_v2_rw;
1877
        foreach (get_object_vars($this) as $name => $unused) {
1878
            if (!isset($this->$name)) {
1879
                continue;
1880
            }
1881
            if ($name == '_config' || $name == '_logger'|| $name == '_registry' ||
1882
                  $name == '_stack') {
1883
                $a->$name = &$this->$name;
1884
            } else {
1885
                $a->$name = $this->$name;
1886
            }
1887
        }
1888
        return $a;
1889
    }
1890
 
1891
    function &getDefaultGenerator()
1892
    {
1893
        if (!class_exists('PEAR_PackageFile_Generator_v2')) {
1894
            require_once 'PEAR/PackageFile/Generator/v2.php';
1895
        }
1896
        $a = &new PEAR_PackageFile_Generator_v2($this);
1897
        return $a;
1898
    }
1899
 
1900
    function analyzeSourceCode($file, $string = false)
1901
    {
1902
        if (!isset($this->_v2Validator) ||
1903
              !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
1904
            if (!class_exists('PEAR_PackageFile_v2_Validator')) {
1905
                require_once 'PEAR/PackageFile/v2/Validator.php';
1906
            }
1907
            $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
1908
        }
1909
        return $this->_v2Validator->analyzeSourceCode($file, $string);
1910
    }
1911
 
1912
    function validate($state = PEAR_VALIDATE_NORMAL)
1913
    {
1914
        if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
1915
            return false;
1916
        }
1917
        if (!isset($this->_v2Validator) ||
1918
              !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
1919
            if (!class_exists('PEAR_PackageFile_v2_Validator')) {
1920
                require_once 'PEAR/PackageFile/v2/Validator.php';
1921
            }
1922
            $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
1923
        }
1924
        if (isset($this->_packageInfo['xsdversion'])) {
1925
            unset($this->_packageInfo['xsdversion']);
1926
        }
1927
        return $this->_v2Validator->validate($this, $state);
1928
    }
1929
 
1930
    function getTasksNs()
1931
    {
1932
        if (!isset($this->_tasksNs)) {
1933
            if (isset($this->_packageInfo['attribs'])) {
1934
                foreach ($this->_packageInfo['attribs'] as $name => $value) {
1935
                    if ($value == 'http://pear.php.net/dtd/tasks-1.0') {
1936
                        $this->_tasksNs = str_replace('xmlns:', '', $name);
1937
                        break;
1938
                    }
1939
                }
1940
            }
1941
        }
1942
        return $this->_tasksNs;
1943
    }
1944
 
1945
    /**
1946
     * Determine whether a task name is a valid task.  Custom tasks may be defined
1947
     * using subdirectories by putting a "-" in the name, as in <tasks:mycustom-task>
1948
     *
1949
     * Note that this method will auto-load the task class file and test for the existence
1950
     * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class
1951
     * PEAR_Task_mycustom_task
1952
     * @param string
1953
     * @return boolean
1954
     */
1955
    function getTask($task)
1956
    {
1957
        $this->getTasksNs();
1958
        // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace
1959
        $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task);
1960
        $taskfile = str_replace(' ', '/', ucwords($task));
1961
        $task = str_replace(array(' ', '/'), '_', ucwords($task));
1962
        if (class_exists("PEAR_Task_$task")) {
1963
            return "PEAR_Task_$task";
1964
        }
1965
        $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true);
1966
        if ($fp) {
1967
            fclose($fp);
1968
            require_once "PEAR/Task/$taskfile.php";
1969
            return "PEAR_Task_$task";
1970
        }
1971
        return false;
1972
    }
1973
 
1974
    /**
1975
     * Key-friendly array_splice
1976
     * @param tagname to splice a value in before
1977
     * @param mixed the value to splice in
1978
     * @param string the new tag name
1979
     */
1980
    function _ksplice($array, $key, $value, $newkey)
1981
    {
1982
        $offset = array_search($key, array_keys($array));
1983
        $after = array_slice($array, $offset);
1984
        $before = array_slice($array, 0, $offset);
1985
        $before[$newkey] = $value;
1986
        return array_merge($before, $after);
1987
    }
1988
 
1989
    /**
1990
     * @param array a list of possible keys, in the order they may occur
1991
     * @param mixed contents of the new package.xml tag
1992
     * @param string tag name
1993
     * @access private
1994
     */
1995
    function _insertBefore($array, $keys, $contents, $newkey)
1996
    {
1997
        foreach ($keys as $key) {
1998
            if (isset($array[$key])) {
1999
                return $array = $this->_ksplice($array, $key, $contents, $newkey);
2000
            }
2001
        }
2002
        $array[$newkey] = $contents;
2003
        return $array;
2004
    }
2005
 
2006
    /**
2007
     * @param subsection of {@link $_packageInfo}
2008
     * @param array|string tag contents
2009
     * @param array format:
2010
     * <pre>
2011
     * array(
2012
     *   tagname => array(list of tag names that follow this one),
2013
     *   childtagname => array(list of child tag names that follow this one),
2014
     * )
2015
     * </pre>
2016
     *
2017
     * This allows construction of nested tags
2018
     * @access private
2019
     */
2020
    function _mergeTag($manip, $contents, $order)
2021
    {
2022
        if (count($order)) {
2023
            foreach ($order as $tag => $curorder) {
2024
                if (!isset($manip[$tag])) {
2025
                    // ensure that the tag is set up
2026
                    $manip = $this->_insertBefore($manip, $curorder, array(), $tag);
2027
                }
2028
                if (count($order) > 1) {
2029
                    $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1));
2030
                    return $manip;
2031
                }
2032
            }
2033
        } else {
2034
            return $manip;
2035
        }
2036
        if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) {
2037
            $manip[$tag][] = $contents;
2038
        } else {
2039
            if (!count($manip[$tag])) {
2040
                $manip[$tag] = $contents;
2041
            } else {
2042
                $manip[$tag] = array($manip[$tag]);
2043
                $manip[$tag][] = $contents;
2044
            }
2045
        }
2046
        return $manip;
2047
    }
2048
}
2049
?>