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