source: branches/version-2_13-dev/data/module/PEAR/PackageFile/v1.php @ 23125

Revision 23125, 50.0 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

Line 
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 */
19require_once 'PEAR/ErrorStack.php';
20
21/**
22 * Error code if parsing is attempted with no xml extension
23 */
24define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
25
26/**
27 * Error code if creating the xml parser resource fails
28 */
29define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
30
31/**
32 * Error code used for all sax xml parsing errors
33 */
34define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
35
36/**
37 * Error code used when there is no name
38 */
39define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
40
41/**
42 * Error code when a package name is not valid
43 */
44define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
45
46/**
47 * Error code used when no summary is parsed
48 */
49define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
50
51/**
52 * Error code for summaries that are more than 1 line
53 */
54define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
55
56/**
57 * Error code used when no description is present
58 */
59define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
60
61/**
62 * Error code used when no license is present
63 */
64define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
65
66/**
67 * Error code used when a <version> version number is not present
68 */
69define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
70
71/**
72 * Error code used when a <version> version number is invalid
73 */
74define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
75
76/**
77 * Error code when release state is missing
78 */
79define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
80
81/**
82 * Error code when release state is invalid
83 */
84define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
85
86/**
87 * Error code when release state is missing
88 */
89define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
90
91/**
92 * Error code when release state is invalid
93 */
94define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
95
96/**
97 * Error code when no release notes are found
98 */
99define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
100
101/**
102 * Error code when no maintainers are found
103 */
104define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
105
106/**
107 * Error code when a maintainer has no handle
108 */
109define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
110
111/**
112 * Error code when a maintainer has no handle
113 */
114define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
115
116/**
117 * Error code when a maintainer has no name
118 */
119define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
120
121/**
122 * Error code when a maintainer has no email
123 */
124define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
125
126/**
127 * Error code when a maintainer has no handle
128 */
129define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
130
131/**
132 * Error code when a dependency is not a PHP dependency, but has no name
133 */
134define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
135
136/**
137 * Error code when a dependency has no type (pkg, php, etc.)
138 */
139define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
140
141/**
142 * Error code when a dependency has no relation (lt, ge, has, etc.)
143 */
144define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
145
146/**
147 * Error code when a dependency is not a 'has' relation, but has no version
148 */
149define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
150
151/**
152 * Error code when a dependency has an invalid relation
153 */
154define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
155
156/**
157 * Error code when a dependency has an invalid type
158 */
159define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
160
161/**
162 * Error code when a dependency has an invalid optional option
163 */
164define('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 */
169define('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 */
174define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
175
176/**
177 * Error code when rel="has" and version attribute is present.
178 */
179define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
180
181/**
182 * Error code when type="php" and dependency name is present
183 */
184define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
185
186/**
187 * Error code when a configure option has no name
188 */
189define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
190
191/**
192 * Error code when a configure option has no name
193 */
194define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
195
196/**
197 * Error code when a file in the filelist has an invalid role
198 */
199define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
200
201/**
202 * Error code when a file in the filelist has no role
203 */
204define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
205
206/**
207 * Error code when analyzing a php source file that has parse errors
208 */
209define('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 */
215define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
216
217/**
218 * Error code when an unknown channel is specified
219 */
220define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
221
222/**
223 * Error code when no files are found in the filelist
224 */
225define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
226
227/**
228 * Error code when a file is not valid php according to _analyzeSourceCode()
229 */
230define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
231
232/**
233 * Error code when the channel validator returns an error or warning
234 */
235define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
236
237/**
238 * Error code when a php5 package is packaged in php4 (analysis doesn't work)
239 */
240define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
241
242/**
243 * Error code when a file is listed in package.xml but does not exist
244 */
245define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
246
247/**
248 * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
249 */
250define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
251
252/**
253 * Error code when a package.xml contains non-ISO-8859-1 characters
254 */
255define('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 */
260define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
261
262/**
263 * Error code when a package has no lead developer
264 */
265define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
266
267/**
268 * Error code when a filename begins with "."
269 */
270define('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 */
282class 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?>
Note: See TracBrowser for help on using the repository browser.