Rev 94 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/*** PEAR_PackageFile_v2, package.xml version 2.0, read/write version** PHP versions 4 and 5** @category pear* @package PEAR* @author Greg Beaver <cellog@php.net>* @copyright 1997-2009 The Authors* @license http://opensource.org/licenses/bsd-license.php New BSD License* @link http://pear.php.net/package/PEAR* @since File available since Release 1.4.0a8*//*** Private validation class used by PEAR_PackageFile_v2 - do not use directly, its* sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller* @category pear* @package PEAR* @author Greg Beaver <cellog@php.net>* @copyright 1997-2009 The Authors* @license http://opensource.org/licenses/bsd-license.php New BSD License* @version Release: 1.10.1* @link http://pear.php.net/package/PEAR* @since Class available since Release 1.4.0a8* @access private*/class PEAR_PackageFile_v2_Validator{/*** @var array*/var $_packageInfo;/*** @var PEAR_PackageFile_v2*/var $_pf;/*** @var PEAR_ErrorStack*/var $_stack;/*** @var int*/var $_isValid = 0;/*** @var int*/var $_filesValid = 0;/*** @var int*/var $_curState = 0;/*** @param PEAR_PackageFile_v2* @param int*/function validate(&$pf, $state = PEAR_VALIDATE_NORMAL){$this->_pf = &$pf;$this->_curState = $state;$this->_packageInfo = $this->_pf->getArray();$this->_isValid = $this->_pf->_isValid;$this->_filesValid = $this->_pf->_filesValid;$this->_stack = &$pf->_stack;$this->_stack->getErrors(true);if (($this->_isValid & $state) == $state) {return true;}if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {return false;}if (!isset($this->_packageInfo['attribs']['version']) ||($this->_packageInfo['attribs']['version'] != '2.0' &&$this->_packageInfo['attribs']['version'] != '2.1')) {$this->_noPackageVersion();}$structure =array('name','channel|uri','*extends', // can't be multiple, but this works fine'summary','description','+lead', // these all need content checks'*developer','*contributor','*helper','date','*time','version','stability','license->?uri->?filesource','notes','contents', //special validation needed'*compatible','dependencies', //special validation needed'*usesrole','*usestask', // reserve these for 1.4.0a1 to implement// this will allow a package.xml to gracefully say it// needs a certain package installed in order to implement a role or task'*providesextension','*srcpackage|*srcuri','+phprelease|+extsrcrelease|+extbinrelease|' .'+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed'*changelog',);$test = $this->_packageInfo;if (isset($test['dependencies']) &&isset($test['dependencies']['required']) &&isset($test['dependencies']['required']['pearinstaller']) &&isset($test['dependencies']['required']['pearinstaller']['min']) &&'1.10.1' != '@package' . '_version@' &&version_compare('1.10.1',$test['dependencies']['required']['pearinstaller']['min'], '<')) {$this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']);return false;}// ignore post-installation array fieldsif (array_key_exists('filelist', $test)) {unset($test['filelist']);}if (array_key_exists('_lastmodified', $test)) {unset($test['_lastmodified']);}if (array_key_exists('#binarypackage', $test)) {unset($test['#binarypackage']);}if (array_key_exists('old', $test)) {unset($test['old']);}if (array_key_exists('_lastversion', $test)) {unset($test['_lastversion']);}if (!$this->_stupidSchemaValidate($structure, $test, '<package>')) {return false;}if (empty($this->_packageInfo['name'])) {$this->_tagCannotBeEmpty('name');}$test = isset($this->_packageInfo['uri']) ? 'uri' :'channel';if (empty($this->_packageInfo[$test])) {$this->_tagCannotBeEmpty($test);}if (is_array($this->_packageInfo['license']) &&(!isset($this->_packageInfo['license']['_content']) ||empty($this->_packageInfo['license']['_content']))) {$this->_tagCannotBeEmpty('license');} elseif (empty($this->_packageInfo['license'])) {$this->_tagCannotBeEmpty('license');}if (empty($this->_packageInfo['summary'])) {$this->_tagCannotBeEmpty('summary');}if (empty($this->_packageInfo['description'])) {$this->_tagCannotBeEmpty('description');}if (empty($this->_packageInfo['date'])) {$this->_tagCannotBeEmpty('date');}if (empty($this->_packageInfo['notes'])) {$this->_tagCannotBeEmpty('notes');}if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) {$this->_tagCannotBeEmpty('time');}if (isset($this->_packageInfo['dependencies'])) {$this->_validateDependencies();}if (isset($this->_packageInfo['compatible'])) {$this->_validateCompatible();}if (!isset($this->_packageInfo['bundle'])) {if (empty($this->_packageInfo['contents'])) {$this->_tagCannotBeEmpty('contents');}if (!isset($this->_packageInfo['contents']['dir'])) {$this->_filelistMustContainDir('contents');return false;}if (isset($this->_packageInfo['contents']['file'])) {$this->_filelistCannotContainFile('contents');return false;}}$this->_validateMaintainers();$this->_validateStabilityVersion();$fail = false;if (array_key_exists('usesrole', $this->_packageInfo)) {$roles = $this->_packageInfo['usesrole'];if (!is_array($roles) || !isset($roles[0])) {$roles = array($roles);}foreach ($roles as $role) {if (!isset($role['role'])) {$this->_usesroletaskMustHaveRoleTask('usesrole', 'role');$fail = true;} else {if (!isset($role['channel'])) {if (!isset($role['uri'])) {$this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole');$fail = true;}} elseif (!isset($role['package'])) {$this->_usesroletaskMustHavePackage($role['role'], 'usesrole');$fail = true;}}}}if (array_key_exists('usestask', $this->_packageInfo)) {$roles = $this->_packageInfo['usestask'];if (!is_array($roles) || !isset($roles[0])) {$roles = array($roles);}foreach ($roles as $role) {if (!isset($role['task'])) {$this->_usesroletaskMustHaveRoleTask('usestask', 'task');$fail = true;} else {if (!isset($role['channel'])) {if (!isset($role['uri'])) {$this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask');$fail = true;}} elseif (!isset($role['package'])) {$this->_usesroletaskMustHavePackage($role['task'], 'usestask');$fail = true;}}}}if ($fail) {return false;}$list = $this->_packageInfo['contents'];if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) {$this->_multipleToplevelDirNotAllowed();return $this->_isValid = 0;}$this->_validateFilelist();$this->_validateRelease();if (!$this->_stack->hasErrors()) {$chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true);if (PEAR::isError($chan)) {$this->_unknownChannel($this->_pf->getChannel());} else {$valpack = $chan->getValidationPackage();// for channel validator packages, always use the default PEAR validator.// otherwise, they can't be installed or packaged$validator = $chan->getValidationObject($this->_pf->getPackage());if (!$validator) {$this->_stack->push(__FUNCTION__, 'error',array('channel' => $chan->getName(),'package' => $this->_pf->getPackage(),'name' => $valpack['_content'],'version' => $valpack['attribs']['version']),'package "%channel%/%package%" cannot be properly validated without ' .'validation package "%channel%/%name%-%version%"');return $this->_isValid = 0;}$validator->setPackageFile($this->_pf);$validator->validate($state);$failures = $validator->getFailures();foreach ($failures['errors'] as $error) {$this->_stack->push(__FUNCTION__, 'error', $error,'Channel validator error: field "%field%" - %reason%');}foreach ($failures['warnings'] as $warning) {$this->_stack->push(__FUNCTION__, 'warning', $warning,'Channel validator warning: field "%field%" - %reason%');}}}$this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error');if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) {if ($this->_pf->getPackageType() == 'bundle') {if ($this->_analyzeBundledPackages()) {$this->_filesValid = $this->_pf->_filesValid = true;} else {$this->_pf->_isValid = $this->_isValid = 0;}} else {if (!$this->_analyzePhpFiles()) {$this->_pf->_isValid = $this->_isValid = 0;} else {$this->_filesValid = $this->_pf->_filesValid = true;}}}if ($this->_isValid) {return $this->_pf->_isValid = $this->_isValid = $state;}return $this->_pf->_isValid = $this->_isValid = 0;}function _stupidSchemaValidate($structure, $xml, $root){if (!is_array($xml)) {$xml = array();}$keys = array_keys($xml);reset($keys);$key = current($keys);while ($key == 'attribs' || $key == '_contents') {$key = next($keys);}$unfoundtags = $optionaltags = array();$ret = true;$mismatch = false;foreach ($structure as $struc) {if ($key) {$tag = $xml[$key];}$test = $this->_processStructure($struc);if (isset($test['choices'])) {$loose = true;foreach ($test['choices'] as $choice) {if ($key == $choice['tag']) {$key = next($keys);while ($key == 'attribs' || $key == '_contents') {$key = next($keys);}$unfoundtags = $optionaltags = array();$mismatch = false;if ($key && $key != $choice['tag'] && isset($choice['multiple'])) {$unfoundtags[] = $choice['tag'];$optionaltags[] = $choice['tag'];if ($key) {$mismatch = true;}}$ret &= $this->_processAttribs($choice, $tag, $root);continue 2;} else {$unfoundtags[] = $choice['tag'];$mismatch = true;}if (!isset($choice['multiple']) || $choice['multiple'] != '*') {$loose = false;} else {$optionaltags[] = $choice['tag'];}}if (!$loose) {$this->_invalidTagOrder($unfoundtags, $key, $root);return false;}} else {if ($key != $test['tag']) {if (isset($test['multiple']) && $test['multiple'] != '*') {$unfoundtags[] = $test['tag'];$this->_invalidTagOrder($unfoundtags, $key, $root);return false;} else {if ($key) {$mismatch = true;}$unfoundtags[] = $test['tag'];$optionaltags[] = $test['tag'];}if (!isset($test['multiple'])) {$this->_invalidTagOrder($unfoundtags, $key, $root);return false;}continue;} else {$unfoundtags = $optionaltags = array();$mismatch = false;}$key = next($keys);while ($key == 'attribs' || $key == '_contents') {$key = next($keys);}if ($key && $key != $test['tag'] && isset($test['multiple'])) {$unfoundtags[] = $test['tag'];$optionaltags[] = $test['tag'];$mismatch = true;}$ret &= $this->_processAttribs($test, $tag, $root);continue;}}if (!$mismatch && count($optionaltags)) {// don't error out on any optional tags$unfoundtags = array_diff($unfoundtags, $optionaltags);}if (count($unfoundtags)) {$this->_invalidTagOrder($unfoundtags, $key, $root);} elseif ($key) {// unknown tags$this->_invalidTagOrder('*no tags allowed here*', $key, $root);while ($key = next($keys)) {$this->_invalidTagOrder('*no tags allowed here*', $key, $root);}}return $ret;}function _processAttribs($choice, $tag, $context){if (isset($choice['attribs'])) {if (!is_array($tag)) {$tag = array($tag);}$tags = $tag;if (!isset($tags[0])) {$tags = array($tags);}$ret = true;foreach ($tags as $i => $tag) {if (!is_array($tag) || !isset($tag['attribs'])) {foreach ($choice['attribs'] as $attrib) {if ($attrib{0} != '?') {$ret &= $this->_tagHasNoAttribs($choice['tag'],$context);continue 2;}}}foreach ($choice['attribs'] as $attrib) {if ($attrib{0} != '?') {if (!isset($tag['attribs'][$attrib])) {$ret &= $this->_tagMissingAttribute($choice['tag'],$attrib, $context);}}}}return $ret;}return true;}function _processStructure($key){$ret = array();if (count($pieces = explode('|', $key)) > 1) {$ret['choices'] = array();foreach ($pieces as $piece) {$ret['choices'][] = $this->_processStructure($piece);}return $ret;}$multi = $key{0};if ($multi == '+' || $multi == '*') {$ret['multiple'] = $key{0};$key = substr($key, 1);}if (count($attrs = explode('->', $key)) > 1) {$ret['tag'] = array_shift($attrs);$ret['attribs'] = $attrs;} else {$ret['tag'] = $key;}return $ret;}function _validateStabilityVersion(){$structure = array('release', 'api');$a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], '<version>');$a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '<stability>');if ($a) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$this->_packageInfo['version']['release'])) {$this->_invalidVersion('release', $this->_packageInfo['version']['release']);}if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$this->_packageInfo['version']['api'])) {$this->_invalidVersion('api', $this->_packageInfo['version']['api']);}if (!in_array($this->_packageInfo['stability']['release'],array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) {$this->_invalidState('release', $this->_packageInfo['stability']['release']);}if (!in_array($this->_packageInfo['stability']['api'],array('devel', 'alpha', 'beta', 'stable'))) {$this->_invalidState('api', $this->_packageInfo['stability']['api']);}}}function _validateMaintainers(){$structure =array('name','user','email','active',);foreach (array('lead', 'developer', 'contributor', 'helper') as $type) {if (!isset($this->_packageInfo[$type])) {continue;}if (isset($this->_packageInfo[$type][0])) {foreach ($this->_packageInfo[$type] as $lead) {$this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>');}} else {$this->_stupidSchemaValidate($structure, $this->_packageInfo[$type],'<' . $type . '>');}}}function _validatePhpDep($dep, $installcondition = false){$structure = array('min','*max','*exclude',);$type = $installcondition ? '<installcondition><php>' : '<dependencies><required><php>';$this->_stupidSchemaValidate($structure, $dep, $type);if (isset($dep['min'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',$dep['min'])) {$this->_invalidVersion($type . '<min>', $dep['min']);}}if (isset($dep['max'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',$dep['max'])) {$this->_invalidVersion($type . '<max>', $dep['max']);}}if (isset($dep['exclude'])) {if (!is_array($dep['exclude'])) {$dep['exclude'] = array($dep['exclude']);}foreach ($dep['exclude'] as $exclude) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',$exclude)) {$this->_invalidVersion($type . '<exclude>', $exclude);}}}}function _validatePearinstallerDep($dep){$structure = array('min','*max','*recommended','*exclude',);$this->_stupidSchemaValidate($structure, $dep, '<dependencies><required><pearinstaller>');if (isset($dep['min'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['min'])) {$this->_invalidVersion('<dependencies><required><pearinstaller><min>',$dep['min']);}}if (isset($dep['max'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['max'])) {$this->_invalidVersion('<dependencies><required><pearinstaller><max>',$dep['max']);}}if (isset($dep['recommended'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['recommended'])) {$this->_invalidVersion('<dependencies><required><pearinstaller><recommended>',$dep['recommended']);}}if (isset($dep['exclude'])) {if (!is_array($dep['exclude'])) {$dep['exclude'] = array($dep['exclude']);}foreach ($dep['exclude'] as $exclude) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$exclude)) {$this->_invalidVersion('<dependencies><required><pearinstaller><exclude>',$exclude);}}}}function _validatePackageDep($dep, $group, $type = '<package>'){if (isset($dep['uri'])) {if (isset($dep['conflicts'])) {$structure = array('name','uri','conflicts','*providesextension',);} else {$structure = array('name','uri','*providesextension',);}} else {if (isset($dep['conflicts'])) {$structure = array('name','channel','*min','*max','*exclude','conflicts','*providesextension',);} else {$structure = array('name','channel','*min','*max','*recommended','*exclude','*nodefault','*providesextension',);}}if (isset($dep['name'])) {$type .= '<name>' . $dep['name'] . '</name>';}$this->_stupidSchemaValidate($structure, $dep, '<dependencies>' . $group . $type);if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) ||isset($dep['recommended']) || isset($dep['exclude']))) {$this->_uriDepsCannotHaveVersioning('<dependencies>' . $group . $type);}if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') {$this->_DepchannelCannotBeUri('<dependencies>' . $group . $type);}if (isset($dep['min'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['min'])) {$this->_invalidVersion('<dependencies>' . $group . $type . '<min>', $dep['min']);}}if (isset($dep['max'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['max'])) {$this->_invalidVersion('<dependencies>' . $group . $type . '<max>', $dep['max']);}}if (isset($dep['recommended'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['recommended'])) {$this->_invalidVersion('<dependencies>' . $group . $type . '<recommended>',$dep['recommended']);}}if (isset($dep['exclude'])) {if (!is_array($dep['exclude'])) {$dep['exclude'] = array($dep['exclude']);}foreach ($dep['exclude'] as $exclude) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$exclude)) {$this->_invalidVersion('<dependencies>' . $group . $type . '<exclude>',$exclude);}}}}function _validateSubpackageDep($dep, $group){$this->_validatePackageDep($dep, $group, '<subpackage>');if (isset($dep['providesextension'])) {$this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : '');}if (isset($dep['conflicts'])) {$this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : '');}}function _validateExtensionDep($dep, $group = false, $installcondition = false){if (isset($dep['conflicts'])) {$structure = array('name','*min','*max','*exclude','conflicts',);} else {$structure = array('name','*min','*max','*recommended','*exclude',);}if ($installcondition) {$type = '<installcondition><extension>';} else {$type = '<dependencies>' . $group . '<extension>';}if (isset($dep['name'])) {$type .= '<name>' . $dep['name'] . '</name>';}$this->_stupidSchemaValidate($structure, $dep, $type);if (isset($dep['min'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['min'])) {$this->_invalidVersion(substr($type, 1) . '<min', $dep['min']);}}if (isset($dep['max'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['max'])) {$this->_invalidVersion(substr($type, 1) . '<max', $dep['max']);}}if (isset($dep['recommended'])) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$dep['recommended'])) {$this->_invalidVersion(substr($type, 1) . '<recommended', $dep['recommended']);}}if (isset($dep['exclude'])) {if (!is_array($dep['exclude'])) {$dep['exclude'] = array($dep['exclude']);}foreach ($dep['exclude'] as $exclude) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$exclude)) {$this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);}}}}function _validateOsDep($dep, $installcondition = false){$structure = array('name','*conflicts',);$type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>';if ($this->_stupidSchemaValidate($structure, $dep, $type)) {if ($dep['name'] == '*') {if (array_key_exists('conflicts', $dep)) {$this->_cannotConflictWithAllOs($type);}}}}function _validateArchDep($dep, $installcondition = false){$structure = array('pattern','*conflicts',);$type = $installcondition ? '<installcondition><arch>' : '<dependencies><required><arch>';$this->_stupidSchemaValidate($structure, $dep, $type);}function _validateInstallConditions($cond, $release){$structure = array('*php','*extension','*os','*arch',);if (!$this->_stupidSchemaValidate($structure,$cond, $release)) {return false;}foreach (array('php', 'extension', 'os', 'arch') as $type) {if (isset($cond[$type])) {$iter = $cond[$type];if (!is_array($iter) || !isset($iter[0])) {$iter = array($iter);}foreach ($iter as $package) {if ($type == 'extension') {$this->{"_validate{$type}Dep"}($package, false, true);} else {$this->{"_validate{$type}Dep"}($package, true);}}}}}function _validateDependencies(){$structure = array('required','*optional','*group->name->hint');if (!$this->_stupidSchemaValidate($structure,$this->_packageInfo['dependencies'], '<dependencies>')) {return false;}foreach (array('required', 'optional') as $simpledep) {if (isset($this->_packageInfo['dependencies'][$simpledep])) {if ($simpledep == 'optional') {$structure = array('*package','*subpackage','*extension',);} else {$structure = array('php','pearinstaller','*package','*subpackage','*extension','*os','*arch',);}if ($this->_stupidSchemaValidate($structure,$this->_packageInfo['dependencies'][$simpledep],"<dependencies><$simpledep>")) {foreach (array('package', 'subpackage', 'extension') as $type) {if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {$iter = $this->_packageInfo['dependencies'][$simpledep][$type];if (!isset($iter[0])) {$iter = array($iter);}foreach ($iter as $package) {if ($type != 'extension') {if (isset($package['uri'])) {if (isset($package['channel'])) {$this->_UrlOrChannel($type,$package['name']);}} else {if (!isset($package['channel'])) {$this->_NoChannel($type, $package['name']);}}}$this->{"_validate{$type}Dep"}($package, "<$simpledep>");}}}if ($simpledep == 'optional') {continue;}foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) {if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {$iter = $this->_packageInfo['dependencies'][$simpledep][$type];if (!isset($iter[0])) {$iter = array($iter);}foreach ($iter as $package) {$this->{"_validate{$type}Dep"}($package);}}}}}}if (isset($this->_packageInfo['dependencies']['group'])) {$groups = $this->_packageInfo['dependencies']['group'];if (!isset($groups[0])) {$groups = array($groups);}$structure = array('*package','*subpackage','*extension',);foreach ($groups as $group) {if ($this->_stupidSchemaValidate($structure, $group, '<group>')) {if (!PEAR_Validate::validGroupName($group['attribs']['name'])) {$this->_invalidDepGroupName($group['attribs']['name']);}foreach (array('package', 'subpackage', 'extension') as $type) {if (isset($group[$type])) {$iter = $group[$type];if (!isset($iter[0])) {$iter = array($iter);}foreach ($iter as $package) {if ($type != 'extension') {if (isset($package['uri'])) {if (isset($package['channel'])) {$this->_UrlOrChannelGroup($type,$package['name'],$group['name']);}} else {if (!isset($package['channel'])) {$this->_NoChannelGroup($type,$package['name'],$group['name']);}}}$this->{"_validate{$type}Dep"}($package, '<group name="' .$group['attribs']['name'] . '">');}}}}}}}function _validateCompatible(){$compat = $this->_packageInfo['compatible'];if (!isset($compat[0])) {$compat = array($compat);}$required = array('name', 'channel', 'min', 'max', '*exclude');foreach ($compat as $package) {$type = '<compatible>';if (is_array($package) && array_key_exists('name', $package)) {$type .= '<name>' . $package['name'] . '</name>';}$this->_stupidSchemaValidate($required, $package, $type);if (is_array($package) && array_key_exists('min', $package)) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$package['min'])) {$this->_invalidVersion(substr($type, 1) . '<min', $package['min']);}}if (is_array($package) && array_key_exists('max', $package)) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$package['max'])) {$this->_invalidVersion(substr($type, 1) . '<max', $package['max']);}}if (is_array($package) && array_key_exists('exclude', $package)) {if (!is_array($package['exclude'])) {$package['exclude'] = array($package['exclude']);}foreach ($package['exclude'] as $exclude) {if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',$exclude)) {$this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);}}}}}function _validateBundle($list){if (!is_array($list) || !isset($list['bundledpackage'])) {return $this->_NoBundledPackages();}if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) {return $this->_AtLeast2BundledPackages();}foreach ($list['bundledpackage'] as $package) {if (!is_string($package)) {$this->_bundledPackagesMustBeFilename();}}}function _validateFilelist($list = false, $allowignore = false, $dirs = ''){$iscontents = false;if (!$list) {$iscontents = true;$list = $this->_packageInfo['contents'];if (isset($this->_packageInfo['bundle'])) {return $this->_validateBundle($list);}}if ($allowignore) {$struc = array('*install->name->as','*ignore->name');} else {$struc = array('*dir->name->?baseinstalldir','*file->name->role->?baseinstalldir->?md5sum');if (isset($list['dir']) && isset($list['file'])) {// stave off validation errors without requiring a set order.$_old = $list;if (isset($list['attribs'])) {$list = array('attribs' => $_old['attribs']);}$list['dir'] = $_old['dir'];$list['file'] = $_old['file'];}}if (!isset($list['attribs']) || !isset($list['attribs']['name'])) {$unknown = $allowignore ? '<filelist>' : '<dir name="*unknown*">';$dirname = $iscontents ? '<contents>' : $unknown;} else {$dirname = '<dir name="' . $list['attribs']['name'] . '">';if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',str_replace('\\', '/', $list['attribs']['name']))) {// file contains .. parent directory or . cur directory$this->_invalidDirName($list['attribs']['name']);}}$res = $this->_stupidSchemaValidate($struc, $list, $dirname);if ($allowignore && $res) {$ignored_or_installed = array();$this->_pf->getFilelist();$fcontents = $this->_pf->getContents();$filelist = array();if (!isset($fcontents['dir']['file'][0])) {$fcontents['dir']['file'] = array($fcontents['dir']['file']);}foreach ($fcontents['dir']['file'] as $file) {$filelist[$file['attribs']['name']] = true;}if (isset($list['install'])) {if (!isset($list['install'][0])) {$list['install'] = array($list['install']);}foreach ($list['install'] as $file) {if (!isset($filelist[$file['attribs']['name']])) {$this->_notInContents($file['attribs']['name'], 'install');continue;}if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {$this->_multipleInstallAs($file['attribs']['name']);}if (!isset($ignored_or_installed[$file['attribs']['name']])) {$ignored_or_installed[$file['attribs']['name']] = array();}$ignored_or_installed[$file['attribs']['name']][] = 1;if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',str_replace('\\', '/', $file['attribs']['as']))) {// file contains .. parent directory or . cur directory references$this->_invalidFileInstallAs($file['attribs']['name'],$file['attribs']['as']);}}}if (isset($list['ignore'])) {if (!isset($list['ignore'][0])) {$list['ignore'] = array($list['ignore']);}foreach ($list['ignore'] as $file) {if (!isset($filelist[$file['attribs']['name']])) {$this->_notInContents($file['attribs']['name'], 'ignore');continue;}if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {$this->_ignoreAndInstallAs($file['attribs']['name']);}}}}if (!$allowignore && isset($list['file'])) {if (is_string($list['file'])) {$this->_oldStyleFileNotAllowed();return false;}if (!isset($list['file'][0])) {// single file$list['file'] = array($list['file']);}foreach ($list['file'] as $i => $file){if (isset($file['attribs']) && isset($file['attribs']['name'])) {if ($file['attribs']['name']{0} == '.' &&$file['attribs']['name']{1} == '/') {// name is something like "./doc/whatever.txt"$this->_invalidFileName($file['attribs']['name'], $dirname);}if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',str_replace('\\', '/', $file['attribs']['name']))) {// file contains .. parent directory or . cur directory$this->_invalidFileName($file['attribs']['name'], $dirname);}}if (isset($file['attribs']) && isset($file['attribs']['role'])) {if (!$this->_validateRole($file['attribs']['role'])) {if (isset($this->_packageInfo['usesrole'])) {$roles = $this->_packageInfo['usesrole'];if (!isset($roles[0])) {$roles = array($roles);}foreach ($roles as $role) {if ($role['role'] = $file['attribs']['role']) {$msg = 'This package contains role "%role%" and requires ' .'package "%package%" to be used';if (isset($role['uri'])) {$params = array('role' => $role['role'],'package' => $role['uri']);} else {$params = array('role' => $role['role'],'package' => $this->_pf->_registry->parsedPackageNameToString(array('package' =>$role['package'], 'channel' => $role['channel']),true));}$this->_stack->push('_mustInstallRole', 'error', $params, $msg);}}}$this->_invalidFileRole($file['attribs']['name'],$dirname, $file['attribs']['role']);}}if (!isset($file['attribs'])) {continue;}$save = $file['attribs'];if ($dirs) {$save['name'] = $dirs . '/' . $save['name'];}unset($file['attribs']);if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasksforeach ($file as $task => $value) {if ($tagClass = $this->_pf->getTask($task)) {if (!is_array($value) || !isset($value[0])) {$value = array($value);}foreach ($value as $v) {$ret = call_user_func(array($tagClass, 'validateXml'),$this->_pf, $v, $this->_pf->_config, $save);if (is_array($ret)) {$this->_invalidTask($task, $ret, isset($save['name']) ?$save['name'] : '');}}} else {if (isset($this->_packageInfo['usestask'])) {$roles = $this->_packageInfo['usestask'];if (!isset($roles[0])) {$roles = array($roles);}foreach ($roles as $role) {if ($role['task'] = $task) {$msg = 'This package contains task "%task%" and requires ' .'package "%package%" to be used';if (isset($role['uri'])) {$params = array('task' => $role['task'],'package' => $role['uri']);} else {$params = array('task' => $role['task'],'package' => $this->_pf->_registry->parsedPackageNameToString(array('package' =>$role['package'], 'channel' => $role['channel']),true));}$this->_stack->push('_mustInstallTask', 'error',$params, $msg);}}}$this->_unknownTask($task, $save['name']);}}}}}if (isset($list['ignore'])) {if (!$allowignore) {$this->_ignoreNotAllowed('ignore');}}if (isset($list['install'])) {if (!$allowignore) {$this->_ignoreNotAllowed('install');}}if (isset($list['file'])) {if ($allowignore) {$this->_fileNotAllowed('file');}}if (isset($list['dir'])) {if ($allowignore) {$this->_fileNotAllowed('dir');} else {if (!isset($list['dir'][0])) {$list['dir'] = array($list['dir']);}foreach ($list['dir'] as $dir) {if (isset($dir['attribs']) && isset($dir['attribs']['name'])) {if ($dir['attribs']['name'] == '/' ||!isset($this->_packageInfo['contents']['dir']['dir'])) {// always use nothing if the filelist has already been flattened$newdirs = '';} elseif ($dirs == '') {$newdirs = $dir['attribs']['name'];} else {$newdirs = $dirs . '/' . $dir['attribs']['name'];}} else {$newdirs = $dirs;}$this->_validateFilelist($dir, $allowignore, $newdirs);}}}}function _validateRelease(){if (isset($this->_packageInfo['phprelease'])) {$release = 'phprelease';if (isset($this->_packageInfo['providesextension'])) {$this->_cannotProvideExtension($release);}if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {$this->_cannotHaveSrcpackage($release);}$releases = $this->_packageInfo['phprelease'];if (!is_array($releases)) {return true;}if (!isset($releases[0])) {$releases = array($releases);}foreach ($releases as $rel) {$this->_stupidSchemaValidate(array('*installconditions','*filelist',), $rel, '<phprelease>');}}foreach (array('', 'zend') as $prefix) {$releasetype = $prefix . 'extsrcrelease';if (isset($this->_packageInfo[$releasetype])) {$release = $releasetype;if (!isset($this->_packageInfo['providesextension'])) {$this->_mustProvideExtension($release);}if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {$this->_cannotHaveSrcpackage($release);}$releases = $this->_packageInfo[$releasetype];if (!is_array($releases)) {return true;}if (!isset($releases[0])) {$releases = array($releases);}foreach ($releases as $rel) {$this->_stupidSchemaValidate(array('*installconditions','*configureoption->name->prompt->?default','*binarypackage','*filelist',), $rel, '<' . $releasetype . '>');if (isset($rel['binarypackage'])) {if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) {$rel['binarypackage'] = array($rel['binarypackage']);}foreach ($rel['binarypackage'] as $bin) {if (!is_string($bin)) {$this->_binaryPackageMustBePackagename();}}}}}$releasetype = 'extbinrelease';if (isset($this->_packageInfo[$releasetype])) {$release = $releasetype;if (!isset($this->_packageInfo['providesextension'])) {$this->_mustProvideExtension($release);}if (isset($this->_packageInfo['channel']) &&!isset($this->_packageInfo['srcpackage'])) {$this->_mustSrcPackage($release);}if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) {$this->_mustSrcuri($release);}$releases = $this->_packageInfo[$releasetype];if (!is_array($releases)) {return true;}if (!isset($releases[0])) {$releases = array($releases);}foreach ($releases as $rel) {$this->_stupidSchemaValidate(array('*installconditions','*filelist',), $rel, '<' . $releasetype . '>');}}}if (isset($this->_packageInfo['bundle'])) {$release = 'bundle';if (isset($this->_packageInfo['providesextension'])) {$this->_cannotProvideExtension($release);}if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {$this->_cannotHaveSrcpackage($release);}$releases = $this->_packageInfo['bundle'];if (!is_array($releases) || !isset($releases[0])) {$releases = array($releases);}foreach ($releases as $rel) {$this->_stupidSchemaValidate(array('*installconditions','*filelist',), $rel, '<bundle>');}}foreach ($releases as $rel) {if (is_array($rel) && array_key_exists('installconditions', $rel)) {$this->_validateInstallConditions($rel['installconditions'],"<$release><installconditions>");}if (is_array($rel) && array_key_exists('filelist', $rel)) {if ($rel['filelist']) {$this->_validateFilelist($rel['filelist'], true);}}}}/*** This is here to allow role extension through plugins* @param string*/function _validateRole($role){return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType()));}function _pearVersionTooLow($version){$this->_stack->push(__FUNCTION__, 'error',array('version' => $version),'This package.xml requires PEAR version %version% to parse properly, we are ' .'version 1.10.1');}function _invalidTagOrder($oktags, $actual, $root){$this->_stack->push(__FUNCTION__, 'error',array('oktags' => $oktags, 'actual' => $actual, 'root' => $root),'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"');}function _ignoreNotAllowed($type){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type),'<%type%> is not allowed inside global <contents>, only inside ' .'<phprelease>/<extbinrelease>/<zendextbinrelease>, use <dir> and <file> only');}function _fileNotAllowed($type){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type),'<%type%> is not allowed inside release <filelist>, only inside ' .'<contents>, use <ignore> and <install> only');}function _oldStyleFileNotAllowed(){$this->_stack->push(__FUNCTION__, 'error', array(),'Old-style <file>name</file> is not allowed. Use' .'<file name="name" role="role"/>');}function _tagMissingAttribute($tag, $attr, $context){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,'attribute' => $attr, 'context' => $context),'tag <%tag%> in context "%context%" has no attribute "%attribute%"');}function _tagHasNoAttribs($tag, $context){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,'context' => $context),'tag <%tag%> has no attributes in context "%context%"');}function _invalidInternalStructure(){$this->_stack->push(__FUNCTION__, 'exception', array(),'internal array was not generated by compatible parser, or extreme parser error, cannot continue');}function _invalidFileRole($file, $dir, $role){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'dir' => $dir, 'role' => $role,'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())),'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%');}function _invalidFileName($file, $dir){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file),'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."');}function _invalidFileInstallAs($file, $as){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'as' => $as),'File "%file%" <install as="%as%"/> cannot contain "./" or contain ".."');}function _invalidDirName($dir){$this->_stack->push(__FUNCTION__, 'error', array('dir' => $file),'Directory "%dir%" cannot begin with "./" or contain ".."');}function _filelistCannotContainFile($filelist){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),'<%tag%> can only contain <dir>, contains <file>. Use ' .'<dir name="/"> as the first dir element');}function _filelistMustContainDir($filelist){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),'<%tag%> must contain <dir>. Use <dir name="/"> as the ' .'first dir element');}function _tagCannotBeEmpty($tag){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),'<%tag%> cannot be empty (<%tag%/>)');}function _UrlOrChannel($type, $name){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type,'name' => $name),'Required dependency <%type%> "%name%" can have either url OR ' .'channel attributes, and not both');}function _NoChannel($type, $name){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type,'name' => $name),'Required dependency <%type%> "%name%" must have either url OR ' .'channel attributes');}function _UrlOrChannelGroup($type, $name, $group){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type,'name' => $name, 'group' => $group),'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .'channel attributes, and not both');}function _NoChannelGroup($type, $name, $group){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type,'name' => $name, 'group' => $group),'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .'channel attributes');}function _unknownChannel($channel){$this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel),'Unknown channel "%channel%"');}function _noPackageVersion(){$this->_stack->push(__FUNCTION__, 'error', array(),'package.xml <package> tag has no version attribute, or version is not 2.0');}function _NoBundledPackages(){$this->_stack->push(__FUNCTION__, 'error', array(),'No <bundledpackage> tag was found in <contents>, required for bundle packages');}function _AtLeast2BundledPackages(){$this->_stack->push(__FUNCTION__, 'error', array(),'At least 2 packages must be bundled in a bundle package');}function _ChannelOrUri($name){$this->_stack->push(__FUNCTION__, 'error', array('name' => $name),'Bundled package "%name%" can have either a uri or a channel, not both');}function _noChildTag($child, $tag){$this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag),'Tag <%tag%> is missing child tag <%child%>');}function _invalidVersion($type, $value){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value),'Version type <%type%> is not a valid version (%value%)');}function _invalidState($type, $value){$states = array('stable', 'beta', 'alpha', 'devel');if ($type != 'api') {$states[] = 'snapshot';}if (strtolower($value) == 'rc') {$this->_stack->push(__FUNCTION__, 'error',array('version' => $this->_packageInfo['version']['release']),'RC is not a state, it is a version postfix, try %version%RC1, stability beta');}$this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value,'types' => $states),'Stability type <%type%> is not a valid stability (%value%), must be one of ' .'%types%');}function _invalidTask($task, $ret, $file){switch ($ret[0]) {case PEAR_TASK_ERROR_MISSING_ATTRIB :$info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file);$msg = 'task <%task%> is missing attribute "%attrib%" in file %file%';break;case PEAR_TASK_ERROR_NOATTRIBS :$info = array('task' => $task, 'file' => $file);$msg = 'task <%task%> has no attributes in file %file%';break;case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :$info = array('attrib' => $ret[1], 'values' => $ret[3],'was' => $ret[2], 'task' => $task, 'file' => $file);$msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '.'in file %file%, expecting one of "%values%"';break;case PEAR_TASK_ERROR_INVALID :$info = array('reason' => $ret[1], 'task' => $task, 'file' => $file);$msg = 'task <%task%> in file %file% is invalid because of "%reason%"';break;}$this->_stack->push(__FUNCTION__, 'error', $info, $msg);}function _unknownTask($task, $file){$this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file),'Unknown task "%task%" passed in file <file name="%file%">');}function _subpackageCannotProvideExtension($name){$this->_stack->push(__FUNCTION__, 'error', array('name' => $name),'Subpackage dependency "%name%" cannot use <providesextension>, ' .'only package dependencies can use this tag');}function _subpackagesCannotConflict($name){$this->_stack->push(__FUNCTION__, 'error', array('name' => $name),'Subpackage dependency "%name%" cannot use <conflicts/>, ' .'only package dependencies can use this tag');}function _cannotProvideExtension($release){$this->_stack->push(__FUNCTION__, 'error', array('release' => $release),'<%release%> packages cannot use <providesextension>, only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension');}function _mustProvideExtension($release){$this->_stack->push(__FUNCTION__, 'error', array('release' => $release),'<%release%> packages must use <providesextension> to indicate which PHP extension is provided');}function _cannotHaveSrcpackage($release){$this->_stack->push(__FUNCTION__, 'error', array('release' => $release),'<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag');}function _mustSrcPackage($release){$this->_stack->push(__FUNCTION__, 'error', array('release' => $release),'<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcpackage>');}function _mustSrcuri($release){$this->_stack->push(__FUNCTION__, 'error', array('release' => $release),'<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcuri>');}function _uriDepsCannotHaveVersioning($type){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type),'%type%: dependencies with a <uri> tag cannot have any versioning information');}function _conflictingDepsCannotHaveVersioning($type){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type),'%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' .'exclude specific versions of a dependency');}function _DepchannelCannotBeUri($type){$this->_stack->push(__FUNCTION__, 'error', array('type' => $type),'%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .'dependencies only');}function _bundledPackagesMustBeFilename(){$this->_stack->push(__FUNCTION__, 'error', array(),'<bundledpackage> tags must contain only the filename of a package release ' .'in the bundle');}function _binaryPackageMustBePackagename(){$this->_stack->push(__FUNCTION__, 'error', array(),'<binarypackage> tags must contain the name of a package that is ' .'a compiled version of this extsrc/zendextsrc package');}function _fileNotFound($file){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file),'File "%file%" in package.xml does not exist');}function _notInContents($file, $tag){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag),'<%tag% name="%file%"> is invalid, file is not in <contents>');}function _cannotValidateNoPathSet(){$this->_stack->push(__FUNCTION__, 'error', array(),'Cannot validate files, no path to package file is set (use setPackageFile())');}function _usesroletaskMustHaveChannelOrUri($role, $tag){$this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),'<%tag%> for role "%role%" must contain either <uri>, or <channel> and <package>');}function _usesroletaskMustHavePackage($role, $tag){$this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),'<%tag%> for role "%role%" must contain <package>');}function _usesroletaskMustHaveRoleTask($tag, $type){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type),'<%tag%> must contain <%type%> defining the %type% to be used');}function _cannotConflictWithAllOs($type){$this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),'%tag% cannot conflict with all OSes');}function _invalidDepGroupName($name){$this->_stack->push(__FUNCTION__, 'error', array('name' => $name),'Invalid dependency group name "%name%"');}function _multipleToplevelDirNotAllowed(){$this->_stack->push(__FUNCTION__, 'error', array(),'Multiple top-level <dir> tags are not allowed. Enclose them ' .'in a <dir name="/">');}function _multipleInstallAs($file){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file),'Only one <install> tag is allowed for file "%file%"');}function _ignoreAndInstallAs($file){$this->_stack->push(__FUNCTION__, 'error', array('file' => $file),'Cannot have both <ignore> and <install> tags for file "%file%"');}function _analyzeBundledPackages(){if (!$this->_isValid) {return false;}if (!$this->_pf->getPackageType() == 'bundle') {return false;}if (!isset($this->_pf->_packageFile)) {return false;}$dir_prefix = dirname($this->_pf->_packageFile);$common = new PEAR_Common;$log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :array($common, 'log');$info = $this->_pf->getContents();$info = $info['bundledpackage'];if (!is_array($info)) {$info = array($info);}$pkg = new PEAR_PackageFile($this->_pf->_config);foreach ($info as $package) {if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) {$this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package);$this->_isValid = 0;continue;}call_user_func_array($log, array(1, "Analyzing bundled package $package"));PEAR::pushErrorHandling(PEAR_ERROR_RETURN);$ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package,PEAR_VALIDATE_NORMAL);PEAR::popErrorHandling();if (PEAR::isError($ret)) {call_user_func_array($log, array(0, "ERROR: package $package is not a valid " .'package'));$inf = $ret->getUserInfo();if (is_array($inf)) {foreach ($inf as $err) {call_user_func_array($log, array(1, $err['message']));}}return false;}}return true;}function _analyzePhpFiles(){if (!$this->_isValid) {return false;}if (!isset($this->_pf->_packageFile)) {$this->_cannotValidateNoPathSet();return false;}$dir_prefix = dirname($this->_pf->_packageFile);$common = new PEAR_Common;$log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :array(&$common, 'log');$info = $this->_pf->getContents();if (!$info || !isset($info['dir']['file'])) {$this->_tagCannotBeEmpty('contents><dir');return false;}$info = $info['dir']['file'];if (isset($info['attribs'])) {$info = array($info);}$provides = array();foreach ($info as $fa) {$fa = $fa['attribs'];$file = $fa['name'];if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {$this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file);$this->_isValid = 0;continue;}if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) {call_user_func_array($log, array(1, "Analyzing $file"));$srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);if ($srcinfo) {$provides = array_merge($provides, $this->_buildProvidesArray($srcinfo));}}}$this->_packageName = $pn = $this->_pf->getPackage();$pnl = strlen($pn);foreach ($provides as $key => $what) {if (isset($what['explicit']) || !$what) {// skip conformance checks if the provides entry is// specified in the package.xml filecontinue;}extract($what);if ($type == 'class') {if (!strncasecmp($name, $pn, $pnl)) {continue;}$this->_stack->push(__FUNCTION__, 'warning',array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),'in %file%: %type% "%name%" not prefixed with package name "%package%"');} elseif ($type == 'function') {if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {continue;}$this->_stack->push(__FUNCTION__, 'warning',array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),'in %file%: %type% "%name%" not prefixed with package name "%package%"');}}return $this->_isValid;}/*** Analyze the source code of the given PHP file** @param string Filename of the PHP file* @param boolean whether to analyze $file as the file contents* @return mixed*/function analyzeSourceCode($file, $string = false){if (!function_exists("token_get_all")) {$this->_stack->push(__FUNCTION__, 'error', array('file' => $file),'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer');return false;}if (!defined('T_DOC_COMMENT')) {define('T_DOC_COMMENT', T_COMMENT);}if (!defined('T_INTERFACE')) {define('T_INTERFACE', -1);}if (!defined('T_IMPLEMENTS')) {define('T_IMPLEMENTS', -1);}if ($string) {$contents = $file;} else {if (!$fp = @fopen($file, "r")) {return false;}fclose($fp);$contents = file_get_contents($file);}// Silence this function so we can catch PHP Warnings and show our own custom message$tokens = @token_get_all($contents);if (isset($php_errormsg)) {if (isset($this->_stack)) {$pn = $this->_pf->getPackage();$this->_stack->push(__FUNCTION__, 'warning',array('file' => $file, 'package' => $pn),'in %file%: Could not process file for unknown reasons,' .' possibly a PHP parse error in %file% from %package%');}}/*for ($i = 0; $i < sizeof($tokens); $i++) {@list($token, $data) = $tokens[$i];if (is_string($token)) {var_dump($token);} else {print token_name($token) . ' ';var_dump(rtrim($data));}}*/$look_for = 0;$paren_level = 0;$bracket_level = 0;$brace_level = 0;$lastphpdoc = '';$current_class = '';$current_interface = '';$current_class_level = -1;$current_function = '';$current_function_level = -1;$declared_classes = array();$declared_interfaces = array();$declared_functions = array();$declared_methods = array();$used_classes = array();$used_functions = array();$extends = array();$implements = array();$nodeps = array();$inquote = false;$interface = false;for ($i = 0; $i < sizeof($tokens); $i++) {if (is_array($tokens[$i])) {list($token, $data) = $tokens[$i];} else {$token = $tokens[$i];$data = '';}if ($inquote) {if ($token != '"' && $token != T_END_HEREDOC) {continue;} else {$inquote = false;continue;}}switch ($token) {case T_WHITESPACE :continue;case ';':if ($interface) {$current_function = '';$current_function_level = -1;}break;case '"':case T_START_HEREDOC:$inquote = true;break;case T_CURLY_OPEN:case T_DOLLAR_OPEN_CURLY_BRACES:case '{': $brace_level++; continue 2;case '}':$brace_level--;if ($current_class_level == $brace_level) {$current_class = '';$current_class_level = -1;}if ($current_function_level == $brace_level) {$current_function = '';$current_function_level = -1;}continue 2;case '[': $bracket_level++; continue 2;case ']': $bracket_level--; continue 2;case '(': $paren_level++; continue 2;case ')': $paren_level--; continue 2;case T_INTERFACE:$interface = true;case T_CLASS:if (($current_class_level != -1) || ($current_function_level != -1)) {if (isset($this->_stack)) {$this->_stack->push(__FUNCTION__, 'error', array('file' => $file),'Parser error: invalid PHP found in file "%file%"');} else {PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",PEAR_COMMON_ERROR_INVALIDPHP);}return false;}case T_FUNCTION:case T_NEW:case T_EXTENDS:case T_IMPLEMENTS:$look_for = $token;continue 2;case T_STRING:if ($look_for == T_CLASS) {$current_class = $data;$current_class_level = $brace_level;$declared_classes[] = $current_class;} elseif ($look_for == T_INTERFACE) {$current_interface = $data;$current_class_level = $brace_level;$declared_interfaces[] = $current_interface;} elseif ($look_for == T_IMPLEMENTS) {$implements[$current_class] = $data;} elseif ($look_for == T_EXTENDS) {$extends[$current_class] = $data;} elseif ($look_for == T_FUNCTION) {if ($current_class) {$current_function = "$current_class::$data";$declared_methods[$current_class][] = $data;} elseif ($current_interface) {$current_function = "$current_interface::$data";$declared_methods[$current_interface][] = $data;} else {$current_function = $data;$declared_functions[] = $current_function;}$current_function_level = $brace_level;$m = array();} elseif ($look_for == T_NEW) {$used_classes[$data] = true;}$look_for = 0;continue 2;case T_VARIABLE:$look_for = 0;continue 2;case T_DOC_COMMENT:case T_COMMENT:if (preg_match('!^/\*\*\s!', $data)) {$lastphpdoc = $data;if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {$nodeps = array_merge($nodeps, $m[1]);}}continue 2;case T_DOUBLE_COLON:$token = $tokens[$i - 1][0];if (!($token == T_WHITESPACE || $token == T_STRING || $token == T_STATIC || $token == T_VARIABLE)) {if (isset($this->_stack)) {$this->_stack->push(__FUNCTION__, 'warning', array('file' => $file),'Parser error: invalid PHP found in file "%file%"');} else {PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",PEAR_COMMON_ERROR_INVALIDPHP);}return false;}$class = $tokens[$i - 1][1];if (strtolower($class) != 'parent') {$used_classes[$class] = true;}continue 2;}}return array("source_file" => $file,"declared_classes" => $declared_classes,"declared_interfaces" => $declared_interfaces,"declared_methods" => $declared_methods,"declared_functions" => $declared_functions,"used_classes" => array_diff(array_keys($used_classes), $nodeps),"inheritance" => $extends,"implements" => $implements,);}/*** Build a "provides" array from data returned by* analyzeSourceCode(). The format of the built array is like* this:** array(* 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),* ...* )*** @param array $srcinfo array with information about a source file* as returned by the analyzeSourceCode() method.** @return void** @access private**/function _buildProvidesArray($srcinfo){if (!$this->_isValid) {return array();}$providesret = array();$file = basename($srcinfo['source_file']);$pn = isset($this->_pf) ? $this->_pf->getPackage() : '';$pnl = strlen($pn);foreach ($srcinfo['declared_classes'] as $class) {$key = "class;$class";if (isset($providesret[$key])) {continue;}$providesret[$key] =array('file'=> $file, 'type' => 'class', 'name' => $class);if (isset($srcinfo['inheritance'][$class])) {$providesret[$key]['extends'] =$srcinfo['inheritance'][$class];}}foreach ($srcinfo['declared_methods'] as $class => $methods) {foreach ($methods as $method) {$function = "$class::$method";$key = "function;$function";if ($method{0} == '_' || !strcasecmp($method, $class) ||isset($providesret[$key])) {continue;}$providesret[$key] =array('file'=> $file, 'type' => 'function', 'name' => $function);}}foreach ($srcinfo['declared_functions'] as $function) {$key = "function;$function";if ($function{0} == '_' || isset($providesret[$key])) {continue;}if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {$warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";}$providesret[$key] =array('file'=> $file, 'type' => 'function', 'name' => $function);}return $providesret;}}