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

Documentation generated on Mon, 11 Mar 2019 15:00:28 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.