PageRenderTime 69ms CodeModel.GetById 2ms app.highlight 58ms RepoModel.GetById 1ms app.codeStats 1ms

/script/lib/PEAR/PackageFile/v1.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 1705 lines | 1238 code | 145 blank | 322 comment | 168 complexity | ec0c248c5146f02ed30c4f521d38de9f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 276383 2009-02-24 23:39:37Z 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.1
 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        {
 395            return $this->_packageInfo['_lastversion'];
 396        }
 397        return false;
 398    }
 399
 400    function getInstalledBinary()
 401    {
 402        return false;
 403    }
 404
 405    function listPostinstallScripts()
 406    {
 407        return false;
 408    }
 409
 410    function initPostinstallScripts()
 411    {
 412        return false;
 413    }
 414
 415    function setLogger(&$logger)
 416    {
 417        if ($logger && (! is_object($logger) || ! method_exists($logger, 'log')))
 418        {
 419            return PEAR :: raiseError('Logger must be compatible with PEAR_Common::log');
 420        }
 421        $this->_logger = &$logger;
 422    }
 423
 424    function setPackagefile($file, $archive = false)
 425    {
 426        $this->_packageFile = $file;
 427        $this->_archiveFile = $archive ? $archive : $file;
 428    }
 429
 430    function getPackageFile()
 431    {
 432        return isset($this->_packageFile) ? $this->_packageFile : false;
 433    }
 434
 435    function getPackageType()
 436    {
 437        return 'php';
 438    }
 439
 440    function getArchiveFile()
 441    {
 442        return $this->_archiveFile;
 443    }
 444
 445    function packageInfo($field)
 446    {
 447        if (! is_string($field) || empty($field) || ! isset($this->_packageInfo[$field]))
 448        {
 449            return false;
 450        }
 451        return $this->_packageInfo[$field];
 452    }
 453
 454    function setDirtree($path)
 455    {
 456        if (! isset($this->_packageInfo['dirtree']))
 457        {
 458            $this->_packageInfo['dirtree'] = array();
 459        }
 460        $this->_packageInfo['dirtree'][$path] = true;
 461    }
 462
 463    function getDirtree()
 464    {
 465        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree']))
 466        {
 467            return $this->_packageInfo['dirtree'];
 468        }
 469        return false;
 470    }
 471
 472    function resetDirtree()
 473    {
 474        unset($this->_packageInfo['dirtree']);
 475    }
 476
 477    function fromArray($pinfo)
 478    {
 479        $this->_incomplete = false;
 480        $this->_packageInfo = $pinfo;
 481    }
 482
 483    function isIncomplete()
 484    {
 485        return $this->_incomplete;
 486    }
 487
 488    function getChannel()
 489    {
 490        return 'pear.php.net';
 491    }
 492
 493    function getUri()
 494    {
 495        return false;
 496    }
 497
 498    function getTime()
 499    {
 500        return false;
 501    }
 502
 503    function getExtends()
 504    {
 505        if (isset($this->_packageInfo['extends']))
 506        {
 507            return $this->_packageInfo['extends'];
 508        }
 509        return false;
 510    }
 511
 512    /**
 513     * @return array
 514     */
 515    function toArray()
 516    {
 517        if (! $this->validate(PEAR_VALIDATE_NORMAL))
 518        {
 519            return false;
 520        }
 521        return $this->getArray();
 522    }
 523
 524    function getArray()
 525    {
 526        return $this->_packageInfo;
 527    }
 528
 529    function getName()
 530    {
 531        return $this->getPackage();
 532    }
 533
 534    function getPackage()
 535    {
 536        if (isset($this->_packageInfo['package']))
 537        {
 538            return $this->_packageInfo['package'];
 539        }
 540        return false;
 541    }
 542
 543    /**
 544     * WARNING - don't use this unless you know what you are doing
 545     */
 546    function setRawPackage($package)
 547    {
 548        $this->_packageInfo['package'] = $package;
 549    }
 550
 551    function setPackage($package)
 552    {
 553        $this->_packageInfo['package'] = $package;
 554        $this->_isValid = false;
 555    }
 556
 557    function getVersion()
 558    {
 559        if (isset($this->_packageInfo['version']))
 560        {
 561            return $this->_packageInfo['version'];
 562        }
 563        return false;
 564    }
 565
 566    function setVersion($version)
 567    {
 568        $this->_packageInfo['version'] = $version;
 569        $this->_isValid = false;
 570    }
 571
 572    function clearMaintainers()
 573    {
 574        unset($this->_packageInfo['maintainers']);
 575    }
 576
 577    function getMaintainers()
 578    {
 579        if (isset($this->_packageInfo['maintainers']))
 580        {
 581            return $this->_packageInfo['maintainers'];
 582        }
 583        return false;
 584    }
 585
 586    /**
 587     * Adds a new maintainer - no checking of duplicates is performed, use
 588     * updatemaintainer for that purpose.
 589     */
 590    function addMaintainer($role, $handle, $name, $email)
 591    {
 592        $this->_packageInfo['maintainers'][] = array('handle' => $handle, 'role' => $role, 'email' => $email, 
 593                'name' => $name);
 594        $this->_isValid = false;
 595    }
 596
 597    function updateMaintainer($role, $handle, $name, $email)
 598    {
 599        $found = false;
 600        if (! isset($this->_packageInfo['maintainers']) || ! is_array($this->_packageInfo['maintainers']))
 601        {
 602            return $this->addMaintainer($role, $handle, $name, $email);
 603        }
 604        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer)
 605        {
 606            if ($maintainer['handle'] == $handle)
 607            {
 608                $found = $i;
 609                break;
 610            }
 611        }
 612        if ($found !== false)
 613        {
 614            unset($this->_packageInfo['maintainers'][$found]);
 615            $this->_packageInfo['maintainers'] = array_values($this->_packageInfo['maintainers']);
 616        }
 617        $this->addMaintainer($role, $handle, $name, $email);
 618    }
 619
 620    function deleteMaintainer($handle)
 621    {
 622        $found = false;
 623        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer)
 624        {
 625            if ($maintainer['handle'] == $handle)
 626            {
 627                $found = $i;
 628                break;
 629            }
 630        }
 631        if ($found !== false)
 632        {
 633            unset($this->_packageInfo['maintainers'][$found]);
 634            $this->_packageInfo['maintainers'] = array_values($this->_packageInfo['maintainers']);
 635            return true;
 636        }
 637        return false;
 638    }
 639
 640    function getState()
 641    {
 642        if (isset($this->_packageInfo['release_state']))
 643        {
 644            return $this->_packageInfo['release_state'];
 645        }
 646        return false;
 647    }
 648
 649    function setRawState($state)
 650    {
 651        $this->_packageInfo['release_state'] = $state;
 652    }
 653
 654    function setState($state)
 655    {
 656        $this->_packageInfo['release_state'] = $state;
 657        $this->_isValid = false;
 658    }
 659
 660    function getDate()
 661    {
 662        if (isset($this->_packageInfo['release_date']))
 663        {
 664            return $this->_packageInfo['release_date'];
 665        }
 666        return false;
 667    }
 668
 669    function setDate($date)
 670    {
 671        $this->_packageInfo['release_date'] = $date;
 672        $this->_isValid = false;
 673    }
 674
 675    function getLicense()
 676    {
 677        if (isset($this->_packageInfo['release_license']))
 678        {
 679            return $this->_packageInfo['release_license'];
 680        }
 681        return false;
 682    }
 683
 684    function setLicense($date)
 685    {
 686        $this->_packageInfo['release_license'] = $date;
 687        $this->_isValid = false;
 688    }
 689
 690    function getSummary()
 691    {
 692        if (isset($this->_packageInfo['summary']))
 693        {
 694            return $this->_packageInfo['summary'];
 695        }
 696        return false;
 697    }
 698
 699    function setSummary($summary)
 700    {
 701        $this->_packageInfo['summary'] = $summary;
 702        $this->_isValid = false;
 703    }
 704
 705    function getDescription()
 706    {
 707        if (isset($this->_packageInfo['description']))
 708        {
 709            return $this->_packageInfo['description'];
 710        }
 711        return false;
 712    }
 713
 714    function setDescription($desc)
 715    {
 716        $this->_packageInfo['description'] = $desc;
 717        $this->_isValid = false;
 718    }
 719
 720    function getNotes()
 721    {
 722        if (isset($this->_packageInfo['release_notes']))
 723        {
 724            return $this->_packageInfo['release_notes'];
 725        }
 726        return false;
 727    }
 728
 729    function setNotes($notes)
 730    {
 731        $this->_packageInfo['release_notes'] = $notes;
 732        $this->_isValid = false;
 733    }
 734
 735    function getDeps()
 736    {
 737        if (isset($this->_packageInfo['release_deps']))
 738        {
 739            return $this->_packageInfo['release_deps'];
 740        }
 741        return false;
 742    }
 743
 744    /**
 745     * Reset dependencies prior to adding new ones
 746     */
 747    function clearDeps()
 748    {
 749        unset($this->_packageInfo['release_deps']);
 750    }
 751
 752    function addPhpDep($version, $rel)
 753    {
 754        $this->_isValid = false;
 755        $this->_packageInfo['release_deps'][] = array('type' => 'php', 'rel' => $rel, 'version' => $version);
 756    }
 757
 758    function addPackageDep($name, $version, $rel, $optional = 'no')
 759    {
 760        $this->_isValid = false;
 761        $dep = array('type' => 'pkg', 'name' => $name, 'rel' => $rel, 'optional' => $optional);
 762        if ($rel != 'has' && $rel != 'not')
 763        {
 764            $dep['version'] = $version;
 765        }
 766        $this->_packageInfo['release_deps'][] = $dep;
 767    }
 768
 769    function addExtensionDep($name, $version, $rel, $optional = 'no')
 770    {
 771        $this->_isValid = false;
 772        $this->_packageInfo['release_deps'][] = array('type' => 'ext', 'name' => $name, 'rel' => $rel, 
 773                'version' => $version, 'optional' => $optional);
 774    }
 775
 776    /**
 777     * WARNING - do not use this function directly unless you know what you're doing
 778     */
 779    function setDeps($deps)
 780    {
 781        $this->_packageInfo['release_deps'] = $deps;
 782    }
 783
 784    function hasDeps()
 785    {
 786        return isset($this->_packageInfo['release_deps']) && count($this->_packageInfo['release_deps']);
 787    }
 788
 789    function getDependencyGroup($group)
 790    {
 791        return false;
 792    }
 793
 794    function isCompatible($pf)
 795    {
 796        return false;
 797    }
 798
 799    function isSubpackageOf($p)
 800    {
 801        return $p->isSubpackage($this);
 802    }
 803
 804    function isSubpackage($p)
 805    {
 806        return false;
 807    }
 808
 809    function dependsOn($package, $channel)
 810    {
 811        if (strtolower($channel) != 'pear.php.net')
 812        {
 813            return false;
 814        }
 815        if (! ($deps = $this->getDeps()))
 816        {
 817            return false;
 818        }
 819        foreach ($deps as $dep)
 820        {
 821            if ($dep['type'] != 'pkg')
 822            {
 823                continue;
 824            }
 825            if (strtolower($dep['name']) == strtolower($package))
 826            {
 827                return true;
 828            }
 829        }
 830        return false;
 831    }
 832
 833    function getConfigureOptions()
 834    {
 835        if (isset($this->_packageInfo['configure_options']))
 836        {
 837            return $this->_packageInfo['configure_options'];
 838        }
 839        return false;
 840    }
 841
 842    function hasConfigureOptions()
 843    {
 844        return isset($this->_packageInfo['configure_options']) && count($this->_packageInfo['configure_options']);
 845    }
 846
 847    function addConfigureOption($name, $prompt, $default = false)
 848    {
 849        $o = array('name' => $name, 'prompt' => $prompt);
 850        if ($default !== false)
 851        {
 852            $o['default'] = $default;
 853        }
 854        if (! isset($this->_packageInfo['configure_options']))
 855        {
 856            $this->_packageInfo['configure_options'] = array();
 857        }
 858        $this->_packageInfo['configure_options'][] = $o;
 859    }
 860
 861    function clearConfigureOptions()
 862    {
 863        unset($this->_packageInfo['configure_options']);
 864    }
 865
 866    function getProvides()
 867    {
 868        if (isset($this->_packageInfo['provides']))
 869        {
 870            return $this->_packageInfo['provides'];
 871        }
 872        return false;
 873    }
 874
 875    function getProvidesExtension()
 876    {
 877        return false;
 878    }
 879
 880    function addFile($dir, $file, $attrs)
 881    {
 882        $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
 883        if ($dir == '/' || $dir == '')
 884        {
 885            $dir = '';
 886        }
 887        else
 888        {
 889            $dir .= '/';
 890        }
 891        $file = $dir . $file;
 892        $file = preg_replace('![\\/]+!', '/', $file);
 893        $this->_packageInfo['filelist'][$file] = $attrs;
 894    }
 895
 896    function getInstallationFilelist()
 897    {
 898        return $this->getFilelist();
 899    }
 900
 901    function getFilelist()
 902    {
 903        if (isset($this->_packageInfo['filelist']))
 904        {
 905            return $this->_packageInfo['filelist'];
 906        }
 907        return false;
 908    }
 909
 910    function setFileAttribute($file, $attr, $value)
 911    {
 912        $this->_packageInfo['filelist'][$file][$attr] = $value;
 913    }
 914
 915    function resetFilelist()
 916    {
 917        $this->_packageInfo['filelist'] = array();
 918    }
 919
 920    function setInstalledAs($file, $path)
 921    {
 922        if ($path)
 923        {
 924            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
 925        }
 926        unset($this->_packageInfo['filelist'][$file]['installed_as']);
 927    }
 928
 929    function installedFile($file, $atts)
 930    {
 931        if (isset($this->_packageInfo['filelist'][$file]))
 932        {
 933            $this->_packageInfo['filelist'][$file] = array_merge($this->_packageInfo['filelist'][$file], $atts);
 934        }
 935        else
 936        {
 937            $this->_packageInfo['filelist'][$file] = $atts;
 938        }
 939    }
 940
 941    function getChangelog()
 942    {
 943        if (isset($this->_packageInfo['changelog']))
 944        {
 945            return $this->_packageInfo['changelog'];
 946        }
 947        return false;
 948    }
 949
 950    function getPackagexmlVersion()
 951    {
 952        return '1.0';
 953    }
 954
 955    /**
 956     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
 957     * @param boolean determines whether to purge the error stack after retrieving
 958     * @return array
 959     */
 960    function getValidationWarnings($purge = true)
 961    {
 962        return $this->_stack->getErrors($purge);
 963    }
 964
 965    // }}}
 966    /**
 967     * Validation error.  Also marks the object contents as invalid
 968     * @param error code
 969     * @param array error information
 970     * @access private
 971     */
 972    function _validateError($code, $params = array())
 973    {
 974        $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
 975        $this->_isValid = false;
 976    }
 977
 978    /**
 979     * Validation warning.  Does not mark the object contents invalid.
 980     * @param error code
 981     * @param array error information
 982     * @access private
 983     */
 984    function _validateWarning($code, $params = array())
 985    {
 986        $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
 987    }
 988
 989    /**
 990     * @param integer error code
 991     * @access protected
 992     */
 993    function _getErrorMessage()
 994    {
 995        return array(PEAR_PACKAGEFILE_ERROR_NO_NAME => 'Missing Package Name', 
 996                PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => 'No summary found', 
 997                PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => 'Summary should be on one line', 
 998                PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => 'Missing description', 
 999                PEAR_PACKAGEFILE_ERROR_NO_LICENSE => 'Missing license', 
1000                PEAR_PACKAGEFILE_ERROR_NO_VERSION => 'No release version found', 
1001                PEAR_PACKAGEFILE_ERROR_NO_STATE => 'No release state found', 
1002                PEAR_PACKAGEFILE_ERROR_NO_DATE => 'No release date found', 
1003                PEAR_PACKAGEFILE_ERROR_NO_NOTES => 'No release notes found', 
1004                PEAR_PACKAGEFILE_ERROR_NO_LEAD => 'Package must have at least one lead maintainer', 
1005                PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => 'No maintainers found, at least one must be defined', 
1006                PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => 'Maintainer %index% has no handle (user ID at channel server)', 
1007                PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => 'Maintainer %index% has no role', 
1008                PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => 'Maintainer %index% has no name', 
1009                PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => 'Maintainer %index% has no email', 
1010                PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => 'Dependency %index% is not a php dependency, and has no name', 
1011                PEAR_PACKAGEFILE_ERROR_NO_DEPREL => 'Dependency %index% has no relation (rel)', 
1012                PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => 'Dependency %index% has no type', 
1013                PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => 'PHP Dependency %index% has a name attribute of "%name%" which will be' . ' ignored!', 
1014                PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . 'and has no version', 
1015                PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => 'Dependency %index% is a type="php" dependency, ' . 'and has no version', 
1016                PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', 
1017                PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => 'Dependency %index% has invalid optional value "%opt%", should be yes or no', 
1018                PEAR_PACKAGEFILE_PHP_NO_NOT => 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . ' to exclude specific versions', 
1019                PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => 'Configure Option %index% has no name', 
1020                PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => 'Configure Option %index% has no prompt', 
1021                PEAR_PACKAGEFILE_ERROR_NO_FILES => 'No files in <filelist> section of package.xml', 
1022                PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => 'File "%file%" has no role, expecting one of "%roles%"', 
1023                PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', 
1024                PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => 'File "%file%" cannot start with ".", cannot package or install', 
1025                PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => 'Parser error: invalid PHP found in file "%file%"', 
1026                PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => 'in %file%: %type% "%name%" not prefixed with package name "%package%"', 
1027                PEAR_PACKAGEFILE_ERROR_INVALID_FILE => 'Parser error: invalid PHP file "%file%"', 
1028                PEAR_PACKAGEFILE_ERROR_CHANNELVAL => 'Channel validator error: field "%field%" - %reason%', 
1029                PEAR_PACKAGEFILE_ERROR_PHP5 => 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', 
1030                PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => 'File "%file%" in package.xml does not exist', 
1031                PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => 'Package.xml contains non-ISO-8859-1 characters, and may not validate');
1032    }
1033
1034    /**
1035     * Validate XML package definition file.
1036     *
1037     * @access public
1038     * @return boolean
1039     */
1040    function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
1041    {
1042        if (($this->_isValid & $state) == $state)
1043        {
1044            return true;
1045        }
1046        $this->_isValid = true;
1047        $info = $this->_packageInfo;
1048        if (empty($info['package']))
1049        {
1050            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
1051            $this->_packageName = $pn = 'unknown';
1052        }
1053        else
1054        {
1055            $this->_packageName = $pn = $info['package'];
1056        }
1057        
1058        if (empty($info['summary']))
1059        {
1060            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
1061        }
1062        elseif (strpos(trim($info['summary']), "\n") !== false)
1063        {
1064            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, array('summary' => $info['summary']));
1065        }
1066        if (empty($info['description']))
1067        {
1068            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
1069        }
1070        if (empty($info['release_license']))
1071        {
1072            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
1073        }
1074        if (empty($info['version']))
1075        {
1076            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
1077        }
1078        if (empty($info['release_state']))
1079        {
1080            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
1081        }
1082        if (empty($info['release_date']))
1083        {
1084            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
1085        }
1086        if (empty($info['release_notes']))
1087        {
1088            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
1089        }
1090        if (empty($info['maintainers']))
1091        {
1092            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
1093        }
1094        else
1095        {
1096            $haslead = false;
1097            $i = 1;
1098            foreach ($info['maintainers'] as $m)
1099            {
1100                if (empty($m['handle']))
1101                {
1102                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, array('index' => $i));
1103                }
1104                if (empty($m['role']))
1105                {
1106                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, array('index' => $i, 
1107                            'roles' => PEAR_Common :: getUserRoles()));
1108                }
1109                elseif ($m['role'] == 'lead')
1110                {
1111                    $haslead = true;
1112                }
1113                if (empty($m['name']))
1114                {
1115                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, array('index' => $i));
1116                }
1117                if (empty($m['email']))
1118                {
1119                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, array('index' => $i));
1120                }
1121                $i ++;
1122            }
1123            if (! $haslead)
1124            {
1125                $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
1126            }
1127        }
1128        if (! empty($info['release_deps']))
1129        {
1130            $i = 1;
1131            foreach ($info['release_deps'] as $d)
1132            {
1133                if (! isset($d['type']) || empty($d['type']))
1134                {
1135                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, array('index' => $i, 
1136                            'types' => PEAR_Common :: getDependencyTypes()));
1137                    continue;
1138                }
1139                if (! isset($d['rel']) || empty($d['rel']))
1140                {
1141                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, array('index' => $i, 
1142                            'rels' => PEAR_Common :: getDependencyRelations()));
1143                    continue;
1144                }
1145                if (! empty($d['optional']))
1146                {
1147                    if (! in_array($d['optional'], array('yes', 'no')))
1148                    {
1149                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, array('index' => $i, 
1150                                'opt' => $d['optional']));
1151                    }
1152                }
1153                if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version']))
1154                {
1155                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, array('index' => $i));
1156                }
1157                elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && ! empty($d['version']))
1158                {
1159                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, array('index' => $i, 
1160                            'rel' => $d['rel']));
1161                }
1162                if ($d['type'] == 'php' && ! empty($d['name']))
1163                {
1164                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, array('index' => $i, 
1165                            'name' => $d['name']));
1166                }
1167                elseif ($d['type'] != 'php' && empty($d['name']))
1168                {
1169                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, array('index' => $i));
1170                }
1171                if ($d['type'] == 'php' && empty($d['version']))
1172                {
1173                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, array('index' => $i));
1174                }
1175                if (($d['rel'] == 'not') && ($d['type'] == 'php'))
1176                {
1177                    $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, array('index' => $i));
1178                }
1179                $i ++;
1180            }
1181        }
1182        if (! empty($info['configure_options']))
1183        {
1184            $i = 1;
1185            foreach ($info['configure_options'] as $c)
1186            {
1187                if (empty($c['name']))
1188                {
1189                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, array('index' => $i));
1190                }
1191                if (empty($c['prompt']))
1192                {
1193                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, array('index' => $i));
1194                }
1195                $i ++;
1196            }
1197        }
1198        if (empty($info['filelist']))
1199        {
1200            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
1201            $errors[] = 'no files';
1202        }
1203        else
1204        {
1205            foreach ($info['filelist'] as $file => $fa)
1206            {
1207                if (empty($fa['role']))
1208                {
1209                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, array('file' => $file, 
1210                            'roles' => PEAR_Common :: getFileRoles()));
1211                    continue;
1212                }
1213                elseif (! in_array($fa['role'], PEAR_Common :: getFileRoles()))
1214                {
1215                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, array('file' => $file, 
1216                            'role' => $fa['role'], 'roles' => PEAR_Common :: getFileRoles()));
1217                }
1218                if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file)))
1219                {
1220                    // file contains .. parent directory or . cur directory references
1221                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, array(
1222                            'file' => $file));
1223                }
1224                if (isset($fa['install-as']) && preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $fa['install-as'])))
1225                {
1226                    // install-as contains .. parent directory or . cur directory references
1227                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, array(
1228                            'file' => $file . ' [installed as ' . $fa['install-as'] . ']'));
1229                }
1230                if (isset($fa['baseinstalldir']) && preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $fa['baseinstalldir'])))
1231                {
1232                    // install-as contains .. parent directory or . cur directory references
1233                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, array(
1234                            'file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']'));
1235                }
1236            }
1237        }
1238        if (isset($this->_registry) && $this->_isValid)
1239        {
1240            $chan = $this->_registry->getChannel('pear.php.net');
1241            if (PEAR :: isError($chan))
1242            {
1243                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage());
1244                return $this->_isValid = 0;
1245            }
1246            $validator = $chan->getValidationObject();
1247            $validator->setPackageFile($this);
1248            $validator->validate($state);
1249            $failures = $validator->getFailures();
1250            foreach ($failures['errors'] as $error)
1251            {
1252                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
1253            }
1254            foreach ($failures['warnings'] as $warning)
1255            {
1256                $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
1257            }
1258        }
1259        if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && ! $nofilechecking)
1260        {
1261            if ($this->_analyzePhpFiles())
1262            {
1263                $this->_isValid = true;
1264            }
1265        }
1266        if ($this->_isValid)
1267        {
1268            return $this->_isValid = $state;
1269        }
1270        return $this->_isValid = 0;
1271    }
1272
1273    function _analyzePhpFiles()
1274    {
1275        if (! $this->_isValid)
1276        {
1277            return false;
1278        }
1279        if (! isset($this->_packageFile))
1280        {
1281            return false;
1282        }
1283        $dir_prefix = dirname($this->_packageFile);
1284        $common = new PEAR_Common();
1285        $log = isset($this->_logger) ? array(&$this->_logger, 'log') : array($common, 'log');
1286        $info = $this->getFilelist();
1287        foreach ($info as $file => $fa)
1288        {
1289            if (! file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file))
1290            {
1291                $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, array(
1292                        'file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
1293                continue;
1294            }
1295            if ($fa['role'] == 'php' && $dir_prefix)
1296            {
1297                call_user_func_array($log, array(1, "Analyzing $file"));
1298                $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
1299                if ($srcinfo)
1300                {
1301                    $this->_buildProvidesArray($srcinfo);
1302                }
1303            }
1304        }
1305        $this->_packageName = $pn = $this->getPackage();
1306        $pnl = strlen($pn);
1307        if (isset($this->_packageInfo['provides']))
1308        {
1309            foreach ((array) $this->_packageInfo['provides'] as $key => $what)
1310            {
1311                if (isset($what['explicit']))
1312                {
1313                    // skip conformance checks if the provides entry is
1314                    // specified in the package.xml file
1315                    continue;
1316                }
1317                extract($what);
1318                if ($type == 'class')
1319                {
1320                    if (! strncasecmp($name, $pn, $pnl))
1321                    {
1322                        continue;
1323                    }
1324                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, array('file' => $file, 
1325                            'type' => $type, 'name' => $name, 'package' => $pn));
1326                }
1327                elseif ($type == 'function')
1328                {
1329                    if (strstr($name, '::') || ! strncasecmp($name, $pn, $pnl))
1330                    {
1331                        continue;
1332                    }
1333                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, array('file' => $file, 
1334                            'type' => $type, 'name' => $name, 'package' => $pn));
1335                }
1336            }
1337        }
1338        return $this->_isValid;
1339    }
1340
1341    /**
1342     * Get the default xml generator object
1343     *
1344     * @return PEAR_PackageFile_Generator_v1
1345     */
1346    function &getDefaultGenerator()
1347    {
1348        if (! class_exists('PEAR_PackageFile_Generator_v1'))
1349        {
1350            require_once 'PEAR/PackageFile/Generator/v1.php';
1351        }
1352        $a = &new PEAR_PackageFile_Generator_v1($this);
1353        return $a;
1354    }
1355
1356    /**
1357     * Get the contents of a file listed within the package.xml
1358     * @param string
1359     * @return string
1360     */
1361    function getFileContents($file)
1362    {
1363        if ($this->_archiveFile == $this->_packageFile)
1364        { // unpacked
1365            $dir = dirname($this->_packageFile);
1366            $file = $dir . DIRECTORY_SEPARATOR . $file;
1367            $file = str_replace(array('/', '\\'), array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
1368            if (file_exists($file) && is_readable($file))
1369            {
1370                return implode('', file($file));
1371            }
1372        }
1373        else
1374        { // tgz
1375            if (! class_exists('Archive_Tar'))
1376            {
1377                require_once 'Archive/Tar.php';
1378            }
1379            $tar = &new Archive_Tar($this->_archiveFile);
1380            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
1381            if ($file != 'package.xml' && $file != 'package2.xml')
1382            {
1383                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
1384            }
1385            $file = $tar->extractInString($file);
1386            $tar->popErrorHandling();
1387            if (PEAR :: isError($file))
1388            {
1389                return PEAR :: raiseError("Cannot locate file '$file' in archive");
1390            }
1391            return $file;
1392        }
1393    }
1394
1395    // {{{ analyzeSourceCode()
1396    /**
1397     * Analyze the source code of the given PHP file
1398     *
1399     * @param  string Filename of the PHP file
1400     * @return mixed
1401     * @access private
1402     */
1403    function _analyzeSourceCode($file)
1404    {
1405        if (! function_exists("token_get_all"))
1406        {
1407            return false;
1408        }
1409        if (! defined('T_DOC_COMMENT'))
1410        {
1411            define('T_DOC_COMMENT', T_COMMENT);
1412        }
1413        if (! defined('T_INTERFACE'))
1414        {
1415            define('T_INTERFACE', - 1);
1416        }
1417        if (! defined('T_IMPLEMENTS'))
1418        {
1419            define('T_IMPLEMENTS', - 1);
1420        }
1421        if (! $fp = @fopen($file, "r"))
1422        {
1423            return false;
1424        }
1425        fclose($fp);
1426        $contents = file_get_contents($file);
1427        $tokens = token_get_all($contents);
1428        /*
1429        for ($i = 0; $i < sizeof($tokens); $i++) {
1430            @list($token, $data) = $tokens[$i];
1431            if (is_string($token)) {
1432                var_dump($token);
1433            } else {
1434                print token_name($token) . ' ';
1435                var_dump(rtrim($data));
1436            }
1437        }
1438*/
1439        $look_for = 0;
1440        $paren_level = 0;
1441        $bracket_level = 0;
1442        $brace_level = 0;
1443        $lastphpdoc = '';
1444        $current_class = '';
1445        $current_interface = '';
1446        $current_class_level = - 1;
1447        $current_function = '';
1448        $current_function_level = - 1;
1449        $declared_classes = array();
1450        $declared_interfaces = array();
1451        $declared_functions = array();
1452        $declared_methods = array();
1453        $used_classes = array();
1454        $used_functions = array();
1455        $extends = array();
1456        $implements = array();
1457        $nodeps = array();
1458        $inquote = false;
1459        $interface = false;
1460        for($i = 0; $i < sizeof($tokens); $i ++)
1461        {
1462            if (is_array($tokens[$i]))
1463            {
1464                list($token, $data) = $tokens[$i];
1465            }
1466            else
1467            {
1468                $token = $tokens[$i];
1469                $data = '';
1470            }
1471            if ($inquote)
1472            {
1473                if ($token != '"' && $token != T_END_HEREDOC)
1474                {
1475                    continue;
1476                }
1477                else
1478                {
1479                    $inquote = false;
1480                    continue;
1481                }
1482            }
1483            switch ($token)
1484            {
1485                case T_WHITESPACE :
1486                    continue;
1487                case ';' :
1488                    if ($interface)
1489                    {
1490                        $current_function = '';
1491                        $current_function_level = - 1;
1492                    }
1493                    break;
1494                case '"' :
1495                case T_START_HEREDOC :
1496                    $inquote = true;
1497                    break;
1498                case T_CURLY_OPEN :
1499                case T_DOLLAR_OPEN_CURLY_BRACES :
1500                case '{' :
1501                    $brace_level ++;
1502                    continue 2;
1503                case '}' :
1504                    $brace_level --;
1505                    if ($current_class_level == $brace_level)
1506                    {
1507                        $current_class = '';
1508                        $current_class_level = - 1;
1509                    }
1510                    if ($current_function_level == $brace_level)
1511                    {
1512                        $current_function = '';
1513                        $current_function_level = - 1;
1514                    }
1515                    continue 2;
1516                case '[' :
1517                    $bracket_level ++;
1518                    continue 2;
1519                case ']' :
1520                    $bracket_level --;
1521                    continue 2;
1522                case '(' :
1523                    $paren_level ++;
1524                    continue 2;
1525                case ')' :
1526                    $paren_level --;
1527                    continue 2;
1528                case T_INTERFACE :
1529                    $interface = true;
1530                case T_CLASS :
1531                    if (($current_class_level != - 1) || ($current_function_level != - 1))
1532                    {
1533                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, array('file' => $file));
1534                        return false;
1535                    }
1536                case T_FUNCTION :
1537                case T_NEW :
1538                case T_EXTENDS :
1539                case T_IMPLEMENTS :
1540                    $look_for = $token;
1541                    continue 2;
1542                case T_STRING :
1543                    if (version_compare(zend_version(), '2.0', '<'))
1544                    {
1545                        if (in_array(strtolower($data), array('public', 'private', 'protected', 'abstract', 
1546                                'interface', 'implements', 'throw')))
1547                        {
1548                            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, array($file));
1549                        }
1550                    }
1551                    if ($look_for == T_CLASS)
1552                    {
1553                        $current_class = $data;
1554                        $current_class_level = $brace_level;
1555                        $declared_classes[] = $current_class;
1556                    }
1557                    elseif ($look_for == T_INTERFACE)
1558                    {
1559                        $current_interface = $data;
1560                        $current_class_level = $brace_level;
1561                        $declared_interfaces[] = $current_interface;
1562                    }
1563                    elseif ($look_for == T_IMPLEMENTS)
1564                    {
1565                        $implements[$current_class] = $data;
1566                    }
1567                    elseif ($look_for == T_EXTENDS)
1568                    {
1569                        $extends[$current_class] = $data;
1570                    }
1571                    elseif ($look_for == T_FUNCTION)
1572                    {
1573                        if ($current_class)
1574                        {
1575                            $current_function = "$current_class::$data";
1576                            $declared_methods[$current_class][] = $data;
1577                        }
1578                        elseif ($current_interface)
1579                        {
1580                            $current_function = "$current_interface::$data";
1581                            $declared_methods[$current_interface][] = $data;
1582                        }
1583                        else
1584                        {
1585                            $current_function = $data;
1586                            $declared_functions[] = $current_function;
1587                        }
1588                        $current_function_level = $brace_level;
1589                        $m = array();
1590                    }
1591                    elseif ($look_for == T_NEW)
1592                    {
1593                        $used_classes[$data] = true;
1594                    }
1595                    $look_for = 0;
1596                    continue 2;
1597                case T_VARIABLE :
1598                    $look_for = 0;
1599                    continue 2;
1600                case T_DOC_COMMENT :
1601                case T_COMMENT :
1602                    if (preg_match('!^/\*\*\s!', $data))
1603                    {
1604                        $lastphpdoc = $data;
1605                        if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m))
1606                        {
1607                            $nodeps = array_merge($nodeps, $m[1]);
1608                        }
1609                    }
1610                    continue 2;
1611                case T_DOUBLE_COLON :
1612                    if (! ($token…

Large files files are truncated, but you can click here to view the full file