PEAR
[ class tree: PEAR ] [ index: PEAR ] [ all elements ]

Source for file Validator.php

Documentation is available at Validator.php

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 5                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at the following url:           |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Greg Beaver <cellog@php.net>                                 |
  17. // |                                                                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Validator.php,v 1.82 2005/10/27 05:07:24 cellog Exp $
  21. /**
  22.  * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its
  23.  * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller
  24.  * @author Greg Beaver <cellog@php.net>
  25.  * @access private
  26.  */
  27. class PEAR_PackageFile_v2_Validator
  28. {
  29.     /**
  30.      * @var array 
  31.      */
  32.     var $_packageInfo;
  33.     /**
  34.      * @var PEAR_PackageFile_v2 
  35.      */
  36.     var $_pf;
  37.     /**
  38.      * @var PEAR_ErrorStack 
  39.      */
  40.     var $_stack;
  41.     /**
  42.      * @var int 
  43.      */
  44.     var $_isValid = 0;
  45.     /**
  46.      * @var int 
  47.      */
  48.     var $_curState = 0;
  49.     /**
  50.      * @param PEAR_PackageFile_v2 
  51.      * @param int 
  52.      */
  53.     function validate(&$pf$state = PEAR_VALIDATE_NORMAL)
  54.     {
  55.         $this->_pf &$pf;
  56.         $this->_curState $state;
  57.         $this->_packageInfo $this->_pf->getArray();
  58.         $this->_isValid $this->_pf->_isValid;
  59.         $this->_filesValid $this->_pf->_filesValid;
  60.         $this->_stack &$pf->_stack;
  61.         $this->_stack->getErrors(true);
  62.         if (($this->_isValid $state== $state{
  63.             return true;
  64.         }
  65.         if (!isset($this->_packageInfo|| !is_array($this->_packageInfo)) {
  66.             return false;
  67.         }
  68.         if (!isset($this->_packageInfo['attribs']['version']||
  69.               $this->_packageInfo['attribs']['version'!= '2.0'{
  70.             $this->_noPackageVersion();
  71.         }
  72.         $structure =
  73.         array(
  74.             'name',
  75.             'channel|uri',
  76.             '*extends'// can't be multiple, but this works fine
  77.             'summary',
  78.             'description',
  79.             '+lead'// these all need content checks
  80.             '*developer',
  81.             '*contributor',
  82.             '*helper',
  83.             'date',
  84.             '*time',
  85.             'version',
  86.             'stability',
  87.             'license->?uri->?filesource',
  88.             'notes',
  89.             'contents'//special validation needed
  90.             '*compatible',
  91.             'dependencies'//special validation needed
  92.             '*usesrole',
  93.             '*usestask'// reserve these for 1.4.0a1 to implement
  94.                          // this will allow a package.xml to gracefully say it
  95.                          // needs a certain package installed in order to implement a role or task
  96.             '*providesextension',
  97.             '*srcpackage|*srcuri',
  98.             '+phprelease|+extsrcrelease|+extbinrelease|bundle'//special validation needed
  99.             '*changelog',
  100.         );
  101.         $test $this->_packageInfo;
  102.         // ignore post-installation array fields
  103.         if (array_key_exists('filelist'$test)) {
  104.             unset($test['filelist']);
  105.         }
  106.         if (array_key_exists('_lastmodified'$test)) {
  107.             unset($test['_lastmodified']);
  108.         }
  109.         if (array_key_exists('#binarypackage'$test)) {
  110.             unset($test['#binarypackage']);
  111.         }
  112.         if (array_key_exists('old'$test)) {
  113.             unset($test['old']);
  114.         }
  115.         if (array_key_exists('_lastversion'$test)) {
  116.             unset($test['_lastversion']);
  117.         }
  118.         if (!$this->_stupidSchemaValidate($structure,
  119.                                           $test'<package>')) {
  120.             return false;
  121.         }
  122.         if (empty($this->_packageInfo['name'])) {
  123.             $this->_tagCannotBeEmpty('name');
  124.         }
  125.         if (isset($this->_packageInfo['uri'])) {
  126.             $test 'uri';
  127.         else {
  128.             $test 'channel';
  129.         }
  130.         if (empty($this->_packageInfo[$test])) {
  131.             $this->_tagCannotBeEmpty($test);
  132.         }
  133.         if (is_array($this->_packageInfo['license']&&
  134.               (!isset($this->_packageInfo['license']['_content']||
  135.               empty($this->_packageInfo['license']['_content']))) {
  136.             $this->_tagCannotBeEmpty('license');
  137.         elseif (empty($this->_packageInfo['license'])) {
  138.             $this->_tagCannotBeEmpty('license');
  139.         }
  140.         if (empty($this->_packageInfo['summary'])) {
  141.             $this->_tagCannotBeEmpty('summary');
  142.         }
  143.         if (empty($this->_packageInfo['description'])) {
  144.             $this->_tagCannotBeEmpty('description');
  145.         }
  146.         if (empty($this->_packageInfo['date'])) {
  147.             $this->_tagCannotBeEmpty('date');
  148.         }
  149.         if (empty($this->_packageInfo['notes'])) {
  150.             $this->_tagCannotBeEmpty('notes');
  151.         }
  152.         if (isset($this->_packageInfo['time']&& empty($this->_packageInfo['time'])) {
  153.             $this->_tagCannotBeEmpty('time');
  154.         }
  155.         if (isset($this->_packageInfo['dependencies'])) {
  156.             $this->_validateDependencies();
  157.         }
  158.         if (isset($this->_packageInfo['compatible'])) {
  159.             $this->_validateCompatible();
  160.         }
  161.         if (!isset($this->_packageInfo['bundle'])) {
  162.             if (!isset($this->_packageInfo['contents']['dir'])) {
  163.                 $this->_filelistMustContainDir('contents');
  164.                 return false;
  165.             }
  166.             if (isset($this->_packageInfo['contents']['file'])) {
  167.                 $this->_filelistCannotContainFile('contents');
  168.                 return false;
  169.             }
  170.         }
  171.         $this->_validateMaintainers();
  172.         $this->_validateStabilityVersion();
  173.         $fail = false;
  174.         if (array_key_exists('usesrole'$this->_packageInfo)) {
  175.             $roles $this->_packageInfo['usesrole'];
  176.             if (!is_array($roles|| !isset($roles[0])) {
  177.                 $roles = array($roles);
  178.             }
  179.             foreach ($roles as $role{
  180.                 if (!isset($role['role'])) {
  181.                     $this->_usesroletaskMustHaveRoleTask('usesrole''role');
  182.                     $fail = true;
  183.                 else {
  184.                     if (!isset($role['channel'])) {
  185.                         if (!isset($role['uri'])) {
  186.                             $this->_usesroletaskMustHaveChannelOrUri($role['role']'usesrole');
  187.                             $fail = true;
  188.                         }
  189.                     elseif (!isset($role['package'])) {
  190.                         $this->_usesroletaskMustHavePackage($role['role']'usesrole');
  191.                         $fail = true;
  192.                     }
  193.                 }
  194.             }
  195.         }
  196.         if (array_key_exists('usestask'$this->_packageInfo)) {
  197.             $roles $this->_packageInfo['usestask'];
  198.             if (!is_array($roles|| !isset($roles[0])) {
  199.                 $roles = array($roles);
  200.             }
  201.             foreach ($roles as $role{
  202.                 if (!isset($role['task'])) {
  203.                     $this->_usesroletaskMustHaveRoleTask('usestask''task');
  204.                     $fail = true;
  205.                 else {
  206.                     if (!isset($role['channel'])) {
  207.                         if (!isset($role['uri'])) {
  208.                             $this->_usesroletaskMustHaveChannelOrUri($role['task']'usestask');
  209.                             $fail = true;
  210.                         }
  211.                     elseif (!isset($role['package'])) {
  212.                         $this->_usesroletaskMustHavePackage($role['task']'usestask');
  213.                         $fail = true;
  214.                     }
  215.                 }
  216.             }
  217.         }
  218.         if ($fail{
  219.             return false;
  220.         }
  221.         $this->_validateFilelist();
  222.         $this->_validateRelease();
  223.         if (!$this->_stack->hasErrors()) {
  224.             $chan $this->_pf->_registry->getChannel($this->_pf->getChannel()true);
  225.             if (!$chan{
  226.                 $this->_unknownChannel($this->_pf->getChannel());
  227.             else {
  228.                 $valpack $chan->getValidationPackage();
  229.                 // for channel validator packages, always use the default PEAR validator.
  230.                 // otherwise, they can't be installed or packaged
  231.                 $validator $chan->getValidationObject($this->_pf->getPackage());
  232.                 if (!$validator{
  233.                     $this->_stack->push(__FUNCTION__'error',
  234.                         array_merge(
  235.                             array('channel' => $chan->getName(),
  236.                                   'package' => $this->_pf->getPackage()),
  237.                               $valpack
  238.                             ),
  239.                         'package "%channel%/%package%" cannot be properly validated without ' .
  240.                         'validation package "%channel%/%name%-%version%"');
  241.                     return $this->_isValid = 0;
  242.                 }
  243.                 $validator->setPackageFile($this->_pf);
  244.                 $validator->validate($state);
  245.                 $failures $validator->getFailures();
  246.                 foreach ($failures['errors'as $error{
  247.                     $this->_stack->push(__FUNCTION__'error'$error,
  248.                         'Channel validator error: field "%field%" - %reason%');
  249.                 }
  250.                 foreach ($failures['warnings'as $warning{
  251.                     $this->_stack->push(__FUNCTION__'warning'$warning,
  252.                         'Channel validator warning: field "%field%" - %reason%');
  253.                 }
  254.             }
  255.         }
  256.         $this->_pf->_isValid = $this->_isValid !$this->_stack->hasErrors('error');
  257.         if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid{
  258.             if ($this->_pf->getPackageType(== 'bundle'{
  259.                 if ($this->_analyzeBundledPackages()) {
  260.                     $this->_filesValid $this->_pf->_filesValid = true;
  261.                 else {
  262.                     $this->_pf->_isValid = $this->_isValid = 0;
  263.                 }
  264.             else {
  265.                 if (!$this->_analyzePhpFiles()) {
  266.                     $this->_pf->_isValid = $this->_isValid = 0;
  267.                 else {
  268.                     $this->_filesValid $this->_pf->_filesValid = true;
  269.                 }
  270.             }
  271.         }
  272.         if ($this->_isValid{
  273.             return $this->_pf->_isValid = $this->_isValid $state;
  274.         }
  275.         return $this->_pf->_isValid = $this->_isValid = 0;
  276.     }
  277.  
  278.     function _stupidSchemaValidate($structure$xml$root)
  279.     {
  280.         if (!is_array($xml)) {
  281.             $xml = array();
  282.         }
  283.         $keys array_keys($xml);
  284.         reset($keys);
  285.         $key current($keys);
  286.         while ($key == 'attribs' || $key == '_contents'{
  287.             $key next($keys);
  288.         }
  289.         $unfoundtags $optionaltags = array();
  290.         $ret = true;
  291.         $mismatch = false;
  292.         foreach ($structure as $struc{
  293.             if ($key{
  294.                 $tag $xml[$key];
  295.             }
  296.             $test $this->_processStructure($struc);
  297.             if (isset($test['choices'])) {
  298.                 $loose = true;
  299.                 foreach ($test['choices'as $choice{
  300.                     if ($key == $choice['tag']{
  301.                         $key next($keys);
  302.                         while ($key == 'attribs' || $key == '_contents'{
  303.                             $key next($keys);
  304.                         }
  305.                         $unfoundtags $optionaltags = array();
  306.                         $mismatch = false;
  307.                         if ($key && $key != $choice['tag'&& isset($choice['multiple'])) {
  308.                             $unfoundtags[$choice['tag'];
  309.                             $optionaltags[$choice['tag'];
  310.                             if ($key{
  311.                                 $mismatch = true;
  312.                             }
  313.                         }
  314.                         $ret &= $this->_processAttribs($choice$tag$root);
  315.                         continue 2;
  316.                     else {
  317.                         $unfoundtags[$choice['tag'];
  318.                         $mismatch = true;
  319.                     }
  320.                     if (!isset($choice['multiple']|| $choice['multiple'!= '*'{
  321.                         $loose = false;
  322.                     else {
  323.                         $optionaltags[$choice['tag'];
  324.                     }
  325.                 }
  326.                 if (!$loose{
  327.                     $this->_invalidTagOrder($unfoundtags$key$root);
  328.                     return false;
  329.                 }
  330.             else {
  331.                 if ($key != $test['tag']{
  332.                     if (isset($test['multiple']&& $test['multiple'!= '*'{
  333.                         $unfoundtags[$test['tag'];
  334.                         $this->_invalidTagOrder($unfoundtags$key$root);
  335.                         return false;
  336.                     else {
  337.                         if ($key{
  338.                             $mismatch = true;
  339.                         }
  340.                         $unfoundtags[$test['tag'];
  341.                         $optionaltags[$test['tag'];
  342.                     }
  343.                     if (!isset($test['multiple'])) {
  344.                         $this->_invalidTagOrder($unfoundtags$key$root);
  345.                         return false;
  346.                     }
  347.                     continue;
  348.                 else {
  349.                     $unfoundtags $optionaltags = array();
  350.                     $mismatch = false;
  351.                 }
  352.                 $key next($keys);
  353.                 while ($key == 'attribs' || $key == '_contents'{
  354.                     $key next($keys);
  355.                 }
  356.                 if ($key && $key != $test['tag'&& isset($test['multiple'])) {
  357.                     $unfoundtags[$test['tag'];
  358.                     $optionaltags[$test['tag'];
  359.                     $mismatch = true;
  360.                 }
  361.                 $ret &= $this->_processAttribs($test$tag$root);
  362.                 continue;
  363.             }
  364.         }
  365.         if (!$mismatch && count($optionaltags)) {
  366.             // don't error out on any optional tags
  367.             $unfoundtags array_diff($unfoundtags$optionaltags);
  368.         }
  369.         if (count($unfoundtags)) {
  370.             $this->_invalidTagOrder($unfoundtags$key$root);
  371.         elseif ($key{
  372.             // unknown tags
  373.             $this->_invalidTagOrder('*no tags allowed here*'$key$root);
  374.             while ($key next($keys)) {
  375.                 $this->_invalidTagOrder('*no tags allowed here*'$key$root);
  376.             }
  377.         }
  378.         return $ret;
  379.     }
  380.  
  381.     function _processAttribs($choice$tag$context)
  382.     {
  383.         if (isset($choice['attribs'])) {
  384.             if (!is_array($tag)) {
  385.                 $tag = array($tag);
  386.             }
  387.             $tags $tag;
  388.             if (!isset($tags[0])) {
  389.                 $tags = array($tags);
  390.             }
  391.             $ret = true;
  392.             foreach ($tags as $i => $tag{
  393.                 if (!is_array($tag|| !isset($tag['attribs'])) {
  394.                     foreach ($choice['attribs'as $attrib{
  395.                         if ($attrib{0!= '?'{
  396.                             $ret &= $this->_tagHasNoAttribs($choice['tag'],
  397.                                 $context);
  398.                             continue 2;
  399.                         }
  400.                     }
  401.                 }
  402.                 foreach ($choice['attribs'as $attrib{
  403.                     if ($attrib{0!= '?'{
  404.                         if (!isset($tag['attribs'][$attrib])) {
  405.                             $ret &= $this->_tagMissingAttribute($choice['tag'],
  406.                                 $attrib$context);
  407.                         }
  408.                     }
  409.                 }
  410.             }
  411.             return $ret;
  412.         }
  413.         return true;
  414.     }
  415.  
  416.     function _processStructure($key)
  417.     {
  418.         $ret = array();
  419.         if (count($pieces explode('|'$key)) > 1{
  420.             foreach ($pieces as $piece{
  421.                 $ret['choices'][$this->_processStructure($piece);
  422.             }
  423.             return $ret;
  424.         }
  425.         $multi $key{0};
  426.         if ($multi == '+' || $multi == '*'{
  427.             $ret['multiple'$key{0};
  428.             $key substr($key1);
  429.         }
  430.         if (count($attrs explode('->'$key)) > 1{
  431.             $ret['tag'array_shift($attrs);
  432.             $ret['attribs'$attrs;
  433.         else {
  434.             $ret['tag'$key;
  435.         }
  436.         return $ret;
  437.     }
  438.  
  439.     function _validateStabilityVersion()
  440.     {
  441.         $structure = array('release''api');
  442.         $a $this->_stupidSchemaValidate($structure$this->_packageInfo['version']'<version>');
  443.         $a &= $this->_stupidSchemaValidate($structure$this->_packageInfo['stability']'<stability>');
  444.         if ($a{
  445.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  446.                   $this->_packageInfo['version']['release'])) {
  447.                 $this->_invalidVersion('release'$this->_packageInfo['version']['release']);
  448.             }
  449.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  450.                   $this->_packageInfo['version']['api'])) {
  451.                 $this->_invalidVersion('api'$this->_packageInfo['version']['api']);
  452.             }
  453.             if (!in_array($this->_packageInfo['stability']['release'],
  454.                   array('snapshot''devel''alpha''beta''stable'))) {
  455.                 $this->_invalidState('release'$this->_packageinfo['stability']['release']);
  456.             }
  457.             if (!in_array($this->_packageInfo['stability']['api'],
  458.                   array('devel''alpha''beta''stable'))) {
  459.                 $this->_invalidState('api'$this->_packageinfo['stability']['api']);
  460.             }
  461.         }
  462.     }
  463.  
  464.     function _validateMaintainers()
  465.     {
  466.         $structure =
  467.             array(
  468.                 'name',
  469.                 'user',
  470.                 'email',
  471.                 'active',
  472.             );
  473.         foreach (array('lead''developer''contributor''helper'as $type{
  474.             if (!isset($this->_packageInfo[$type])) {
  475.                 continue;
  476.             }
  477.             if (isset($this->_packageInfo[$type][0])) {
  478.                 foreach ($this->_packageInfo[$typeas $lead{
  479.                     $this->_stupidSchemaValidate($structure$lead'<' $type '>');
  480.                 }
  481.             else {
  482.                 $this->_stupidSchemaValidate($structure$this->_packageInfo[$type],
  483.                     '<' $type '>');
  484.             }
  485.         }
  486.     }
  487.  
  488.     function _validatePhpDep($dep$installcondition = false)
  489.     {
  490.         $structure = array(
  491.             'min',
  492.             '*max',
  493.             '*exclude',
  494.         );
  495.         $type $installcondition '<installcondition><php>' '<dependencies><required><php>';
  496.         $this->_stupidSchemaValidate($structure$dep$type);
  497.         if (isset($dep['min'])) {
  498.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?$/',
  499.                   $dep['min'])) {
  500.                 $this->_invalidVersion($type '<min>'$dep['min']);
  501.             }
  502.         }
  503.         if (isset($dep['max'])) {
  504.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?$/',
  505.                   $dep['max'])) {
  506.                 $this->_invalidVersion($type '<max>'$dep['max']);
  507.             }
  508.         }
  509.     }
  510.  
  511.     function _validatePearinstallerDep($dep)
  512.     {
  513.         $structure = array(
  514.             'min',
  515.             '*max',
  516.             '*recommended',
  517.             '*exclude',
  518.         );
  519.         $this->_stupidSchemaValidate($structure$dep'<dependencies><required><pearinstaller>');
  520.         if (isset($dep['min'])) {
  521.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  522.                   $dep['min'])) {
  523.                 $this->_invalidVersion('<dependencies><required><pearinstaller><min>',
  524.                     $dep['min']);
  525.             }
  526.         }
  527.         if (isset($dep['max'])) {
  528.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  529.                   $dep['max'])) {
  530.                 $this->_invalidVersion('<dependencies><required><pearinstaller><max>',
  531.                     $dep['max']);
  532.             }
  533.         }
  534.         if (isset($dep['recommended'])) {
  535.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  536.                   $dep['recommended'])) {
  537.                 $this->_invalidVersion('<dependencies><required><pearinstaller><recommended>',
  538.                     $dep['recommended']);
  539.             }
  540.         }
  541.         if (isset($dep['exclude'])) {
  542.             if (!is_array($dep['exclude'])) {
  543.                 $dep['exclude'= array($dep['exclude']);
  544.             }
  545.             foreach ($dep['exclude'as $exclude{
  546.                 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  547.                       $exclude)) {
  548.                     $this->_invalidVersion('<dependencies><required><pearinstaller><exclude>',
  549.                         $exclude);
  550.                 }
  551.             }
  552.         }
  553.     }
  554.  
  555.     function _validatePackageDep($dep$group$type '<package>')
  556.     {
  557.         if (isset($dep['uri'])) {
  558.             if (isset($dep['conflicts'])) {
  559.                 $structure = array(
  560.                     'name',
  561.                     'uri',
  562.                     'conflicts',
  563.                     '*providesextension',
  564.                 );
  565.             else {
  566.                 $structure = array(
  567.                     'name',
  568.                     'uri',
  569.                     '*providesextension',
  570.                 );
  571.             }
  572.         else {
  573.             if (isset($dep['conflicts'])) {
  574.                 $structure = array(
  575.                     'name',
  576.                     'channel',
  577.                     '*min',
  578.                     '*max',
  579.                     '*exclude',
  580.                     'conflicts',
  581.                     '*providesextension',
  582.                 );
  583.             else {
  584.                 $structure = array(
  585.                     'name',
  586.                     'channel',
  587.                     '*min',
  588.                     '*max',
  589.                     '*recommended',
  590.                     '*exclude',
  591.                     '*nodefault',
  592.                     '*providesextension',
  593.                 );
  594.             }
  595.         }
  596.         if (isset($dep['name'])) {
  597.             $type .= '<name>' $dep['name''</name>';
  598.         }
  599.         $this->_stupidSchemaValidate($structure$dep'<dependencies>' $group $type);
  600.         if (isset($dep['uri']&& (isset($dep['min']|| isset($dep['max']||
  601.               isset($dep['recommended']|| isset($dep['exclude']))) {
  602.             $this->_uriDepsCannotHaveVersioning('<dependencies>' $group $type);
  603.         }
  604.         if (isset($dep['channel']&& strtolower($dep['channel']== '__uri'{
  605.             $this->_DepchannelCannotBeUri('<dependencies>' $group $type);
  606.         }
  607.         if (isset($dep['min'])) {
  608.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  609.                   $dep['min'])) {
  610.                 $this->_invalidVersion('<dependencies>' $group $type '<min>'$dep['min']);
  611.             }
  612.         }
  613.         if (isset($dep['max'])) {
  614.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  615.                   $dep['max'])) {
  616.                 $this->_invalidVersion('<dependencies>' $group $type '<max>'$dep['max']);
  617.             }
  618.         }
  619.         if (isset($dep['recommended'])) {
  620.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  621.                   $dep['recommended'])) {
  622.                 $this->_invalidVersion('<dependencies>' $group $type '<recommended>',
  623.                     $dep['recommended']);
  624.             }
  625.         }
  626.         if (isset($dep['exclude'])) {
  627.             if (!is_array($dep['exclude'])) {
  628.                 $dep['exclude'= array($dep['exclude']);
  629.             }
  630.             foreach ($dep['exclude'as $exclude{
  631.                 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  632.                       $exclude)) {
  633.                     $this->_invalidVersion('<dependencies>' $group $type '<exclude>',
  634.                         $exclude);
  635.                 }
  636.             }
  637.         }
  638.     }
  639.  
  640.     function _validateSubpackageDep($dep$group)
  641.     {
  642.         $this->_validatePackageDep($dep$group'<subpackage>');
  643.         if (isset($dep['providesextension'])) {
  644.             $this->_subpackageCannotProvideExtension(@$dep['name']);
  645.         }
  646.         if (isset($dep['conflicts'])) {
  647.             $this->_subpackagesCannotConflict(@$dep['name']);
  648.         }
  649.     }
  650.  
  651.     function _validateExtensionDep($dep$group = false$installcondition = false)
  652.     {
  653.         if (isset($dep['conflicts'])) {
  654.             $structure = array(
  655.                 'name',
  656.                 '*min',
  657.                 '*max',
  658.                 '*exclude',
  659.                 'conflicts',
  660.             );
  661.         else {
  662.             $structure = array(
  663.                 'name',
  664.                 '*min',
  665.                 '*max',
  666.                 '*recommended',
  667.                 '*exclude',
  668.             );
  669.         }
  670.         if ($installcondition{
  671.             $type '<installcondition><extension>';
  672.         else {
  673.             $type '<dependencies>' $group '<extension>';
  674.         }
  675.         if (isset($dep['name'])) {
  676.             $type .= '<name>' $dep['name''</name>';
  677.         }
  678.         $this->_stupidSchemaValidate($structure$dep$type);
  679.         if (isset($dep['min'])) {
  680.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  681.                   $dep['min'])) {
  682.                 $this->_invalidVersion(substr($type1'<min'$dep['min']);
  683.             }
  684.         }
  685.         if (isset($dep['max'])) {
  686.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  687.                   $dep['max'])) {
  688.                 $this->_invalidVersion(substr($type1'<max'$dep['max']);
  689.             }
  690.         }
  691.         if (isset($dep['recommended'])) {
  692.             if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  693.                   $dep['recommended'])) {
  694.                 $this->_invalidVersion(substr($type1'<recommended'$dep['recommended']);
  695.             }
  696.         }
  697.         if (isset($dep['exclude'])) {
  698.             if (!is_array($dep['exclude'])) {
  699.                 $dep['exclude'= array($dep['exclude']);
  700.             }
  701.             foreach ($dep['exclude'as $exclude{
  702.                 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  703.                       $exclude)) {
  704.                     $this->_invalidVersion(substr($type1'<exclude'$exclude);
  705.                 }
  706.             }
  707.         }
  708.     }
  709.  
  710.     function _validateOsDep($dep$installcondition = false)
  711.     {
  712.         $structure = array(
  713.             'name',
  714.             '*conflicts',
  715.         );
  716.         $type $installcondition '<installcondition><os>' '<dependencies><required><os>';
  717.         if ($this->_stupidSchemaValidate($structure$dep$type)) {
  718.             if ($dep['name'== '*'{
  719.                 if (array_key_exists('conflicts'$dep)) {
  720.                     $this->_cannotConflictWithAllOs($type);
  721.                 }
  722.             }
  723.         }
  724.     }
  725.  
  726.     function _validateArchDep($dep$installcondition = false)
  727.     {
  728.         $structure = array(
  729.             'pattern',
  730.             '*conflicts',
  731.         );
  732.         $type $installcondition '<installcondition><arch>' '<dependencies><required><arch>';
  733.         $this->_stupidSchemaValidate($structure$dep$type);
  734.     }
  735.  
  736.     function _validateInstallConditions($cond$release)
  737.     {
  738.         $structure = array(
  739.             '*php',
  740.             '*extension',
  741.             '*os',
  742.             '*arch',
  743.         );
  744.         if (!$this->_stupidSchemaValidate($structure,
  745.               $cond$release)) {
  746.             return false;
  747.         }
  748.         foreach (array('php''extension''os''arch'as $type{
  749.             if (isset($cond[$type])) {
  750.                 $iter $cond[$type];
  751.                 if (!is_array($iter|| !isset($iter[0])) {
  752.                     $iter = array($iter);
  753.                 }
  754.                 foreach ($iter as $package{
  755.                     if ($type == 'extension'{
  756.                         $this->{"_validate{$type}Dep"}($packagefalsetrue);
  757.                     else {
  758.                         $this->{"_validate{$type}Dep"}($packagetrue);
  759.                     }
  760.                 }
  761.             }
  762.         }
  763.     }
  764.  
  765.     function _validateDependencies()
  766.     {
  767.         $structure = array(
  768.             'required',
  769.             '*optional',
  770.             '*group->name->hint'
  771.         );
  772.         if (!$this->_stupidSchemaValidate($structure,
  773.               $this->_packageInfo['dependencies']'<dependencies>')) {
  774.             return false;
  775.         }
  776.         foreach (array('required''optional'as $simpledep{
  777.             if (isset($this->_packageInfo['dependencies'][$simpledep])) {
  778.                 if ($simpledep == 'optional'{
  779.                     $structure = array(
  780.                         '*package',
  781.                         '*subpackage',
  782.                         '*extension',
  783.                     );
  784.                 else {
  785.                     $structure = array(
  786.                         'php',
  787.                         'pearinstaller',
  788.                         '*package',
  789.                         '*subpackage',
  790.                         '*extension',
  791.                         '*os',
  792.                         '*arch',
  793.                     );
  794.                 }
  795.                 if ($this->_stupidSchemaValidate($structure,
  796.                       $this->_packageInfo['dependencies'][$simpledep],
  797.                       "<dependencies><$simpledep>")) {
  798.                     foreach (array('package''subpackage''extension'as $type{
  799.                         if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
  800.                             $iter $this->_packageInfo['dependencies'][$simpledep][$type];
  801.                             if (!isset($iter[0])) {
  802.                                 $iter = array($iter);
  803.                             }
  804.                             foreach ($iter as $package{
  805.                                 if ($type != 'extension'{
  806.                                     if (isset($package['uri'])) {
  807.                                         if (isset($package['channel'])) {
  808.                                             $this->_UrlOrChannel($type,
  809.                                                 $package['name']);
  810.                                         }
  811.                                     else {
  812.                                         if (!isset($package['channel'])) {
  813.                                             $this->_NoChannel($type$package['name']);
  814.                                         }
  815.                                     }
  816.                                 }
  817.                                 $this->{"_validate{$type}Dep"}($package"<$simpledep>");
  818.                             }
  819.                         }
  820.                     }
  821.                     if ($simpledep == 'optional'{
  822.                         continue;
  823.                     }
  824.                     foreach (array('php''pearinstaller''os''arch'as $type{
  825.                         if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
  826.                             $iter $this->_packageInfo['dependencies'][$simpledep][$type];
  827.                             if (!isset($iter[0])) {
  828.                                 $iter = array($iter);
  829.                             }
  830.                             foreach ($iter as $package{
  831.                                 $this->{"_validate{$type}Dep"}($package);
  832.                             }
  833.                         }
  834.                     }
  835.                 }
  836.             }
  837.         }
  838.         if (isset($this->_packageInfo['dependencies']['group'])) {
  839.             $groups $this->_packageInfo['dependencies']['group'];
  840.             if (!isset($groups[0])) {
  841.                 $groups = array($groups);
  842.             }
  843.             $structure = array(
  844.                 '*package',
  845.                 '*subpackage',
  846.                 '*extension',
  847.             );
  848.             foreach ($groups as $group{
  849.                 if ($this->_stupidSchemaValidate($structure$group'<group>')) {
  850.                     if (!PEAR_Validate::validGroupName($group['attribs']['name'])) {
  851.                         $this->_invalidDepGroupName($group['attribs']['name']);
  852.                     }
  853.                     foreach (array('package''subpackage''extension'as $type{
  854.                         if (isset($group[$type])) {
  855.                             $iter $group[$type];
  856.                             if (!isset($iter[0])) {
  857.                                 $iter = array($iter);
  858.                             }
  859.                             foreach ($iter as $package{
  860.                                 if ($type != 'extension'{
  861.                                     if (isset($package['uri'])) {
  862.                                         if (isset($package['channel'])) {
  863.                                             $this->_UrlOrChannelGroup($type,
  864.                                                 $package['name'],
  865.                                                 $group['name']);
  866.                                         }
  867.                                     else {
  868.                                         if (!isset($package['channel'])) {
  869.                                             $this->_NoChannelGroup($type,
  870.                                                 $package['name'],
  871.                                                 $group['name']);
  872.                                         }
  873.                                     }
  874.                                 }
  875.                                 $this->{"_validate{$type}Dep"}($package'<group name="' .
  876.                                     $group['attribs']['name''">');
  877.                             }
  878.                         }
  879.                     }
  880.                 }
  881.             }
  882.         }
  883.     }
  884.  
  885.     function _validateCompatible()
  886.     {
  887.         $compat $this->_packageInfo['compatible'];
  888.         if (!isset($compat[0])) {
  889.             $compat = array($compat);
  890.         }
  891.         $required = array('name''channel''min''max''*exclude');
  892.         foreach ($compat as $package{
  893.             $type '<compatible>';
  894.             if (is_array($package&& array_key_exists('name'$package)) {
  895.                 $type .= '<name>' $package['name''</name>';
  896.             }
  897.             $this->_stupidSchemaValidate($required$package$type);
  898.             if (is_array($package&& array_key_exists('min'$package)) {
  899.                 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  900.                       $package['min'])) {
  901.                     $this->_invalidVersion(substr($type1'<min'$package['min']);
  902.                 }
  903.             }
  904.             if (is_array($package&& array_key_exists('max'$package)) {
  905.                 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  906.                       $package['max'])) {
  907.                     $this->_invalidVersion(substr($type1'<max'$package['max']);
  908.                 }
  909.             }
  910.             if (is_array($package&& array_key_exists('exclude'$package)) {
  911.                 if (!is_array($package['exclude'])) {
  912.                     $package['exclude'= array($package['exclude']);
  913.                 }
  914.                 foreach ($package['exclude'as $exclude{
  915.                     if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/',
  916.                           $exclude)) {
  917.                         $this->_invalidVersion(substr($type1'<exclude'$exclude);
  918.                     }
  919.                 }
  920.             }
  921.         }
  922.     }
  923.  
  924.     function _validateBundle($list)
  925.     {
  926.         if (!is_array($list|| !isset($list['bundledpackage'])) {
  927.             return $this->_NoBundledPackages();
  928.         }
  929.         if (!is_array($list['bundledpackage']|| !isset($list['bundledpackage'][0])) {
  930.             return $this->_AtLeast2BundledPackages();
  931.         }
  932.         foreach ($list['bundledpackage'as $package{
  933.             if (!is_string($package)) {
  934.                 $this->_bundledPackagesMustBeFilename();
  935.             }
  936.         }
  937.     }
  938.  
  939.     function _validateFilelist($list = false$allowignore = false$dirs '')
  940.     {
  941.         $iscontents = false;
  942.         if (!$list{
  943.             $iscontents = true;
  944.             $list $this->_packageInfo['contents'];
  945.             if (isset($this->_packageInfo['bundle'])) {
  946.                 return $this->_validateBundle($list);
  947.             }
  948.         }
  949.         if ($allowignore{
  950.             $struc = array(
  951.                 '*install->name->as',
  952.                 '*ignore->name'
  953.             );
  954.         else {
  955.             $struc = array(
  956.                 '*dir->name->?baseinstalldir',
  957.                 '*file->name->role->?baseinstalldir->?md5sum'
  958.             );
  959.             if (isset($list['dir']&& isset($list['file'])) {
  960.                 // stave off validation errors without requiring a set order.
  961.                 $_old $list;
  962.                 if (isset($list['attribs'])) {
  963.                     $list = array('attribs' => $_old['attribs']);
  964.                 }
  965.                 $list['dir'$_old['dir'];
  966.                 $list['file'$_old['file'];
  967.             }
  968.         }
  969.         if (!isset($list['attribs']|| !isset($list['attribs']['name'])) {
  970.             $unknown $allowignore '<filelist>' '<dir name="*unknown*">';
  971.             $dirname $iscontents '<contents>' $unknown;
  972.         else {
  973.             $dirname '<dir name="' $list['attribs']['name''">';
  974.         }
  975.         $res $this->_stupidSchemaValidate($struc$list$dirname);
  976.         if ($allowignore && $res{
  977.             $this->_pf->getFilelist();
  978.             $fcontents $this->_pf->getContents();
  979.             $filelist = array();
  980.             if (!isset($fcontents['dir']['file'][0])) {
  981.                 $fcontents['dir']['file'= array($fcontents['dir']['file']);
  982.             }
  983.             foreach ($fcontents['dir']['file'as $file{
  984.                 $filelist[$file['attribs']['name']] = true;
  985.             }
  986.             if (isset($list['install'])) {
  987.                 if (!isset($list['install'][0])) {
  988.                     $list['install'= array($list['install']);
  989.                 }
  990.                 foreach ($list['install'as $file{
  991.                     if (!isset($filelist[$file['attribs']['name']])) {
  992.                         $this->_notInContents($file['attribs']['name']'install');
  993.                     }
  994.                 }
  995.             }
  996.             if (isset($list['ignore'])) {
  997.                 if (!isset($list['ignore'][0])) {
  998.                     $list['ignore'= array($list['ignore']);
  999.                 }
  1000.                 foreach ($list['ignore'as $file{
  1001.                     if (!isset($filelist[$file['attribs']['name']])) {
  1002.                         $this->_notInContents($file['attribs']['name']'ignore');
  1003.                     }
  1004.                 }
  1005.             }
  1006.         }
  1007.         if (!$allowignore && isset($list['file'])) {
  1008.             if (!isset($list['file'][0])) {
  1009.                 // single file
  1010.                 $list['file'= array($list['file']);
  1011.             }
  1012.             foreach ($list['file'as $i => $file)
  1013.             {
  1014.                 if (isset($file['attribs']&& isset($file['attribs']['name']&&
  1015.                       $file['attribs']['name']{0== '.' &&
  1016.                         $file['attribs']['name']{1== '/'{
  1017.                     // name is something like "./doc/whatever.txt"
  1018.                     $this->_invalidFileName($file['attribs']['name']);
  1019.                 }
  1020.                 if (isset($file['attribs']&& isset($file['attribs']['role'])) {
  1021.                     if (!$this->_validateRole($file['attribs']['role'])) {
  1022.                         if (isset($this->_packageInfo['usesrole'])) {
  1023.                             $roles $this->_packageInfo['usesrole'];
  1024.                             if (!isset($roles[0])) {
  1025.                                 $roles = array($roles);
  1026.                             }
  1027.                             foreach ($roles as $role{
  1028.                                 if ($role['role'$file['attribs']['role']{
  1029.                                     $msg 'This package contains role "%role%" and requires ' .
  1030.                                         'package "%package%" to be used';
  1031.                                     if (isset($role['uri'])) {
  1032.                                         $params = array('role' => $role['role'],
  1033.                                             'package' => $role['uri']);
  1034.                                     else {
  1035.                                         $params = array('role' => $role['role'],
  1036.                                             'package' => $this->_pf->_registry->
  1037.                                             parsedPackageNameToString(array('package' =>
  1038.                                                 $role['package']'channel' => $role['channel']),
  1039.                                                 true));
  1040.                                     }
  1041.                                     $this->_stack->push('_mustInstallRole''error'$params$msg);
  1042.                                 }
  1043.                             }
  1044.                         }
  1045.                         $this->_invalidFileRole($file['attribs']['name'],
  1046.                             $dirname$file['attribs']['role']);
  1047.                     }
  1048.                 }
  1049.                 if (!isset($file['attribs'])) {
  1050.                     continue;
  1051.                 }
  1052.                 $save $file['attribs'];
  1053.                 if ($dirs{
  1054.                     $save['name'$dirs '/' $save['name'];
  1055.                 }
  1056.                 unset($file['attribs']);
  1057.                 if (count($file&& $this->_curState != PEAR_VALIDATE_DOWNLOADING// has tasks
  1058.                     foreach ($file as $task => $value{
  1059.                         if ($tagClass $this->_pf->getTask($task)) {
  1060.                             if (!is_array($value|| !isset($value[0])) {
  1061.                                 $value = array($value);
  1062.                             }
  1063.                             foreach ($value as $v{
  1064.                                 $ret call_user_func(array($tagClass'validateXml'),
  1065.                                     $this->_pf$v$this->_pf->_config$save);
  1066.                                 if (is_array($ret)) {
  1067.                                     $this->_invalidTask($task$ret@$save['name']);
  1068.                                 }
  1069.                             }
  1070.                         else {
  1071.                             if (isset($this->_packageInfo['usestask'])) {
  1072.                                 $roles $this->_packageInfo['usestask'];
  1073.                                 if (!isset($roles[0])) {
  1074.                                     $roles = array($roles);
  1075.                                 }
  1076.                                 foreach ($roles as $role{
  1077.                                     if ($role['task'$task{
  1078.                                         $msg 'This package contains task "%task%" and requires ' .
  1079.                                             'package "%package%" to be used';
  1080.                                         if (isset($role['uri'])) {
  1081.                                             $params = array('task' => $role['task'],
  1082.                                                 'package' => $role['uri']);
  1083.                                         else {
  1084.                                             $params = array('task' => $role['task'],
  1085.                                                 'package' => $this->_pf->_registry->
  1086.                                                 parsedPackageNameToString(array('package' =>
  1087.                                                     $role['package']'channel' => $role['channel']),
  1088.                                                     true));
  1089.                                         }
  1090.                                         $this->_stack->push('_mustInstallTask''error',
  1091.                                             $params$msg);
  1092.                                     }
  1093.                                 }
  1094.                             }
  1095.                             $this->_unknownTask($task$save['name']);
  1096.                         }
  1097.                     }
  1098.                 }
  1099.             }
  1100.         }
  1101.         if (isset($list['ignore'])) {
  1102.             if (!$allowignore{
  1103.                 $this->_ignoreNotAllowed('ignore');
  1104.             }
  1105.         }
  1106.         if (isset($list['install'])) {
  1107.             if (!$allowignore{
  1108.                 $this->_ignoreNotAllowed('install');
  1109.             }
  1110.         }
  1111.         if (isset($list['file'])) {
  1112.             if ($allowignore{
  1113.                 $this->_fileNotAllowed('file');
  1114.             }
  1115.         }
  1116.         if (isset($list['dir'])) {
  1117.             if ($allowignore{
  1118.                 $this->_fileNotAllowed('dir');
  1119.             else {
  1120.                 if (!isset($list['dir'][0])) {
  1121.                     $list['dir'= array($list['dir']);
  1122.                 }
  1123.                 foreach ($list['dir'as $dir{
  1124.                     if (isset($dir['attribs']&& isset($dir['attribs']['name'])) {
  1125.                         if ($dir['attribs']['name'== '/' ||
  1126.                               !isset($this->_packageInfo['contents']['dir']['dir'])) {
  1127.                             // always use nothing if the filelist has already been flattened
  1128.                             $newdirs '';
  1129.                         elseif ($dirs == ''{
  1130.                             $newdirs $dir['attribs']['name'];
  1131.                         else {
  1132.                             $newdirs $dirs '/' $dir['attribs']['name'];
  1133.                         }
  1134.                     else {
  1135.                         $newdirs $dirs;
  1136.                     }
  1137.                     $this->_validateFilelist($dir$allowignore$newdirs);
  1138.                 }
  1139.             }
  1140.         }
  1141.     }
  1142.  
  1143.     function _validateRelease()
  1144.     {
  1145.         if (isset($this->_packageInfo['phprelease'])) {
  1146.             $release 'phprelease';
  1147.             if (isset($this->_packageInfo['providesextension'])) {
  1148.                 $this->_cannotProvideExtension($release);
  1149.             }
  1150.             if (isset($this->_packageInfo['srcpackage']|| isset($this->_packageInfo['srcuri'])) {
  1151.                 $this->_cannotHaveSrcpackage($release);
  1152.             }
  1153.             $releases $this->_packageInfo['phprelease'];
  1154.             if (!is_array($releases)) {
  1155.                 return true;
  1156.             }
  1157.             if (!isset($releases[0])) {
  1158.                 $releases = array($releases);
  1159.             }
  1160.             foreach ($releases as $rel{
  1161.                 $this->_stupidSchemaValidate(array(
  1162.                     '*installconditions',
  1163.                     '*filelist',
  1164.                 )$rel'<phprelease>');
  1165.             }
  1166.         }
  1167.         if (isset($this->_packageInfo['extsrcrelease'])) {
  1168.             $release 'extsrcrelease';
  1169.             if (!isset($this->_packageInfo['providesextension'])) {
  1170.                 $this->_mustProvideExtension($release);
  1171.             }
  1172.             if (isset($this->_packageInfo['srcpackage']|| isset($this->_packageInfo['srcuri'])) {
  1173.                 $this->_cannotHaveSrcpackage($release);
  1174.             }
  1175.             $releases $this->_packageInfo['extsrcrelease'];
  1176.             if (!is_array($releases)) {
  1177.                 return true;
  1178.             }
  1179.             if (!isset($releases[0])) {
  1180.                 $releases = array($releases);
  1181.             }
  1182.             foreach ($releases as $rel{
  1183.                 $this->_stupidSchemaValidate(array(
  1184.                     '*installconditions',
  1185.                     '*configureoption->name->prompt->?default',
  1186.                     '*binarypackage',
  1187.                     '*filelist',
  1188.                 )$rel'<extsrcrelease>');
  1189.                 if (isset($rel['binarypackage'])) {
  1190.                     if (!is_array($rel['binarypackage']|| !isset($rel['binarypackage'][0])) {
  1191.                         $rel['binarypackage'= array($rel['binarypackage']);
  1192.                     }
  1193.                     foreach ($rel['binarypackage'as $bin{
  1194.                         if (!is_string($bin)) {
  1195.                             $this->_binaryPackageMustBePackagename();
  1196.                         }
  1197.                     }
  1198.                 }
  1199.             }
  1200.         }
  1201.         if (isset($this->_packageInfo['extbinrelease'])) {
  1202.             $release 'extbinrelease';
  1203.             if (!isset($this->_packageInfo['providesextension'])) {
  1204.                 $this->_mustProvideExtension($release);
  1205.             }
  1206.             if (isset($this->_packageInfo['channel']&&
  1207.                   !isset($this->_packageInfo['srcpackage'])) {
  1208.                 $this->_mustSrcPackage($release);
  1209.             }
  1210.             if (isset($this->_packageInfo['uri']&& !isset($this->_packageInfo['srcuri'])) {
  1211.                 $this->_mustSrcuri($release);
  1212.             }
  1213.             $releases $this->_packageInfo['extbinrelease'];
  1214.             if (!is_array($releases)) {
  1215.                 return true;
  1216.             }
  1217.             if (!isset($releases[0])) {
  1218.                 $releases = array($releases);
  1219.             }
  1220.             foreach ($releases as $rel{
  1221.                 $this->_stupidSchemaValidate(array(
  1222.                     '*installconditions',
  1223.                     '*filelist',
  1224.                 )$rel'<extbinrelease>');
  1225.             }
  1226.         }
  1227.         if (isset($this->_packageInfo['bundle'])) {
  1228.             $release 'bundle';
  1229.             if (isset($this->_packageInfo['providesextension'])) {
  1230.                 $this->_cannotProvideExtension($release);
  1231.             }
  1232.             if (isset($this->_packageInfo['srcpackage']|| isset($this->_packageInfo['srcuri'])) {
  1233.                 $this->_cannotHaveSrcpackage($release);
  1234.             }
  1235.             $releases $this->_packageInfo['bundle'];
  1236.             if (!is_array($releases|| !isset($releases[0])) {
  1237.                 $releases = array($releases);
  1238.             }
  1239.             foreach ($releases as $rel{
  1240.                 $this->_stupidSchemaValidate(array(
  1241.                     '*installconditions',
  1242.                     '*filelist',
  1243.                 )$rel'<bundle>');
  1244.             }
  1245.         }
  1246.         foreach ($releases as $rel{
  1247.             if (is_array($rel&& array_key_exists('installconditions'$rel)) {
  1248.                 $this->_validateInstallConditions($rel['installconditions'],
  1249.                     "<$release><installconditions>");
  1250.             }
  1251.             if (is_array($rel&& array_key_exists('filelist'$rel)) {
  1252.                 if ($rel['filelist']{
  1253.                     
  1254.                     $this->_validateFilelist($rel['filelist']true);
  1255.                 }
  1256.             }
  1257.         }
  1258.     }
  1259.  
  1260.     /**
  1261.      * This is here to allow role extension through plugins
  1262.      * @param string 
  1263.      */
  1264.     function _validateRole($role)
  1265.     {
  1266.         return in_array($rolePEAR_Installer_Role::getValidRoles($this->_pf->getPackageType()));
  1267.     }
  1268.  
  1269.     function _invalidTagOrder($oktags$actual$root)
  1270.     {
  1271.         $this->_stack->push(__FUNCTION__'error',
  1272.             array('oktags' => $oktags'actual' => $actual'root' => $root),
  1273.             'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"');
  1274.     }
  1275.  
  1276.     function _ignoreNotAllowed($type)
  1277.     {
  1278.         $this->_stack->push(__FUNCTION__'error'array('type' => $type),
  1279.             '<%type%> is not allowed inside global <contents>, only inside ' .
  1280.             '<phprelease>/<extbinrelease>, use <dir> and <file> only');
  1281.     }
  1282.  
  1283.     function _fileNotAllowed($type)
  1284.     {
  1285.         $this->_stack->push(__FUNCTION__'error'array('type' => $type),
  1286.             '<%type%> is not allowed inside release <filelist>, only inside ' .
  1287.             '<contents>, use <ignore> and <install> only');
  1288.     }
  1289.  
  1290.     function _tagMissingAttribute($tag$attr$context)
  1291.     {
  1292.         $this->_stack->push(__FUNCTION__'error'array('tag' => $tag,
  1293.             'attribute' => $attr'context' => $context),
  1294.             'tag <%tag%> in context "%context%" has no attribute "%attribute%"');
  1295.     }
  1296.  
  1297.     function _tagHasNoAttribs($tag$context)
  1298.     {
  1299.         $this->_stack->push(__FUNCTION__'error'array('tag' => $tag,
  1300.             'context' => $context),
  1301.             'tag <%tag%> has no attributes in context "%context%"');
  1302.     }
  1303.  
  1304.     function _invalidInternalStructure()
  1305.     {
  1306.         $this->_stack->push(__FUNCTION__'exception'array(),
  1307.             'internal array was not generated by compatible parser, or extreme parser error, cannot continue');
  1308.     }
  1309.  
  1310.     function _invalidFileRole($file$dir$role)
  1311.     {
  1312.         $this->_stack->push(__FUNCTION__'error'array(
  1313.             'file' => $file'dir' => $dir'role' => $role,
  1314.             'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())),
  1315.             'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%');
  1316.     }
  1317.  
  1318.     function _invalidFileName($file$dir)
  1319.     {
  1320.         $this->_stack->push(__FUNCTION__'error'array(
  1321.             'file' => $file),
  1322.             'File "%file%" cannot begin with "."');
  1323.     }
  1324.  
  1325.     function _filelistCannotContainFile($filelist)
  1326.     {
  1327.         $this->_stack->push(__FUNCTION__'error'array('tag' => $filelist),
  1328.             '<%tag%> can only contain <dir>, contains <file>.  Use ' .
  1329.             '<dir name="/"> as the first dir element');
  1330.     }
  1331.  
  1332.     function _filelistMustContainDir($filelist)
  1333.     {
  1334.         $this->_stack->push(__FUNCTION__'error'array('tag' => $filelist),
  1335.             '<%tag%> must contain <dir>.  Use <dir name="/"> as the ' .
  1336.             'first dir element');
  1337.     }
  1338.  
  1339.     function _tagCannotBeEmpty($tag)
  1340.     {
  1341.         $this->_stack->push(__FUNCTION__'error'array('tag' => $tag),
  1342.             '<%tag%> cannot be empty (<%tag%/>)');
  1343.     }
  1344.  
  1345.     function _UrlOrChannel($type$name)
  1346.     {
  1347.         $this->_stack->push(__FUNCTION__'error'array('type' => $type,
  1348.             'name' => $name),
  1349.             'Required dependency <%type%> "%name%" can have either url OR ' .
  1350.             'channel attributes, and not both');
  1351.     }
  1352.  
  1353.     function _NoChannel($type$name)
  1354.     {
  1355.         $this->_stack->push(__FUNCTION__'error'array('type' => $type,
  1356.             'name' => $name),
  1357.             'Required dependency <%type%> "%name%" must have either url OR ' .
  1358.             'channel attributes');
  1359.     }
  1360.  
  1361.     function _UrlOrChannelGroup($type$name$group)
  1362.     {
  1363.         $this->_stack->push(__FUNCTION__'error'array('type' => $type,
  1364.             'name' => $name'group' => $group),
  1365.             'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .
  1366.             'channel attributes, and not both');
  1367.     }
  1368.  
  1369.     function _NoChannelGroup($type$name$group)
  1370.     {
  1371.         $this->_stack->push(__FUNCTION__'error'array('type' => $type,
  1372.             'name' => $name'group' => $group),
  1373.             'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .
  1374.             'channel attributes');
  1375.     }
  1376.  
  1377.     function _unknownChannel($channel)
  1378.     {
  1379.         $this->_stack->push(__FUNCTION__'error'array('channel' => $channel),
  1380.             'Unknown channel "%channel%"');
  1381.     }
  1382.  
  1383.     function _noPackageVersion()
  1384.     {
  1385.         $this->_stack->push(__FUNCTION__'error'array(),
  1386.             'package.xml <package> tag has no version attribute, or version is not 2.0');
  1387.     }
  1388.  
  1389.     function _NoBundledPackages()
  1390.     {
  1391.         $this->_stack->push(__FUNCTION__'error'array(),
  1392.             'No <bundledpackage> tag was found in <contents>, required for bundle packages');
  1393.     }
  1394.  
  1395.     function _AtLeast2BundledPackages()
  1396.     {
  1397.         $this->_stack->push(__FUNCTION__'error'array(),
  1398.             'At least 2 packages must be bundled in a bundle package');
  1399.     }
  1400.  
  1401.     function _ChannelOrUri($name)
  1402.     {
  1403.         $this->_stack->push(__FUNCTION__'error'array('name' => $name),
  1404.             'Bundled package "%name%" can have either a uri or a channel, not both');
  1405.     }
  1406.  
  1407.     function _noChildTag($child$tag)
  1408.     {
  1409.         $this->_stack->push(__FUNCTION__'error'array('child' => $child'tag' => $tag),
  1410.             'Tag <%tag%> is missing child tag <%child%>');
  1411.     }
  1412.  
  1413.     function _invalidVersion($type$value)
  1414.     {
  1415.         $this->_stack->push(__FUNCTION__'error'array('type' => $type'value' => $value),
  1416.             'Version type <%type%> is not a valid version (%value%)');
  1417.     }
  1418.  
  1419.     function _invalidState($type$value)
  1420.     {
  1421.         $states = array('stable''beta''alpha''devel');
  1422.         if ($type != 'api'{
  1423.             $states['snapshot';
  1424.         }
  1425.         if (strtolower($value== 'rc'{
  1426.             $this->_stack->push(__FUNCTION__'error',
  1427.                 array('version' => $this->_packageInfo['version']['release']),
  1428.                 'RC is not a state, it is a version postfix, try %version%RC1, stability beta');
  1429.         }
  1430.         $this->_stack->push(__FUNCTION__'error'array('type' => $type'value' => $value,
  1431.             'types' => $states),
  1432.             'Stability type <%type%> is not a valid stability (%value%), must be one of ' .
  1433.             '%types%');
  1434.     }
  1435.  
  1436.     function _invalidTask($task$ret$file)
  1437.     {
  1438.         switch ($ret[0]{
  1439.             case PEAR_TASK_ERROR_MISSING_ATTRIB :
  1440.                 $info = array('attrib' => $ret[1]'task' => $task'file' => $file);
  1441.                 $msg 'task <%task%> is missing attribute "%attrib%" in file %file%';
  1442.             break;
  1443.             case PEAR_TASK_ERROR_NOATTRIBS :
  1444.                 $info = array('task' => $task'file' => $file);
  1445.                 $msg 'task <%task%> has no attributes in file %file%';
  1446.             break;
  1447.             case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :
  1448.                 $info = array('attrib' => $ret[1]'values' => $ret[3],
  1449.                     'was' => $ret[2]'task' => $task'file' => $file);
  1450.                 $msg 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '.
  1451.                     'in file %file%, expecting one of "%values%"';
  1452.             break;
  1453.             case PEAR_TASK_ERROR_INVALID :
  1454.                 $info = array('reason' => $ret[1]'task' => $task'file' => $file);
  1455.                 $msg 'task <%task%> in file %file% is invalid because of "%reason%"';
  1456.             break;
  1457.         }
  1458.         $this->_stack->push(__FUNCTION__'error'$info$msg);
  1459.     }
  1460.  
  1461.     function _unknownTask($task$file)
  1462.     {
  1463.         $this->_stack->push(__FUNCTION__'error'array('task' => $task'file' => $file),
  1464.             'Unknown task "%task%" passed in file <file name="%file%">');
  1465.     }
  1466.  
  1467.     function _subpackageCannotProvideExtension($name)
  1468.     {
  1469.         $this->_stack->push(__FUNCTION__'error'array('name' => $name),
  1470.             'Subpackage dependency "%name%" cannot use <providesextension>, ' .
  1471.             'only package dependencies can use this tag');
  1472.     }
  1473.  
  1474.     function _subpackagesCannotConflict($name)
  1475.     {
  1476.         $this->_stack->push(__FUNCTION__'error'array('name' => $name),
  1477.             'Subpackage dependency "%name%" cannot use <conflicts/>, ' .
  1478.             'only package dependencies can use this tag');
  1479.     }
  1480.  
  1481.     function _cannotProvideExtension($release)
  1482.     {
  1483.         $this->_stack->push(__FUNCTION__'error'array('release' => $release),
  1484.             '<%release%> packages cannot use <providesextension>, only extbinrelease and extsrcrelease can provide a PHP extension');
  1485.     }
  1486.  
  1487.     function _mustProvideExtension($release)
  1488.     {
  1489.         $this->_stack->push(__FUNCTION__'error'array('release' => $release),
  1490.             '<%release%> packages must use <providesextension> to indicate which PHP extension is provided');
  1491.     }
  1492.  
  1493.     function _cannotHaveSrcpackage($release)
  1494.     {
  1495.         $this->_stack->push(__FUNCTION__'error'array('release' => $release),
  1496.             '<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag');
  1497.     }
  1498.  
  1499.     function _mustSrcPackage($release)
  1500.     {
  1501.         $this->_stack->push(__FUNCTION__'error'array('release' => $release),
  1502.             '<extbinrelease> packages must specify a source code package with <srcpackage>');
  1503.     }
  1504.  
  1505.     function _mustSrcuri($release)
  1506.     {
  1507.         $this->_stack->push(__FUNCTION__'error'array('release' => $release),
  1508.             '<extbinrelease> packages must specify a source code package with <srcuri>');
  1509.     }
  1510.  
  1511.     function _uriDepsCannotHaveVersioning($type)
  1512.     {
  1513.         $this->_stack->push(__FUNCTION__'error'array('type' => $type),
  1514.             '%type%: dependencies with a <uri> tag cannot have any versioning information');
  1515.     }
  1516.  
  1517.     function _conflictingDepsCannotHaveVersioning($type)
  1518.     {
  1519.         $this->_stack->push(__FUNCTION__'error'array('type' => $type),
  1520.             '%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' .
  1521.             'exclude specific versions of a dependency');
  1522.     }
  1523.  
  1524.     function _DepchannelCannotBeUri($type)
  1525.     {
  1526.         $this->_stack->push(__FUNCTION__'error'array('type' => $type),
  1527.             '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .
  1528.             'dependencies only');
  1529.     }
  1530.  
  1531.     function _bundledPackagesMustBeFilename()
  1532.     {
  1533.         $this->_stack->push(__FUNCTION__'error'array(),
  1534.             '<bundledpackage> tags must contain only the filename of a package release ' .
  1535.             'in the bundle');
  1536.     }
  1537.  
  1538.     function _binaryPackageMustBePackagename()
  1539.     {
  1540.         $this->_stack->push(__FUNCTION__'error'array(),
  1541.             '<binarypackage> tags must contain the name of a package that is ' .
  1542.             'a compiled version of this extsrc package');
  1543.     }
  1544.  
  1545.     function _fileNotFound($file)
  1546.     {
  1547.         $this->_stack->push(__FUNCTION__'error'array('file' => $file),
  1548.             'File "%file%" in package.xml does not exist');
  1549.     }
  1550.  
  1551.     function _notInContents($file$tag)
  1552.     {
  1553.         $this->_stack->push(__FUNCTION__'error'array('file' => $file'tag' => $tag),
  1554.             '<%tag% name="%file%"> is invalid, file is not in <contents>');
  1555.     }
  1556.  
  1557.     function _cannotValidateNoPathSet()
  1558.     {
  1559.         $this->_stack->push(__FUNCTION__'error'array(),
  1560.             'Cannot validate files, no path to package file is set (use setPackageFile())');
  1561.     }
  1562.  
  1563.     function _usesroletaskMustHaveChannelOrUri($role$tag)
  1564.     {
  1565.         $this->_stack->push(__FUNCTION__'error'array('role' => $role'tag' => $tag),
  1566.             '<%tag%> must contain either <uri>, or <channel> and <package>');
  1567.     }
  1568.  
  1569.     function _usesroletaskMustHavePackage($role$tag)
  1570.     {
  1571.         $this->_stack->push(__FUNCTION__'error'array('role' => $role'tag' => $tag),
  1572.             '<%tag%> must contain <package>');
  1573.     }
  1574.  
  1575.     function _usesroletaskMustHaveRoleTask($tag$type)
  1576.     {
  1577.         $this->_stack->push(__FUNCTION__'error'array('tag' => $tag'type' => $type),
  1578.             '<%tag%> must contain <%type%> defining the %type% to be used');
  1579.     }
  1580.  
  1581.     function _cannotConflictWithAllOs($type)
  1582.     {
  1583.         $this->_stack->push(__FUNCTION__'error'array('tag' => $tag),
  1584.             '%tag% cannot conflict with all OSes');
  1585.     }
  1586.  
  1587.     function _invalidDepGroupName($name)
  1588.     {
  1589.         $this->_stack->push(__FUNCTION__'error'array('group' => $name),
  1590.             'Invalid dependency group name "%name%"');
  1591.     }
  1592.  
  1593.     function _analyzeBundledPackages()
  1594.     {
  1595.         if (!$this->_isValid{
  1596.             return false;
  1597.         }
  1598.         if (!$this->_pf->getPackageType(== 'bundle'{
  1599.             return false;
  1600.         }
  1601.         if (!isset($this->_pf->_packageFile)) {
  1602.             return false;
  1603.         }
  1604.         $dir_prefix dirname($this->_pf->_packageFile);
  1605.         $log = isset($this->_pf->_logger? array(&$this->_pf->_logger'log':
  1606.             array('PEAR_Common''log');
  1607.         $info $this->_pf->getContents();
  1608.         $info $info['bundledpackage'];
  1609.         if (!is_array($info)) {
  1610.             $info = array($info);
  1611.         }
  1612.         $pkg &new PEAR_PackageFile($this->_pf->_config);
  1613.         foreach ($info as $package{
  1614.             if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) {
  1615.                 $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package);
  1616.                 $this->_isValid = 0;
  1617.                 continue;
  1618.             }
  1619.             call_user_func_array($logarray(1"Analyzing bundled package $package"));
  1620.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1621.             $ret $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package,
  1622.                 PEAR_VALIDATE_NORMAL);
  1623.             PEAR::popErrorHandling();
  1624.             if (PEAR::isError($ret)) {
  1625.                 call_user_func_array($logarray(0"ERROR: package $package is not a valid " .
  1626.                     'package'));
  1627.                 $inf $ret->getUserInfo();
  1628.                 if (is_array($inf)) {
  1629.                     foreach ($inf as $err{
  1630.                         call_user_func_array($logarray(1$err['message']));
  1631.                     }
  1632.                 }
  1633.                 return false;
  1634.             }
  1635.         }
  1636.         return true;
  1637.     }
  1638.  
  1639.     function _analyzePhpFiles()
  1640.     {
  1641.         if (!$this->_isValid{
  1642.             return false;
  1643.         }
  1644.         if (!isset($this->_pf->_packageFile)) {
  1645.             $this->_cannotValidateNoPathSet();
  1646.             return false;
  1647.         }
  1648.         $dir_prefix dirname($this->_pf->_packageFile);
  1649.         $common = new PEAR_Common;
  1650.         $log = isset($this->_pf->_logger? array(&$this->_pf->_logger'log':
  1651.             array(&$common'log');
  1652.         $info $this->_pf->getContents();
  1653.         $info $info['dir']['file'];
  1654.         if (isset($info['attribs'])) {
  1655.             $info = array($info);
  1656.         }
  1657.         $provides = array();
  1658.         foreach ($info as $fa{
  1659.             $fa $fa['attribs'];
  1660.             $file $fa['name'];
  1661.             if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
  1662.                 $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file);
  1663.                 $this->_isValid = 0;
  1664.                 continue;
  1665.             }
  1666.             if (in_array($fa['role']PEAR_Installer_Role::getPhpRoles()) && $dir_prefix{
  1667.                 call_user_func_array($logarray(1"Analyzing $file"));
  1668.                 $srcinfo $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
  1669.                 if ($srcinfo{
  1670.                     $provides array_merge($provides$this->_buildProvidesArray($srcinfo));
  1671.                 }
  1672.             }
  1673.         }
  1674.         $this->_packageName = $pn $this->_pf->getPackage();
  1675.         $pnl strlen($pn);
  1676.         foreach ($provides as $key => $what{
  1677.             if (isset($what['explicit']|| !$what{
  1678.                 // skip conformance checks if the provides entry is
  1679.                 // specified in the package.xml file
  1680.                 continue;
  1681.             }
  1682.             extract($what);
  1683.             if ($type == 'class'{
  1684.                 if (!strncasecmp($name$pn$pnl)) {
  1685.                     continue;
  1686.                 }
  1687.                 $this->_stack->push(__FUNCTION__'warning',
  1688.                     array('file' => $file'type' => $type'name' => $name'package' => $pn),
  1689.                     'in %file%: %type% "%name%" not prefixed with package name "%package%"');
  1690.             elseif ($type == 'function'{
  1691.                 if (strstr($name'::'|| !strncasecmp($name$pn$pnl)) {
  1692.                     continue;
  1693.                 }
  1694.                 $this->_stack->push(__FUNCTION__'warning',
  1695.                     array('file' => $file'type' => $type'name' => $name'package' => $pn),
  1696.                     'in %file%: %type% "%name%" not prefixed with package name "%package%"');
  1697.             }
  1698.         }
  1699.         return $this->_isValid;
  1700.     }
  1701.  
  1702.     /**
  1703.      * Analyze the source code of the given PHP file
  1704.      *
  1705.      * @param  string Filename of the PHP file
  1706.      * @param  boolean whether to analyze $file as the file contents
  1707.      * @return mixed 
  1708.      */
  1709.     function analyzeSourceCode($file$string = false)
  1710.     {
  1711.         if (!function_exists("token_get_all")) {
  1712.             return false;
  1713.         }
  1714.         if (!defined('T_DOC_COMMENT')) {
  1715.             define('T_DOC_COMMENT'T_COMMENT);
  1716.         }
  1717.         if (!defined('T_INTERFACE')) {
  1718.             define('T_INTERFACE'-1);
  1719.         }
  1720.         if (!defined('T_IMPLEMENTS')) {
  1721.             define('T_IMPLEMENTS'-1);
  1722.         }
  1723.         if ($string{
  1724.             $contents $file;
  1725.         else {
  1726.             if (!$fp @fopen($file"r")) {
  1727.                 return false;
  1728.             }
  1729.             if (function_exists('file_get_contents')) {
  1730.                 fclose($fp);
  1731.                 $contents file_get_contents($file);
  1732.             else {
  1733.                 $contents @fread($fpfilesize($file));
  1734.                 fclose($fp);
  1735.             }
  1736.         }
  1737.         $tokens token_get_all($contents);
  1738. /*
  1739.         for ($i = 0; $i < sizeof($tokens); $i++) {
  1740.             @list($token, $data) = $tokens[$i];
  1741.             if (is_string($token)) {
  1742.                 var_dump($token);
  1743.             } else {
  1744.                 print token_name($token) . ' ';
  1745.                 var_dump(rtrim($data));
  1746.             }
  1747.         }
  1748. */
  1749.         $look_for = 0;
  1750.         $paren_level = 0;
  1751.         $bracket_level = 0;
  1752.         $brace_level = 0;
  1753.         $lastphpdoc '';
  1754.         $current_class '';
  1755.         $current_interface '';
  1756.         $current_class_level = -1;
  1757.         $current_function '';
  1758.         $current_function_level = -1;
  1759.         $declared_classes = array();
  1760.         $declared_interfaces = array();
  1761.         $declared_functions = array();
  1762.         $declared_methods = array();
  1763.         $used_classes = array();
  1764.         $used_functions = array();
  1765.         $extends = array();
  1766.         $implements = array();
  1767.         $nodeps = array();
  1768.         $inquote = false;
  1769.         $interface = false;
  1770.         for ($i = 0; $i sizeof($tokens)$i++{
  1771.             if (is_array($tokens[$i])) {
  1772.                 list($token$data$tokens[$i];
  1773.             else {
  1774.                 $token $tokens[$i];
  1775.                 $data '';
  1776.             }
  1777.             if ($inquote{
  1778.                 if ($token != '"' && $token != T_END_HEREDOC{
  1779.                     continue;
  1780.                 else {
  1781.                     $inquote = false;
  1782.                     continue;
  1783.                 }
  1784.             }
  1785.             switch ($token{
  1786.                 case T_WHITESPACE :
  1787.                     continue;
  1788.                 case ';':
  1789.                     if ($interface{
  1790.                         $current_function '';
  1791.                         $current_function_level = -1;
  1792.                     }
  1793.                     break;
  1794.                 case '"':
  1795.                 case T_START_HEREDOC:
  1796.                     $inquote = true;
  1797.                     break;
  1798.                 case T_CURLY_OPEN:
  1799.                 case T_DOLLAR_OPEN_CURLY_BRACES:
  1800.                 case '{'$brace_level++; continue 2;
  1801.                 case '}':
  1802.                     $brace_level--;
  1803.                     if ($current_class_level == $brace_level{
  1804.                         $current_class '';
  1805.                         $current_class_level = -1;
  1806.                     }
  1807.                     if ($current_function_level == $brace_level{
  1808.                         $current_function '';
  1809.                         $current_function_level = -1;
  1810.                     }
  1811.                     continue 2;
  1812.                 case '['$bracket_level++; continue 2;
  1813.                 case ']'$bracket_level--; continue 2;
  1814.                 case '('$paren_level++;   continue 2;
  1815.                 case ')'$paren_level--;   continue 2;
  1816.                 case T_INTERFACE:
  1817.                     $interface = true;
  1818.                 case T_CLASS:
  1819.                     if (($current_class_level != -1|| ($current_function_level != -1)) {
  1820.                         $this->_stack->push(__FUNCTION__'error'array('file' => $file),
  1821.                         'Parser error: invalid PHP found in file "%file%"');
  1822.                         return false;
  1823.                     }
  1824.                 case T_FUNCTION:
  1825.                 case T_NEW:
  1826.                 case T_EXTENDS:
  1827.                 case T_IMPLEMENTS:
  1828.                     $look_for $token;
  1829.                     continue 2;
  1830.                 case T_STRING:
  1831.                     if (version_compare(zend_version()'2.0''<')) {
  1832.                         if (in_array(strtolower($data),
  1833.                             array('public''private''protected''abstract',
  1834.                                   'interface''implements''throw'
  1835.                                  )) {
  1836.                             $this->_stack->push(__FUNCTION__'warning'array(
  1837.                                 'file' => $file),
  1838.                                 'Error, PHP5 token encountered in %file%,' .
  1839.                                 ' analysis should be in PHP5');
  1840.                         }
  1841.                     }
  1842.                     if ($look_for == T_CLASS{
  1843.                         $current_class $data;
  1844.                         $current_class_level $brace_level;
  1845.                         $declared_classes[$current_class;
  1846.                     elseif ($look_for == T_INTERFACE{
  1847.                         $current_interface $data;
  1848.                         $current_class_level $brace_level;
  1849.                         $declared_interfaces[$current_interface;
  1850.                     elseif ($look_for == T_IMPLEMENTS{
  1851.                         $implements[$current_class$data;
  1852.                     elseif ($look_for == T_EXTENDS{
  1853.                         $extends[$current_class$data;
  1854.                     elseif ($look_for == T_FUNCTION{
  1855.                         if ($current_class{
  1856.                             $current_function = "$current_class::$data";
  1857.                             $declared_methods[$current_class][$data;
  1858.                         elseif ($current_interface{
  1859.                             $current_function = "$current_interface::$data";
  1860.                             $declared_methods[$current_interface][$data;
  1861.                         else {
  1862.                             $current_function $data;
  1863.                             $declared_functions[$current_function;
  1864.                         }
  1865.                         $current_function_level $brace_level;
  1866.                         $m = array();
  1867.                     elseif ($look_for == T_NEW{
  1868.                         $used_classes[$data= true;
  1869.                     }
  1870.                     $look_for = 0;
  1871.                     continue 2;
  1872.                 case T_VARIABLE:
  1873.                     $look_for = 0;
  1874.                     continue 2;
  1875.                 case T_DOC_COMMENT:
  1876.                 case T_COMMENT:
  1877.                     if (preg_match('!^/\*\*\s!'$data)) {
  1878.                         $lastphpdoc $data;
  1879.                         if (preg_match_all('/@nodep\s+(\S+)/'$lastphpdoc$m)) {
  1880.                             $nodeps array_merge($nodeps$m[1]);
  1881.                         }
  1882.                     }
  1883.                     continue 2;
  1884.                 case T_DOUBLE_COLON:
  1885.                     if (!($tokens[$i - 1][0== T_WHITESPACE || $tokens[$i - 1][0== T_STRING)) {
  1886.                         $this->_stack->push(__FUNCTION__'warning'array('file' => $file),
  1887.                             'Parser error: invalid PHP found in file "%file%"');
  1888.                         return false;
  1889.                     }
  1890.                     $class $tokens[$i - 1][1];
  1891.                     if (strtolower($class!= 'parent'{
  1892.                         $used_classes[$class= true;
  1893.                     }
  1894.                     continue 2;
  1895.             }
  1896.         }
  1897.         return array(
  1898.             "source_file" => $file,
  1899.             "declared_classes" => $declared_classes,
  1900.             "declared_interfaces" => $declared_interfaces,
  1901.             "declared_methods" => $declared_methods,
  1902.             "declared_functions" => $declared_functions,
  1903.             "used_classes" => array_diff(array_keys($used_classes)$nodeps),
  1904.             "inheritance" => $extends,
  1905.             "implements" => $implements,
  1906.             );
  1907.     }
  1908.  
  1909.     /**
  1910.      * Build a "provides" array from data returned by
  1911.      * analyzeSourceCode().  The format of the built array is like
  1912.      * this:
  1913.      *
  1914.      *  array(
  1915.      *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  1916.      *    ...
  1917.      *  )
  1918.      *
  1919.      *
  1920.      * @param array $srcinfo array with information about a source file
  1921.      *  as returned by the analyzeSourceCode() method.
  1922.      *
  1923.      * @return void 
  1924.      *
  1925.      * @access private
  1926.      *
  1927.      */
  1928.     function _buildProvidesArray($srcinfo)
  1929.     {
  1930.         if (!$this->_isValid{
  1931.             return array();
  1932.         }
  1933.         $providesret = array();
  1934.         $file basename($srcinfo['source_file']);
  1935.         $pn $this->_pf->getPackage();
  1936.         $pnl strlen($pn);
  1937.         foreach ($srcinfo['declared_classes'as $class{
  1938.             $key = "class;$class";
  1939.             if (isset($providesret[$key])) {
  1940.                 continue;
  1941.             }
  1942.             $providesret[$key=
  1943.                 array('file'=> $file'type' => 'class''name' => $class);
  1944.             if (isset($srcinfo['inheritance'][$class])) {
  1945.                 $providesret[$key]['extends'=
  1946.                     $srcinfo['inheritance'][$class];
  1947.             }
  1948.         }
  1949.         foreach ($srcinfo['declared_methods'as $class => $methods{
  1950.             foreach ($methods as $method{
  1951.                 $function = "$class::$method";
  1952.                 $key = "function;$function";
  1953.                 if ($method{0== '_' || !strcasecmp($method$class||
  1954.                     isset($providesret[$key])) {
  1955.                     continue;
  1956.                 }
  1957.                 $providesret[$key=
  1958.                     array('file'=> $file'type' => 'function''name' => $function);
  1959.             }
  1960.         }
  1961.  
  1962.         foreach ($srcinfo['declared_functions'as $function{
  1963.             $key = "function;$function";
  1964.             if ($function{0== '_' || isset($providesret[$key])) {
  1965.                 continue;
  1966.             }
  1967.             if (!strstr($function'::'&& strncasecmp($function$pn$pnl)) {
  1968.                 $warnings["in1 " $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  1969.             }
  1970.             $providesret[$key=
  1971.                 array('file'=> $file'type' => 'function''name' => $function);
  1972.         }
  1973.         return $providesret;
  1974.     }
  1975. }
  1976. ?>

Documentation generated on Mon, 11 Mar 2019 14:10:56 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.