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_v1, package.xml version 1.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: v1.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
/**
22
 * Error code if parsing is attempted with no xml extension
23
 */
24
define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
25
 
26
/**
27
 * Error code if creating the xml parser resource fails
28
 */
29
define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
30
 
31
/**
32
 * Error code used for all sax xml parsing errors
33
 */
34
define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
35
 
36
/**
37
 * Error code used when there is no name
38
 */
39
define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
40
 
41
/**
42
 * Error code when a package name is not valid
43
 */
44
define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
45
 
46
/**
47
 * Error code used when no summary is parsed
48
 */
49
define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
50
 
51
/**
52
 * Error code for summaries that are more than 1 line
53
 */
54
define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
55
 
56
/**
57
 * Error code used when no description is present
58
 */
59
define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
60
 
61
/**
62
 * Error code used when no license is present
63
 */
64
define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
65
 
66
/**
67
 * Error code used when a <version> version number is not present
68
 */
69
define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
70
 
71
/**
72
 * Error code used when a <version> version number is invalid
73
 */
74
define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
75
 
76
/**
77
 * Error code when release state is missing
78
 */
79
define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
80
 
81
/**
82
 * Error code when release state is invalid
83
 */
84
define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
85
 
86
/**
87
 * Error code when release state is missing
88
 */
89
define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
90
 
91
/**
92
 * Error code when release state is invalid
93
 */
94
define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
95
 
96
/**
97
 * Error code when no release notes are found
98
 */
99
define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
100
 
101
/**
102
 * Error code when no maintainers are found
103
 */
104
define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
105
 
106
/**
107
 * Error code when a maintainer has no handle
108
 */
109
define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
110
 
111
/**
112
 * Error code when a maintainer has no handle
113
 */
114
define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
115
 
116
/**
117
 * Error code when a maintainer has no name
118
 */
119
define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
120
 
121
/**
122
 * Error code when a maintainer has no email
123
 */
124
define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
125
 
126
/**
127
 * Error code when a maintainer has no handle
128
 */
129
define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
130
 
131
/**
132
 * Error code when a dependency is not a PHP dependency, but has no name
133
 */
134
define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
135
 
136
/**
137
 * Error code when a dependency has no type (pkg, php, etc.)
138
 */
139
define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
140
 
141
/**
142
 * Error code when a dependency has no relation (lt, ge, has, etc.)
143
 */
144
define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
145
 
146
/**
147
 * Error code when a dependency is not a 'has' relation, but has no version
148
 */
149
define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
150
 
151
/**
152
 * Error code when a dependency has an invalid relation
153
 */
154
define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
155
 
156
/**
157
 * Error code when a dependency has an invalid type
158
 */
159
define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
160
 
161
/**
162
 * Error code when a dependency has an invalid optional option
163
 */
164
define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
165
 
166
/**
167
 * Error code when a dependency is a pkg dependency, and has an invalid package name
168
 */
169
define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
170
 
171
/**
172
 * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
173
 */
174
define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
175
 
176
/**
177
 * Error code when rel="has" and version attribute is present.
178
 */
179
define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
180
 
181
/**
182
 * Error code when type="php" and dependency name is present
183
 */
184
define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
185
 
186
/**
187
 * Error code when a configure option has no name
188
 */
189
define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
190
 
191
/**
192
 * Error code when a configure option has no name
193
 */
194
define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
195
 
196
/**
197
 * Error code when a file in the filelist has an invalid role
198
 */
199
define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
200
 
201
/**
202
 * Error code when a file in the filelist has no role
203
 */
204
define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
205
 
206
/**
207
 * Error code when analyzing a php source file that has parse errors
208
 */
209
define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
210
 
211
/**
212
 * Error code when analyzing a php source file reveals a source element
213
 * without a package name prefix
214
 */
215
define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
216
 
217
/**
218
 * Error code when an unknown channel is specified
219
 */
220
define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
221
 
222
/**
223
 * Error code when no files are found in the filelist
224
 */
225
define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
226
 
227
/**
228
 * Error code when a file is not valid php according to _analyzeSourceCode()
229
 */
230
define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
231
 
232
/**
233
 * Error code when the channel validator returns an error or warning
234
 */
235
define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
236
 
237
/**
238
 * Error code when a php5 package is packaged in php4 (analysis doesn't work)
239
 */
240
define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
241
 
242
/**
243
 * Error code when a file is listed in package.xml but does not exist
244
 */
245
define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
246
 
247
/**
248
 * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
249
 */
250
define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
251
 
252
/**
253
 * Error code when a package.xml contains non-ISO-8859-1 characters
254
 */
255
define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49);
256
 
257
/**
258
 * Error code when a dependency is not a 'has' relation, but has no version
259
 */
260
define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
261
 
262
/**
263
 * Error code when a package has no lead developer
264
 */
265
define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
266
 
267
/**
268
 * Error code when a filename begins with "."
269
 */
270
define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52);
271
/**
272
 * package.xml encapsulator
273
 * @category   pear
274
 * @package    PEAR
275
 * @author     Greg Beaver <cellog@php.net>
276
 * @copyright  1997-2009 The Authors
277
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
278
 * @version    Release: 1.9.4
279
 * @link       http://pear.php.net/package/PEAR
280
 * @since      Class available since Release 1.4.0a1
281
 */
282
class PEAR_PackageFile_v1
283
{
284
    /**
285
     * @access private
286
     * @var PEAR_ErrorStack
287
     * @access private
288
     */
289
    var $_stack;
290
 
291
    /**
292
     * A registry object, used to access the package name validation regex for non-standard channels
293
     * @var PEAR_Registry
294
     * @access private
295
     */
296
    var $_registry;
297
 
298
    /**
299
     * An object that contains a log method that matches PEAR_Common::log's signature
300
     * @var object
301
     * @access private
302
     */
303
    var $_logger;
304
 
305
    /**
306
     * Parsed package information
307
     * @var array
308
     * @access private
309
     */
310
    var $_packageInfo;
311
 
312
    /**
313
     * path to package.xml
314
     * @var string
315
     * @access private
316
     */
317
    var $_packageFile;
318
 
319
    /**
320
     * path to package .tgz or false if this is a local/extracted package.xml
321
     * @var string
322
     * @access private
323
     */
324
    var $_archiveFile;
325
 
326
    /**
327
     * @var int
328
     * @access private
329
     */
330
    var $_isValid = 0;
331
 
332
    /**
333
     * Determines whether this packagefile was initialized only with partial package info
334
     *
335
     * If this package file was constructed via parsing REST, it will only contain
336
     *
337
     * - package name
338
     * - channel name
339
     * - dependencies
340
     * @var boolean
341
     * @access private
342
     */
343
    var $_incomplete = true;
344
 
345
    /**
346
     * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
347
     * @param string Name of Error Stack class to use.
348
     */
349
    function PEAR_PackageFile_v1()
350
    {
351
        $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1');
352
        $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
353
        $this->_isValid = 0;
354
    }
355
 
356
    function installBinary($installer)
357
    {
358
        return false;
359
    }
360
 
361
    function isExtension($name)
362
    {
363
        return false;
364
    }
365
 
366
    function setConfig(&$config)
367
    {
368
        $this->_config = &$config;
369
        $this->_registry = &$config->getRegistry();
370
    }
371
 
372
    function setRequestedGroup()
373
    {
374
        // placeholder
375
    }
376
 
377
    /**
378
     * For saving in the registry.
379
     *
380
     * Set the last version that was installed
381
     * @param string
382
     */
383
    function setLastInstalledVersion($version)
384
    {
385
        $this->_packageInfo['_lastversion'] = $version;
386
    }
387
 
388
    /**
389
     * @return string|false
390
     */
391
    function getLastInstalledVersion()
392
    {
393
        if (isset($this->_packageInfo['_lastversion'])) {
394
            return $this->_packageInfo['_lastversion'];
395
        }
396
        return false;
397
    }
398
 
399
    function getInstalledBinary()
400
    {
401
        return false;
402
    }
403
 
404
    function listPostinstallScripts()
405
    {
406
        return false;
407
    }
408
 
409
    function initPostinstallScripts()
410
    {
411
        return false;
412
    }
413
 
414
    function setLogger(&$logger)
415
    {
416
        if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
417
            return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
418
        }
419
        $this->_logger = &$logger;
420
    }
421
 
422
    function setPackagefile($file, $archive = false)
423
    {
424
        $this->_packageFile = $file;
425
        $this->_archiveFile = $archive ? $archive : $file;
426
    }
427
 
428
    function getPackageFile()
429
    {
430
        return isset($this->_packageFile) ? $this->_packageFile : false;
431
    }
432
 
433
    function getPackageType()
434
    {
435
        return 'php';
436
    }
437
 
438
    function getArchiveFile()
439
    {
440
        return $this->_archiveFile;
441
    }
442
 
443
    function packageInfo($field)
444
    {
445
        if (!is_string($field) || empty($field) ||
446
            !isset($this->_packageInfo[$field])) {
447
            return false;
448
        }
449
        return $this->_packageInfo[$field];
450
    }
451
 
452
    function setDirtree($path)
453
    {
454
        if (!isset($this->_packageInfo['dirtree'])) {
455
            $this->_packageInfo['dirtree'] = array();
456
        }
457
        $this->_packageInfo['dirtree'][$path] = true;
458
    }
459
 
460
    function getDirtree()
461
    {
462
        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
463
            return $this->_packageInfo['dirtree'];
464
        }
465
        return false;
466
    }
467
 
468
    function resetDirtree()
469
    {
470
        unset($this->_packageInfo['dirtree']);
471
    }
472
 
473
    function fromArray($pinfo)
474
    {
475
        $this->_incomplete = false;
476
        $this->_packageInfo = $pinfo;
477
    }
478
 
479
    function isIncomplete()
480
    {
481
        return $this->_incomplete;
482
    }
483
 
484
    function getChannel()
485
    {
486
        return 'pear.php.net';
487
    }
488
 
489
    function getUri()
490
    {
491
        return false;
492
    }
493
 
494
    function getTime()
495
    {
496
        return false;
497
    }
498
 
499
    function getExtends()
500
    {
501
        if (isset($this->_packageInfo['extends'])) {
502
            return $this->_packageInfo['extends'];
503
        }
504
        return false;
505
    }
506
 
507
    /**
508
     * @return array
509
     */
510
    function toArray()
511
    {
512
        if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
513
            return false;
514
        }
515
        return $this->getArray();
516
    }
517
 
518
    function getArray()
519
    {
520
        return $this->_packageInfo;
521
    }
522
 
523
    function getName()
524
    {
525
        return $this->getPackage();
526
    }
527
 
528
    function getPackage()
529
    {
530
        if (isset($this->_packageInfo['package'])) {
531
            return $this->_packageInfo['package'];
532
        }
533
        return false;
534
    }
535
 
536
    /**
537
     * WARNING - don't use this unless you know what you are doing
538
     */
539
    function setRawPackage($package)
540
    {
541
        $this->_packageInfo['package'] = $package;
542
    }
543
 
544
    function setPackage($package)
545
    {
546
        $this->_packageInfo['package'] = $package;
547
        $this->_isValid = false;
548
    }
549
 
550
    function getVersion()
551
    {
552
        if (isset($this->_packageInfo['version'])) {
553
            return $this->_packageInfo['version'];
554
        }
555
        return false;
556
    }
557
 
558
    function setVersion($version)
559
    {
560
        $this->_packageInfo['version'] = $version;
561
        $this->_isValid = false;
562
    }
563
 
564
    function clearMaintainers()
565
    {
566
        unset($this->_packageInfo['maintainers']);
567
    }
568
 
569
    function getMaintainers()
570
    {
571
        if (isset($this->_packageInfo['maintainers'])) {
572
            return $this->_packageInfo['maintainers'];
573
        }
574
        return false;
575
    }
576
 
577
    /**
578
     * Adds a new maintainer - no checking of duplicates is performed, use
579
     * updatemaintainer for that purpose.
580
     */
581
    function addMaintainer($role, $handle, $name, $email)
582
    {
583
        $this->_packageInfo['maintainers'][] =
584
            array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
585
        $this->_isValid = false;
586
    }
587
 
588
    function updateMaintainer($role, $handle, $name, $email)
589
    {
590
        $found = false;
591
        if (!isset($this->_packageInfo['maintainers']) ||
592
              !is_array($this->_packageInfo['maintainers'])) {
593
            return $this->addMaintainer($role, $handle, $name, $email);
594
        }
595
        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
596
            if ($maintainer['handle'] == $handle) {
597
                $found = $i;
598
                break;
599
            }
600
        }
601
        if ($found !== false) {
602
            unset($this->_packageInfo['maintainers'][$found]);
603
            $this->_packageInfo['maintainers'] =
604
                array_values($this->_packageInfo['maintainers']);
605
        }
606
        $this->addMaintainer($role, $handle, $name, $email);
607
    }
608
 
609
    function deleteMaintainer($handle)
610
    {
611
        $found = false;
612
        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
613
            if ($maintainer['handle'] == $handle) {
614
                $found = $i;
615
                break;
616
            }
617
        }
618
        if ($found !== false) {
619
            unset($this->_packageInfo['maintainers'][$found]);
620
            $this->_packageInfo['maintainers'] =
621
                array_values($this->_packageInfo['maintainers']);
622
            return true;
623
        }
624
        return false;
625
    }
626
 
627
    function getState()
628
    {
629
        if (isset($this->_packageInfo['release_state'])) {
630
            return $this->_packageInfo['release_state'];
631
        }
632
        return false;
633
    }
634
 
635
    function setRawState($state)
636
    {
637
        $this->_packageInfo['release_state'] = $state;
638
    }
639
 
640
    function setState($state)
641
    {
642
        $this->_packageInfo['release_state'] = $state;
643
        $this->_isValid = false;
644
    }
645
 
646
    function getDate()
647
    {
648
        if (isset($this->_packageInfo['release_date'])) {
649
            return $this->_packageInfo['release_date'];
650
        }
651
        return false;
652
    }
653
 
654
    function setDate($date)
655
    {
656
        $this->_packageInfo['release_date'] = $date;
657
        $this->_isValid = false;
658
    }
659
 
660
    function getLicense()
661
    {
662
        if (isset($this->_packageInfo['release_license'])) {
663
            return $this->_packageInfo['release_license'];
664
        }
665
        return false;
666
    }
667
 
668
    function setLicense($date)
669
    {
670
        $this->_packageInfo['release_license'] = $date;
671
        $this->_isValid = false;
672
    }
673
 
674
    function getSummary()
675
    {
676
        if (isset($this->_packageInfo['summary'])) {
677
            return $this->_packageInfo['summary'];
678
        }
679
        return false;
680
    }
681
 
682
    function setSummary($summary)
683
    {
684
        $this->_packageInfo['summary'] = $summary;
685
        $this->_isValid = false;
686
    }
687
 
688
    function getDescription()
689
    {
690
        if (isset($this->_packageInfo['description'])) {
691
            return $this->_packageInfo['description'];
692
        }
693
        return false;
694
    }
695
 
696
    function setDescription($desc)
697
    {
698
        $this->_packageInfo['description'] = $desc;
699
        $this->_isValid = false;
700
    }
701
 
702
    function getNotes()
703
    {
704
        if (isset($this->_packageInfo['release_notes'])) {
705
            return $this->_packageInfo['release_notes'];
706
        }
707
        return false;
708
    }
709
 
710
    function setNotes($notes)
711
    {
712
        $this->_packageInfo['release_notes'] = $notes;
713
        $this->_isValid = false;
714
    }
715
 
716
    function getDeps()
717
    {
718
        if (isset($this->_packageInfo['release_deps'])) {
719
            return $this->_packageInfo['release_deps'];
720
        }
721
        return false;
722
    }
723
 
724
    /**
725
     * Reset dependencies prior to adding new ones
726
     */
727
    function clearDeps()
728
    {
729
        unset($this->_packageInfo['release_deps']);
730
    }
731
 
732
    function addPhpDep($version, $rel)
733
    {
734
        $this->_isValid = false;
735
        $this->_packageInfo['release_deps'][] =
736
            array('type' => 'php',
737
                  'rel' => $rel,
738
                  'version' => $version);
739
    }
740
 
741
    function addPackageDep($name, $version, $rel, $optional = 'no')
742
    {
743
        $this->_isValid = false;
744
        $dep =
745
            array('type' => 'pkg',
746
                  'name' => $name,
747
                  'rel' => $rel,
748
                  'optional' => $optional);
749
        if ($rel != 'has' && $rel != 'not') {
750
            $dep['version'] = $version;
751
        }
752
        $this->_packageInfo['release_deps'][] = $dep;
753
    }
754
 
755
    function addExtensionDep($name, $version, $rel, $optional = 'no')
756
    {
757
        $this->_isValid = false;
758
        $this->_packageInfo['release_deps'][] =
759
            array('type' => 'ext',
760
                  'name' => $name,
761
                  'rel' => $rel,
762
                  'version' => $version,
763
                  'optional' => $optional);
764
    }
765
 
766
    /**
767
     * WARNING - do not use this function directly unless you know what you're doing
768
     */
769
    function setDeps($deps)
770
    {
771
        $this->_packageInfo['release_deps'] = $deps;
772
    }
773
 
774
    function hasDeps()
775
    {
776
        return isset($this->_packageInfo['release_deps']) &&
777
            count($this->_packageInfo['release_deps']);
778
    }
779
 
780
    function getDependencyGroup($group)
781
    {
782
        return false;
783
    }
784
 
785
    function isCompatible($pf)
786
    {
787
        return false;
788
    }
789
 
790
    function isSubpackageOf($p)
791
    {
792
        return $p->isSubpackage($this);
793
    }
794
 
795
    function isSubpackage($p)
796
    {
797
        return false;
798
    }
799
 
800
    function dependsOn($package, $channel)
801
    {
802
        if (strtolower($channel) != 'pear.php.net') {
803
            return false;
804
        }
805
        if (!($deps = $this->getDeps())) {
806
            return false;
807
        }
808
        foreach ($deps as $dep) {
809
            if ($dep['type'] != 'pkg') {
810
                continue;
811
            }
812
            if (strtolower($dep['name']) == strtolower($package)) {
813
                return true;
814
            }
815
        }
816
        return false;
817
    }
818
 
819
    function getConfigureOptions()
820
    {
821
        if (isset($this->_packageInfo['configure_options'])) {
822
            return $this->_packageInfo['configure_options'];
823
        }
824
        return false;
825
    }
826
 
827
    function hasConfigureOptions()
828
    {
829
        return isset($this->_packageInfo['configure_options']) &&
830
            count($this->_packageInfo['configure_options']);
831
    }
832
 
833
    function addConfigureOption($name, $prompt, $default = false)
834
    {
835
        $o = array('name' => $name, 'prompt' => $prompt);
836
        if ($default !== false) {
837
            $o['default'] = $default;
838
        }
839
        if (!isset($this->_packageInfo['configure_options'])) {
840
            $this->_packageInfo['configure_options'] = array();
841
        }
842
        $this->_packageInfo['configure_options'][] = $o;
843
    }
844
 
845
    function clearConfigureOptions()
846
    {
847
        unset($this->_packageInfo['configure_options']);
848
    }
849
 
850
    function getProvides()
851
    {
852
        if (isset($this->_packageInfo['provides'])) {
853
            return $this->_packageInfo['provides'];
854
        }
855
        return false;
856
    }
857
 
858
    function getProvidesExtension()
859
    {
860
        return false;
861
    }
862
 
863
    function addFile($dir, $file, $attrs)
864
    {
865
        $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
866
        if ($dir == '/' || $dir == '') {
867
            $dir = '';
868
        } else {
869
            $dir .= '/';
870
        }
871
        $file = $dir . $file;
872
        $file = preg_replace('![\\/]+!', '/', $file);
873
        $this->_packageInfo['filelist'][$file] = $attrs;
874
    }
875
 
876
    function getInstallationFilelist()
877
    {
878
        return $this->getFilelist();
879
    }
880
 
881
    function getFilelist()
882
    {
883
        if (isset($this->_packageInfo['filelist'])) {
884
            return $this->_packageInfo['filelist'];
885
        }
886
        return false;
887
    }
888
 
889
    function setFileAttribute($file, $attr, $value)
890
    {
891
        $this->_packageInfo['filelist'][$file][$attr] = $value;
892
    }
893
 
894
    function resetFilelist()
895
    {
896
        $this->_packageInfo['filelist'] = array();
897
    }
898
 
899
    function setInstalledAs($file, $path)
900
    {
901
        if ($path) {
902
            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
903
        }
904
        unset($this->_packageInfo['filelist'][$file]['installed_as']);
905
    }
906
 
907
    function installedFile($file, $atts)
908
    {
909
        if (isset($this->_packageInfo['filelist'][$file])) {
910
            $this->_packageInfo['filelist'][$file] =
911
                array_merge($this->_packageInfo['filelist'][$file], $atts);
912
        } else {
913
            $this->_packageInfo['filelist'][$file] = $atts;
914
        }
915
    }
916
 
917
    function getChangelog()
918
    {
919
        if (isset($this->_packageInfo['changelog'])) {
920
            return $this->_packageInfo['changelog'];
921
        }
922
        return false;
923
    }
924
 
925
    function getPackagexmlVersion()
926
    {
927
        return '1.0';
928
    }
929
 
930
    /**
931
     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
932
     * @param boolean determines whether to purge the error stack after retrieving
933
     * @return array
934
     */
935
    function getValidationWarnings($purge = true)
936
    {
937
        return $this->_stack->getErrors($purge);
938
    }
939
 
940
    // }}}
941
    /**
942
     * Validation error.  Also marks the object contents as invalid
943
     * @param error code
944
     * @param array error information
945
     * @access private
946
     */
947
    function _validateError($code, $params = array())
948
    {
949
        $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
950
        $this->_isValid = false;
951
    }
952
 
953
    /**
954
     * Validation warning.  Does not mark the object contents invalid.
955
     * @param error code
956
     * @param array error information
957
     * @access private
958
     */
959
    function _validateWarning($code, $params = array())
960
    {
961
        $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
962
    }
963
 
964
    /**
965
     * @param integer error code
966
     * @access protected
967
     */
968
    function _getErrorMessage()
969
    {
970
        return array(
971
                PEAR_PACKAGEFILE_ERROR_NO_NAME =>
972
                    'Missing Package Name',
973
                PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
974
                    'No summary found',
975
                PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
976
                    'Summary should be on one line',
977
                PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
978
                    'Missing description',
979
                PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
980
                    'Missing license',
981
                PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
982
                    'No release version found',
983
                PEAR_PACKAGEFILE_ERROR_NO_STATE =>
984
                    'No release state found',
985
                PEAR_PACKAGEFILE_ERROR_NO_DATE =>
986
                    'No release date found',
987
                PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
988
                    'No release notes found',
989
                PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
990
                    'Package must have at least one lead maintainer',
991
                PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
992
                    'No maintainers found, at least one must be defined',
993
                PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
994
                    'Maintainer %index% has no handle (user ID at channel server)',
995
                PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
996
                    'Maintainer %index% has no role',
997
                PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
998
                    'Maintainer %index% has no name',
999
                PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
1000
                    'Maintainer %index% has no email',
1001
                PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
1002
                    'Dependency %index% is not a php dependency, and has no name',
1003
                PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
1004
                    'Dependency %index% has no relation (rel)',
1005
                PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
1006
                    'Dependency %index% has no type',
1007
                PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
1008
                    'PHP Dependency %index% has a name attribute of "%name%" which will be' .
1009
                        ' ignored!',
1010
                PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
1011
                    'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
1012
                        'and has no version',
1013
                PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
1014
                    'Dependency %index% is a type="php" dependency, ' .
1015
                        'and has no version',
1016
                PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
1017
                    'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
1018
                PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
1019
                    'Dependency %index% has invalid optional value "%opt%", should be yes or no',
1020
                PEAR_PACKAGEFILE_PHP_NO_NOT =>
1021
                    'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
1022
                        ' to exclude specific versions',
1023
                PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
1024
                    'Configure Option %index% has no name',
1025
                PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
1026
                    'Configure Option %index% has no prompt',
1027
                PEAR_PACKAGEFILE_ERROR_NO_FILES =>
1028
                    'No files in <filelist> section of package.xml',
1029
                PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
1030
                    'File "%file%" has no role, expecting one of "%roles%"',
1031
                PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
1032
                    'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
1033
                PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
1034
                    'File "%file%" cannot start with ".", cannot package or install',
1035
                PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
1036
                    'Parser error: invalid PHP found in file "%file%"',
1037
                PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
1038
                    'in %file%: %type% "%name%" not prefixed with package name "%package%"',
1039
                PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
1040
                    'Parser error: invalid PHP file "%file%"',
1041
                PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
1042
                    'Channel validator error: field "%field%" - %reason%',
1043
                PEAR_PACKAGEFILE_ERROR_PHP5 =>
1044
                    'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
1045
                PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
1046
                    'File "%file%" in package.xml does not exist',
1047
                PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
1048
                    'Package.xml contains non-ISO-8859-1 characters, and may not validate',
1049
            );
1050
    }
1051
 
1052
    /**
1053
     * Validate XML package definition file.
1054
     *
1055
     * @access public
1056
     * @return boolean
1057
     */
1058
    function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
1059
    {
1060
        if (($this->_isValid & $state) == $state) {
1061
            return true;
1062
        }
1063
        $this->_isValid = true;
1064
        $info = $this->_packageInfo;
1065
        if (empty($info['package'])) {
1066
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
1067
            $this->_packageName = $pn = 'unknown';
1068
        } else {
1069
            $this->_packageName = $pn = $info['package'];
1070
        }
1071
 
1072
        if (empty($info['summary'])) {
1073
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
1074
        } elseif (strpos(trim($info['summary']), "\n") !== false) {
1075
            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
1076
                array('summary' => $info['summary']));
1077
        }
1078
        if (empty($info['description'])) {
1079
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
1080
        }
1081
        if (empty($info['release_license'])) {
1082
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
1083
        }
1084
        if (empty($info['version'])) {
1085
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
1086
        }
1087
        if (empty($info['release_state'])) {
1088
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
1089
        }
1090
        if (empty($info['release_date'])) {
1091
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
1092
        }
1093
        if (empty($info['release_notes'])) {
1094
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
1095
        }
1096
        if (empty($info['maintainers'])) {
1097
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
1098
        } else {
1099
            $haslead = false;
1100
            $i = 1;
1101
            foreach ($info['maintainers'] as $m) {
1102
                if (empty($m['handle'])) {
1103
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
1104
                        array('index' => $i));
1105
                }
1106
                if (empty($m['role'])) {
1107
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
1108
                        array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
1109
                } elseif ($m['role'] == 'lead') {
1110
                    $haslead = true;
1111
                }
1112
                if (empty($m['name'])) {
1113
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
1114
                        array('index' => $i));
1115
                }
1116
                if (empty($m['email'])) {
1117
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
1118
                        array('index' => $i));
1119
                }
1120
                $i++;
1121
            }
1122
            if (!$haslead) {
1123
                $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
1124
            }
1125
        }
1126
        if (!empty($info['release_deps'])) {
1127
            $i = 1;
1128
            foreach ($info['release_deps'] as $d) {
1129
                if (!isset($d['type']) || empty($d['type'])) {
1130
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
1131
                        array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
1132
                    continue;
1133
                }
1134
                if (!isset($d['rel']) || empty($d['rel'])) {
1135
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
1136
                        array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
1137
                    continue;
1138
                }
1139
                if (!empty($d['optional'])) {
1140
                    if (!in_array($d['optional'], array('yes', 'no'))) {
1141
                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
1142
                            array('index' => $i, 'opt' => $d['optional']));
1143
                    }
1144
                }
1145
                if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
1146
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
1147
                        array('index' => $i));
1148
                } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
1149
                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
1150
                        array('index' => $i, 'rel' => $d['rel']));
1151
                }
1152
                if ($d['type'] == 'php' && !empty($d['name'])) {
1153
                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
1154
                        array('index' => $i, 'name' => $d['name']));
1155
                } elseif ($d['type'] != 'php' && empty($d['name'])) {
1156
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
1157
                        array('index' => $i));
1158
                }
1159
                if ($d['type'] == 'php' && empty($d['version'])) {
1160
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
1161
                        array('index' => $i));
1162
                }
1163
                if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
1164
                    $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
1165
                        array('index' => $i));
1166
                }
1167
                $i++;
1168
            }
1169
        }
1170
        if (!empty($info['configure_options'])) {
1171
            $i = 1;
1172
            foreach ($info['configure_options'] as $c) {
1173
                if (empty($c['name'])) {
1174
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
1175
                        array('index' => $i));
1176
                }
1177
                if (empty($c['prompt'])) {
1178
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
1179
                        array('index' => $i));
1180
                }
1181
                $i++;
1182
            }
1183
        }
1184
        if (empty($info['filelist'])) {
1185
            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
1186
            $errors[] = 'no files';
1187
        } else {
1188
            foreach ($info['filelist'] as $file => $fa) {
1189
                if (empty($fa['role'])) {
1190
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
1191
                        array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
1192
                    continue;
1193
                } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
1194
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
1195
                        array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
1196
                }
1197
                if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) {
1198
                    // file contains .. parent directory or . cur directory references
1199
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
1200
                        array('file' => $file));
1201
                }
1202
                if (isset($fa['install-as']) &&
1203
                      preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
1204
                                 str_replace('\\', '/', $fa['install-as']))) {
1205
                    // install-as contains .. parent directory or . cur directory references
1206
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
1207
                        array('file' => $file . ' [installed as ' . $fa['install-as'] . ']'));
1208
                }
1209
                if (isset($fa['baseinstalldir']) &&
1210
                      preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
1211
                                 str_replace('\\', '/', $fa['baseinstalldir']))) {
1212
                    // install-as contains .. parent directory or . cur directory references
1213
                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
1214
                        array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']'));
1215
                }
1216
            }
1217
        }
1218
        if (isset($this->_registry) && $this->_isValid) {
1219
            $chan = $this->_registry->getChannel('pear.php.net');
1220
            if (PEAR::isError($chan)) {
1221
                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage());
1222
                return $this->_isValid = 0;
1223
            }
1224
            $validator = $chan->getValidationObject();
1225
            $validator->setPackageFile($this);
1226
            $validator->validate($state);
1227
            $failures = $validator->getFailures();
1228
            foreach ($failures['errors'] as $error) {
1229
                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
1230
            }
1231
            foreach ($failures['warnings'] as $warning) {
1232
                $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
1233
            }
1234
        }
1235
        if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
1236
            if ($this->_analyzePhpFiles()) {
1237
                $this->_isValid = true;
1238
            }
1239
        }
1240
        if ($this->_isValid) {
1241
            return $this->_isValid = $state;
1242
        }
1243
        return $this->_isValid = 0;
1244
    }
1245
 
1246
    function _analyzePhpFiles()
1247
    {
1248
        if (!$this->_isValid) {
1249
            return false;
1250
        }
1251
        if (!isset($this->_packageFile)) {
1252
            return false;
1253
        }
1254
        $dir_prefix = dirname($this->_packageFile);
1255
        $common = new PEAR_Common;
1256
        $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
1257
            array($common, 'log');
1258
        $info = $this->getFilelist();
1259
        foreach ($info as $file => $fa) {
1260
            if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
1261
                $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
1262
                    array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
1263
                continue;
1264
            }
1265
            if ($fa['role'] == 'php' && $dir_prefix) {
1266
                call_user_func_array($log, array(1, "Analyzing $file"));
1267
                $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
1268
                if ($srcinfo) {
1269
                    $this->_buildProvidesArray($srcinfo);
1270
                }
1271
            }
1272
        }
1273
        $this->_packageName = $pn = $this->getPackage();
1274
        $pnl = strlen($pn);
1275
        if (isset($this->_packageInfo['provides'])) {
1276
            foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
1277
                if (isset($what['explicit'])) {
1278
                    // skip conformance checks if the provides entry is
1279
                    // specified in the package.xml file
1280
                    continue;
1281
                }
1282
                extract($what);
1283
                if ($type == 'class') {
1284
                    if (!strncasecmp($name, $pn, $pnl)) {
1285
                        continue;
1286
                    }
1287
                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
1288
                        array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
1289
                } elseif ($type == 'function') {
1290
                    if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
1291
                        continue;
1292
                    }
1293
                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
1294
                        array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
1295
                }
1296
            }
1297
        }
1298
        return $this->_isValid;
1299
    }
1300
 
1301
    /**
1302
     * Get the default xml generator object
1303
     *
1304
     * @return PEAR_PackageFile_Generator_v1
1305
     */
1306
    function &getDefaultGenerator()
1307
    {
1308
        if (!class_exists('PEAR_PackageFile_Generator_v1')) {
1309
            require_once 'PEAR/PackageFile/Generator/v1.php';
1310
        }
1311
        $a = &new PEAR_PackageFile_Generator_v1($this);
1312
        return $a;
1313
    }
1314
 
1315
    /**
1316
     * Get the contents of a file listed within the package.xml
1317
     * @param string
1318
     * @return string
1319
     */
1320
    function getFileContents($file)
1321
    {
1322
        if ($this->_archiveFile == $this->_packageFile) { // unpacked
1323
            $dir = dirname($this->_packageFile);
1324
            $file = $dir . DIRECTORY_SEPARATOR . $file;
1325
            $file = str_replace(array('/', '\\'),
1326
                array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
1327
            if (file_exists($file) && is_readable($file)) {
1328
                return implode('', file($file));
1329
            }
1330
        } else { // tgz
1331
            if (!class_exists('Archive_Tar')) {
1332
                require_once 'Archive/Tar.php';
1333
            }
1334
            $tar = &new Archive_Tar($this->_archiveFile);
1335
            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
1336
            if ($file != 'package.xml' && $file != 'package2.xml') {
1337
                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
1338
            }
1339
            $file = $tar->extractInString($file);
1340
            $tar->popErrorHandling();
1341
            if (PEAR::isError($file)) {
1342
                return PEAR::raiseError("Cannot locate file '$file' in archive");
1343
            }
1344
            return $file;
1345
        }
1346
    }
1347
 
1348
    // {{{ analyzeSourceCode()
1349
    /**
1350
     * Analyze the source code of the given PHP file
1351
     *
1352
     * @param  string Filename of the PHP file
1353
     * @return mixed
1354
     * @access private
1355
     */
1356
    function _analyzeSourceCode($file)
1357
    {
1358
        if (!function_exists("token_get_all")) {
1359
            return false;
1360
        }
1361
        if (!defined('T_DOC_COMMENT')) {
1362
            define('T_DOC_COMMENT', T_COMMENT);
1363
        }
1364
        if (!defined('T_INTERFACE')) {
1365
            define('T_INTERFACE', -1);
1366
        }
1367
        if (!defined('T_IMPLEMENTS')) {
1368
            define('T_IMPLEMENTS', -1);
1369
        }
1370
        if (!$fp = @fopen($file, "r")) {
1371
            return false;
1372
        }
1373
        fclose($fp);
1374
        $contents = file_get_contents($file);
1375
        $tokens = token_get_all($contents);
1376
/*
1377
        for ($i = 0; $i < sizeof($tokens); $i++) {
1378
            @list($token, $data) = $tokens[$i];
1379
            if (is_string($token)) {
1380
                var_dump($token);
1381
            } else {
1382
                print token_name($token) . ' ';
1383
                var_dump(rtrim($data));
1384
            }
1385
        }
1386
*/
1387
        $look_for = 0;
1388
        $paren_level = 0;
1389
        $bracket_level = 0;
1390
        $brace_level = 0;
1391
        $lastphpdoc = '';
1392
        $current_class = '';
1393
        $current_interface = '';
1394
        $current_class_level = -1;
1395
        $current_function = '';
1396
        $current_function_level = -1;
1397
        $declared_classes = array();
1398
        $declared_interfaces = array();
1399
        $declared_functions = array();
1400
        $declared_methods = array();
1401
        $used_classes = array();
1402
        $used_functions = array();
1403
        $extends = array();
1404
        $implements = array();
1405
        $nodeps = array();
1406
        $inquote = false;
1407
        $interface = false;
1408
        for ($i = 0; $i < sizeof($tokens); $i++) {
1409
            if (is_array($tokens[$i])) {
1410
                list($token, $data) = $tokens[$i];
1411
            } else {
1412
                $token = $tokens[$i];
1413
                $data = '';
1414
            }
1415
            if ($inquote) {
1416
                if ($token != '"' && $token != T_END_HEREDOC) {
1417
                    continue;
1418
                } else {
1419
                    $inquote = false;
1420
                    continue;
1421
                }
1422
            }
1423
            switch ($token) {
1424
                case T_WHITESPACE :
1425
                    continue;
1426
                case ';':
1427
                    if ($interface) {
1428
                        $current_function = '';
1429
                        $current_function_level = -1;
1430
                    }
1431
                    break;
1432
                case '"':
1433
                case T_START_HEREDOC:
1434
                    $inquote = true;
1435
                    break;
1436
                case T_CURLY_OPEN:
1437
                case T_DOLLAR_OPEN_CURLY_BRACES:
1438
                case '{': $brace_level++; continue 2;
1439
                case '}':
1440
                    $brace_level--;
1441
                    if ($current_class_level == $brace_level) {
1442
                        $current_class = '';
1443
                        $current_class_level = -1;
1444
                    }
1445
                    if ($current_function_level == $brace_level) {
1446
                        $current_function = '';
1447
                        $current_function_level = -1;
1448
                    }
1449
                    continue 2;
1450
                case '[': $bracket_level++; continue 2;
1451
                case ']': $bracket_level--; continue 2;
1452
                case '(': $paren_level++;   continue 2;
1453
                case ')': $paren_level--;   continue 2;
1454
                case T_INTERFACE:
1455
                    $interface = true;
1456
                case T_CLASS:
1457
                    if (($current_class_level != -1) || ($current_function_level != -1)) {
1458
                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
1459
                            array('file' => $file));
1460
                        return false;
1461
                    }
1462
                case T_FUNCTION:
1463
                case T_NEW:
1464
                case T_EXTENDS:
1465
                case T_IMPLEMENTS:
1466
                    $look_for = $token;
1467
                    continue 2;
1468
                case T_STRING:
1469
                    if (version_compare(zend_version(), '2.0', '<')) {
1470
                        if (in_array(strtolower($data),
1471
                            array('public', 'private', 'protected', 'abstract',
1472
                                  'interface', 'implements', 'throw')
1473
                                 )) {
1474
                            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5,
1475
                                array($file));
1476
                        }
1477
                    }
1478
                    if ($look_for == T_CLASS) {
1479
                        $current_class = $data;
1480
                        $current_class_level = $brace_level;
1481
                        $declared_classes[] = $current_class;
1482
                    } elseif ($look_for == T_INTERFACE) {
1483
                        $current_interface = $data;
1484
                        $current_class_level = $brace_level;
1485
                        $declared_interfaces[] = $current_interface;
1486
                    } elseif ($look_for == T_IMPLEMENTS) {
1487
                        $implements[$current_class] = $data;
1488
                    } elseif ($look_for == T_EXTENDS) {
1489
                        $extends[$current_class] = $data;
1490
                    } elseif ($look_for == T_FUNCTION) {
1491
                        if ($current_class) {
1492
                            $current_function = "$current_class::$data";
1493
                            $declared_methods[$current_class][] = $data;
1494
                        } elseif ($current_interface) {
1495
                            $current_function = "$current_interface::$data";
1496
                            $declared_methods[$current_interface][] = $data;
1497
                        } else {
1498
                            $current_function = $data;
1499
                            $declared_functions[] = $current_function;
1500
                        }
1501
                        $current_function_level = $brace_level;
1502
                        $m = array();
1503
                    } elseif ($look_for == T_NEW) {
1504
                        $used_classes[$data] = true;
1505
                    }
1506
                    $look_for = 0;
1507
                    continue 2;
1508
                case T_VARIABLE:
1509
                    $look_for = 0;
1510
                    continue 2;
1511
                case T_DOC_COMMENT:
1512
                case T_COMMENT:
1513
                    if (preg_match('!^/\*\*\s!', $data)) {
1514
                        $lastphpdoc = $data;
1515
                        if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
1516
                            $nodeps = array_merge($nodeps, $m[1]);
1517
                        }
1518
                    }
1519
                    continue 2;
1520
                case T_DOUBLE_COLON:
1521
                    if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
1522
                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
1523
                            array('file' => $file));
1524
                        return false;
1525
                    }
1526
                    $class = $tokens[$i - 1][1];
1527
                    if (strtolower($class) != 'parent') {
1528
                        $used_classes[$class] = true;
1529
                    }
1530
                    continue 2;
1531
            }
1532
        }
1533
        return array(
1534
            "source_file" => $file,
1535
            "declared_classes" => $declared_classes,
1536
            "declared_interfaces" => $declared_interfaces,
1537
            "declared_methods" => $declared_methods,
1538
            "declared_functions" => $declared_functions,
1539
            "used_classes" => array_diff(array_keys($used_classes), $nodeps),
1540
            "inheritance" => $extends,
1541
            "implements" => $implements,
1542
            );
1543
    }
1544
 
1545
    /**
1546
     * Build a "provides" array from data returned by
1547
     * analyzeSourceCode().  The format of the built array is like
1548
     * this:
1549
     *
1550
     *  array(
1551
     *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
1552
     *    ...
1553
     *  )
1554
     *
1555
     *
1556
     * @param array $srcinfo array with information about a source file
1557
     * as returned by the analyzeSourceCode() method.
1558
     *
1559
     * @return void
1560
     *
1561
     * @access private
1562
     *
1563
     */
1564
    function _buildProvidesArray($srcinfo)
1565
    {
1566
        if (!$this->_isValid) {
1567
            return false;
1568
        }
1569
        $file = basename($srcinfo['source_file']);
1570
        $pn = $this->getPackage();
1571
        $pnl = strlen($pn);
1572
        foreach ($srcinfo['declared_classes'] as $class) {
1573
            $key = "class;$class";
1574
            if (isset($this->_packageInfo['provides'][$key])) {
1575
                continue;
1576
            }
1577
            $this->_packageInfo['provides'][$key] =
1578
                array('file'=> $file, 'type' => 'class', 'name' => $class);
1579
            if (isset($srcinfo['inheritance'][$class])) {
1580
                $this->_packageInfo['provides'][$key]['extends'] =
1581
                    $srcinfo['inheritance'][$class];
1582
            }
1583
        }
1584
        foreach ($srcinfo['declared_methods'] as $class => $methods) {
1585
            foreach ($methods as $method) {
1586
                $function = "$class::$method";
1587
                $key = "function;$function";
1588
                if ($method{0} == '_' || !strcasecmp($method, $class) ||
1589
                    isset($this->_packageInfo['provides'][$key])) {
1590
                    continue;
1591
                }
1592
                $this->_packageInfo['provides'][$key] =
1593
                    array('file'=> $file, 'type' => 'function', 'name' => $function);
1594
            }
1595
        }
1596
 
1597
        foreach ($srcinfo['declared_functions'] as $function) {
1598
            $key = "function;$function";
1599
            if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) {
1600
                continue;
1601
            }
1602
            if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
1603
                $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
1604
            }
1605
            $this->_packageInfo['provides'][$key] =
1606
                array('file'=> $file, 'type' => 'function', 'name' => $function);
1607
        }
1608
    }
1609
 
1610
    // }}}
1611
}
1612
?>