| [ Index ] |
|
Code source de PHP PEAR 1.4.5 |
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.96 2006/11/21 03:17:17 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.0', 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($key, 1); 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*)?$/', 470 $this->_packageInfo['version']['release'])) { 471 $this->_invalidVersion('release', $this->_packageInfo['version']['release']); 472 } 473 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/', 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[$type] as $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]+)?$/', 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]+)?$/', 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]+)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 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*)?$/', 717 $dep['min'])) { 718 $this->_invalidVersion(substr($type, 1) . '<min', $dep['min']); 719 } 720 } 721 if (isset($dep['max'])) { 722 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/', 723 $dep['max'])) { 724 $this->_invalidVersion(substr($type, 1) . '<max', $dep['max']); 725 } 726 } 727 if (isset($dep['recommended'])) { 728 if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?$/', 729 $dep['recommended'])) { 730 $this->_invalidVersion(substr($type, 1) . '<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*)?$/', 739 $exclude)) { 740 $this->_invalidVersion(substr($type, 1) . '<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"}($package, false, true); 793 } else { 794 $this->{"_validate{$type}Dep"}($package, true); 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*)?$/', 936 $package['min'])) { 937 $this->_invalidVersion(substr($type, 1) . '<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*)?$/', 942 $package['max'])) { 943 $this->_invalidVersion(substr($type, 1) . '<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*)?$/', 952 $exclude)) { 953 $this->_invalidVersion(substr($type, 1) . '<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 (!isset($list['file'][0])) { 1058 // single file 1059 $list['file'] = array($list['file']); 1060 } 1061 foreach ($list['file'] as $i => $file) 1062 { 1063 if (isset($file['attribs']) && isset($file['attribs']['name']) && 1064 $file['attribs']['name']{0} == '.' && 1065 $file['attribs']['name']{1} == '/') { 1066 // name is something like "./doc/whatever.txt" 1067 $this->_invalidFileName($file['attribs']['name']); 1068 } 1069 if (isset($file['attribs']) && isset($file['attribs']['role'])) { 1070 if (!$this->_validateRole($file['attribs']['role'])) { 1071 if (isset($this->_packageInfo['usesrole'])) { 1072 $roles = $this->_packageInfo['usesrole']; 1073 if (!isset($roles[0])) { 1074 $roles = array($roles); 1075 } 1076 foreach ($roles as $role) { 1077 if ($role['role'] = $file['attribs']['role']) { 1078 $msg = 'This package contains role "%role%" and requires ' . 1079 'package "%package%" to be used'; 1080 if (isset($role['uri'])) { 1081 $params = array('role' => $role['role'], 1082 'package' => $role['uri']); 1083 } else { 1084 $params = array('role' => $role['role'], 1085 'package' => $this->_pf->_registry-> 1086 parsedPackageNameToString(array('package' => 1087 $role['package'], 'channel' => $role['channel']), 1088 true)); 1089 } 1090 $this->_stack->push('_mustInstallRole', 'error', $params, $msg); 1091 } 1092 } 1093 } 1094 $this->_invalidFileRole($file['attribs']['name'], 1095 $dirname, $file['attribs']['role']); 1096 } 1097 } 1098 if (!isset($file['attribs'])) { 1099 continue; 1100 } 1101 $save = $file['attribs']; 1102 if ($dirs) { 1103 $save['name'] = $dirs . '/' . $save['name']; 1104 } 1105 unset($file['attribs']); 1106 if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks 1107 foreach ($file as $task => $value) { 1108 if ($tagClass = $this->_pf->getTask($task)) { 1109 if (!is_array($value) || !isset($value[0])) { 1110 $value = array($value); 1111 } 1112 foreach ($value as $v) { 1113 $ret = call_user_func(array($tagClass, 'validateXml'), 1114 $this->_pf, $v, $this->_pf->_config, $save); 1115 if (is_array($ret)) { 1116 $this->_invalidTask($task, $ret, isset($save['name']) ? 1117 $save['name'] : ''); 1118 } 1119 } 1120 } else { 1121 if (isset($this->_packageInfo['usestask'])) { 1122 $roles = $this->_packageInfo['usestask']; 1123 if (!isset($roles[0])) { 1124 $roles = array($roles); 1125 } 1126 foreach ($roles as $role) { 1127 if ($role['task'] = $task) { 1128 $msg = 'This package contains task "%task%" and requires ' . 1129 'package "%package%" to be used'; 1130 if (isset($role['uri'])) { 1131 $params = array('task' => $role['task'], 1132 'package' => $role['uri']); 1133 } else { 1134 $params = array('task' => $role['task'], 1135 'package' => $this->_pf->_registry-> 1136 parsedPackageNameToString(array('package' => 1137 $role['package'], 'channel' => $role['channel']), 1138 true)); 1139 } 1140 $this->_stack->push('_mustInstallTask', 'error', 1141 $params, $msg); 1142 } 1143 } 1144 } 1145 $this->_unknownTask($task, $save['name']); 1146 } 1147 } 1148 } 1149 } 1150 } 1151 if (isset($list['ignore'])) { 1152 if (!$allowignore) { 1153 $this->_ignoreNotAllowed('ignore'); 1154 } 1155 } 1156 if (isset($list['install'])) { 1157 if (!$allowignore) { 1158 $this->_ignoreNotAllowed('install'); 1159 } 1160 } 1161 if (isset($list['file'])) { 1162 if ($allowignore) { 1163 $this->_fileNotAllowed('file'); 1164 } 1165 } 1166 if (isset($list['dir'])) { 1167 if ($allowignore) { 1168 $this->_fileNotAllowed('dir'); 1169 } else { 1170 if (!isset($list['dir'][0])) { 1171 $list['dir'] = array($list['dir']); 1172 } 1173 foreach ($list['dir'] as $dir) { 1174 if (isset($dir['attribs']) && isset($dir['attribs']['name'])) { 1175 if ($dir['attribs']['name'] == '/' || 1176 !isset($this->_packageInfo['contents']['dir']['dir'])) { 1177 // always use nothing if the filelist has already been flattened 1178 $newdirs = ''; 1179 } elseif ($dirs == '') { 1180 $newdirs = $dir['attribs']['name']; 1181 } else { 1182 $newdirs = $dirs . '/' . $dir['attribs']['name']; 1183 } 1184 } else { 1185 $newdirs = $dirs; 1186 } 1187 $this->_validateFilelist($dir, $allowignore, $newdirs); 1188 } 1189 } 1190 } 1191 } 1192 1193 function _validateRelease() 1194 { 1195 if (isset($this->_packageInfo['phprelease'])) { 1196 $release = 'phprelease'; 1197 if (isset($this->_packageInfo['providesextension'])) { 1198 $this->_cannotProvideExtension($release); 1199 } 1200 if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { 1201 $this->_cannotHaveSrcpackage($release); 1202 } 1203 $releases = $this->_packageInfo['phprelease']; 1204 if (!is_array($releases)) { 1205 return true; 1206 } 1207 if (!isset($releases[0])) { 1208 $releases = array($releases); 1209 } 1210 foreach ($releases as $rel) { 1211 $this->_stupidSchemaValidate(array( 1212 '*installconditions', 1213 '*filelist', 1214 ), $rel, '<phprelease>'); 1215 } 1216 } 1217 foreach (array('', 'zend') as $prefix) { 1218 $releasetype = $prefix . 'extsrcrelease'; 1219 if (isset($this->_packageInfo[$releasetype])) { 1220 $release = $releasetype; 1221 if (!isset($this->_packageInfo['providesextension'])) { 1222 $this->_mustProvideExtension($release); 1223 } 1224 if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { 1225 $this->_cannotHaveSrcpackage($release); 1226 } 1227 $releases = $this->_packageInfo[$releasetype]; 1228 if (!is_array($releases)) { 1229 return true; 1230 } 1231 if (!isset($releases[0])) { 1232 $releases = array($releases); 1233 } 1234 foreach ($releases as $rel) { 1235 $this->_stupidSchemaValidate(array( 1236 '*installconditions', 1237 '*configureoption->name->prompt->?default', 1238 '*binarypackage', 1239 '*filelist', 1240 ), $rel, '<' . $releasetype . '>'); 1241 if (isset($rel['binarypackage'])) { 1242 if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) { 1243 $rel['binarypackage'] = array($rel['binarypackage']); 1244 } 1245 foreach ($rel['binarypackage'] as $bin) { 1246 if (!is_string($bin)) { 1247 $this->_binaryPackageMustBePackagename(); 1248 } 1249 } 1250 } 1251 } 1252 } 1253 $releasetype = 'extbinrelease'; 1254 if (isset($this->_packageInfo[$releasetype])) { 1255 $release = $releasetype; 1256 if (!isset($this->_packageInfo['providesextension'])) { 1257 $this->_mustProvideExtension($release); 1258 } 1259 if (isset($this->_packageInfo['channel']) && 1260 !isset($this->_packageInfo['srcpackage'])) { 1261 $this->_mustSrcPackage($release); 1262 } 1263 if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) { 1264 $this->_mustSrcuri($release); 1265 } 1266 $releases = $this->_packageInfo[$releasetype]; 1267 if (!is_array($releases)) { 1268 return true; 1269 } 1270 if (!isset($releases[0])) { 1271 $releases = array($releases); 1272 } 1273 foreach ($releases as $rel) { 1274 $this->_stupidSchemaValidate(array( 1275 '*installconditions', 1276 '*filelist', 1277 ), $rel, '<' . $releasetype . '>'); 1278 } 1279 } 1280 } 1281 if (isset($this->_packageInfo['bundle'])) { 1282 $release = 'bundle'; 1283 if (isset($this->_packageInfo['providesextension'])) { 1284 $this->_cannotProvideExtension($release); 1285 } 1286 if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { 1287 $this->_cannotHaveSrcpackage($release); 1288 } 1289 $releases = $this->_packageInfo['bundle']; 1290 if (!is_array($releases) || !isset($releases[0])) { 1291 $releases = array($releases); 1292 } 1293 foreach ($releases as $rel) { 1294 $this->_stupidSchemaValidate(array( 1295 '*installconditions', 1296 '*filelist', 1297 ), $rel, '<bundle>'); 1298 } 1299 } 1300 foreach ($releases as $rel) { 1301 if (is_array($rel) && array_key_exists('installconditions', $rel)) { 1302 $this->_validateInstallConditions($rel['installconditions'], 1303 "<$release><installconditions>"); 1304 } 1305 if (is_array($rel) && array_key_exists('filelist', $rel)) { 1306 if ($rel['filelist']) { 1307 1308 $this->_validateFilelist($rel['filelist'], true); 1309 } 1310 } 1311 } 1312 } 1313 1314 /** 1315 * This is here to allow role extension through plugins 1316 * @param string 1317 */ 1318 function _validateRole($role) 1319 { 1320 return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())); 1321 } 1322 1323 function _pearVersionTooLow($version) 1324 { 1325 $this->_stack->push(__FUNCTION__, 'error', 1326 array('version' => $version), 1327 'This package.xml requires PEAR version %version% to parse properly, we are ' . 1328 'version 1.5.0'); 1329 } 1330 1331 function _invalidTagOrder($oktags, $actual, $root) 1332 { 1333 $this->_stack->push(__FUNCTION__, 'error', 1334 array('oktags' => $oktags, 'actual' => $actual, 'root' => $root), 1335 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"'); 1336 } 1337 1338 function _ignoreNotAllowed($type) 1339 { 1340 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), 1341 '<%type%> is not allowed inside global <contents>, only inside ' . 1342 '<phprelease>/<extbinrelease>/<zendextbinrelease>, use <dir> and <file> only'); 1343 } 1344 1345 function _fileNotAllowed($type) 1346 { 1347 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), 1348 '<%type%> is not allowed inside release <filelist>, only inside ' . 1349 '<contents>, use <ignore> and <install> only'); 1350 } 1351 1352 function _tagMissingAttribute($tag, $attr, $context) 1353 { 1354 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 1355 'attribute' => $attr, 'context' => $context), 1356 'tag <%tag%> in context "%context%" has no attribute "%attribute%"'); 1357 } 1358 1359 function _tagHasNoAttribs($tag, $context) 1360 { 1361 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 1362 'context' => $context), 1363 'tag <%tag%> has no attributes in context "%context%"'); 1364 } 1365 1366 function _invalidInternalStructure() 1367 { 1368 $this->_stack->push(__FUNCTION__, 'exception', array(), 1369 'internal array was not generated by compatible parser, or extreme parser error, cannot continue'); 1370 } 1371 1372 function _invalidFileRole($file, $dir, $role) 1373 { 1374 $this->_stack->push(__FUNCTION__, 'error', array( 1375 'file' => $file, 'dir' => $dir, 'role' => $role, 1376 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())), 1377 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%'); 1378 } 1379 1380 function _invalidFileName($file, $dir) 1381 { 1382 $this->_stack->push(__FUNCTION__, 'error', array( 1383 'file' => $file), 1384 'File "%file%" cannot begin with "."'); 1385 } 1386 1387 function _filelistCannotContainFile($filelist) 1388 { 1389 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), 1390 '<%tag%> can only contain <dir>, contains <file>. Use ' . 1391 '<dir name="/"> as the first dir element'); 1392 } 1393 1394 function _filelistMustContainDir($filelist) 1395 { 1396 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), 1397 '<%tag%> must contain <dir>. Use <dir name="/"> as the ' . 1398 'first dir element'); 1399 } 1400 1401 function _tagCannotBeEmpty($tag) 1402 { 1403 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), 1404 '<%tag%> cannot be empty (<%tag%/>)'); 1405 } 1406 1407 function _UrlOrChannel($type, $name) 1408 { 1409 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 1410 'name' => $name), 1411 'Required dependency <%type%> "%name%" can have either url OR ' . 1412 'channel attributes, and not both'); 1413 } 1414 1415 function _NoChannel($type, $name) 1416 { 1417 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 1418 'name' => $name), 1419 'Required dependency <%type%> "%name%" must have either url OR ' . 1420 'channel attributes'); 1421 } 1422 1423 function _UrlOrChannelGroup($type, $name, $group) 1424 { 1425 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 1426 'name' => $name, 'group' => $group), 1427 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' . 1428 'channel attributes, and not both'); 1429 } 1430 1431 function _NoChannelGroup($type, $name, $group) 1432 { 1433 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 1434 'name' => $name, 'group' => $group), 1435 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' . 1436 'channel attributes'); 1437 } 1438 1439 function _unknownChannel($channel) 1440 { 1441 $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel), 1442 'Unknown channel "%channel%"'); 1443 } 1444 1445 function _noPackageVersion() 1446 { 1447 $this->_stack->push(__FUNCTION__, 'error', array(), 1448 'package.xml <package> tag has no version attribute, or version is not 2.0'); 1449 } 1450 1451 function _NoBundledPackages() 1452 { 1453 $this->_stack->push(__FUNCTION__, 'error', array(), 1454 'No <bundledpackage> tag was found in <contents>, required for bundle packages'); 1455 } 1456 1457 function _AtLeast2BundledPackages() 1458 { 1459 $this->_stack->push(__FUNCTION__, 'error', array(), 1460 'At least 2 packages must be bundled in a bundle package'); 1461 } 1462 1463 function _ChannelOrUri($name) 1464 { 1465 $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), 1466 'Bundled package "%name%" can have either a uri or a channel, not both'); 1467 } 1468 1469 function _noChildTag($child, $tag) 1470 { 1471 $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag), 1472 'Tag <%tag%> is missing child tag <%child%>'); 1473 } 1474 1475 function _invalidVersion($type, $value) 1476 { 1477 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value), 1478 'Version type <%type%> is not a valid version (%value%)'); 1479 } 1480 1481 function _invalidState($type, $value) 1482 { 1483 $states = array('stable', 'beta', 'alpha', 'devel'); 1484 if ($type != 'api') { 1485 $states[] = 'snapshot'; 1486 } 1487 if (strtolower($value) == 'rc') { 1488 $this->_stack->push(__FUNCTION__, 'error', 1489 array('version' => $this->_packageInfo['version']['release']), 1490 'RC is not a state, it is a version postfix, try %version%RC1, stability beta'); 1491 } 1492 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value, 1493 'types' => $states), 1494 'Stability type <%type%> is not a valid stability (%value%), must be one of ' . 1495 '%types%'); 1496 } 1497 1498 function _invalidTask($task, $ret, $file) 1499 { 1500 switch ($ret[0]) { 1501 case PEAR_TASK_ERROR_MISSING_ATTRIB : 1502 $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file); 1503 $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%'; 1504 break; 1505 case PEAR_TASK_ERROR_NOATTRIBS : 1506 $info = array('task' => $task, 'file' => $file); 1507 $msg = 'task <%task%> has no attributes in file %file%'; 1508 break; 1509 case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE : 1510 $info = array('attrib' => $ret[1], 'values' => $ret[3], 1511 'was' => $ret[2], 'task' => $task, 'file' => $file); 1512 $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '. 1513 'in file %file%, expecting one of "%values%"'; 1514 break; 1515 case PEAR_TASK_ERROR_INVALID : 1516 $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file); 1517 $msg = 'task <%task%> in file %file% is invalid because of "%reason%"'; 1518 break; 1519 } 1520 $this->_stack->push(__FUNCTION__, 'error', $info, $msg); 1521 } 1522 1523 function _unknownTask($task, $file) 1524 { 1525 $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file), 1526 'Unknown task "%task%" passed in file <file name="%file%">'); 1527 } 1528 1529 function _subpackageCannotProvideExtension($name) 1530 { 1531 $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), 1532 'Subpackage dependency "%name%" cannot use <providesextension>, ' . 1533 'only package dependencies can use this tag'); 1534 } 1535 1536 function _subpackagesCannotConflict($name) 1537 { 1538 $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), 1539 'Subpackage dependency "%name%" cannot use <conflicts/>, ' . 1540 'only package dependencies can use this tag'); 1541 } 1542 1543 function _cannotProvideExtension($release) 1544 { 1545 $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), 1546 '<%release%> packages cannot use <providesextension>, only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension'); 1547 } 1548 1549 function _mustProvideExtension($release) 1550 { 1551 $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), 1552 '<%release%> packages must use <providesextension> to indicate which PHP extension is provided'); 1553 } 1554 1555 function _cannotHaveSrcpackage($release) 1556 { 1557 $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), 1558 '<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag'); 1559 } 1560 1561 function _mustSrcPackage($release) 1562 { 1563 $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), 1564 '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcpackage>'); 1565 } 1566 1567 function _mustSrcuri($release) 1568 { 1569 $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), 1570 '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcuri>'); 1571 } 1572 1573 function _uriDepsCannotHaveVersioning($type) 1574 { 1575 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), 1576 '%type%: dependencies with a <uri> tag cannot have any versioning information'); 1577 } 1578 1579 function _conflictingDepsCannotHaveVersioning($type) 1580 { 1581 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), 1582 '%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' . 1583 'exclude specific versions of a dependency'); 1584 } 1585 1586 function _DepchannelCannotBeUri($type) 1587 { 1588 $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), 1589 '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' . 1590 'dependencies only'); 1591 } 1592 1593 function _bundledPackagesMustBeFilename() 1594 { 1595 $this->_stack->push(__FUNCTION__, 'error', array(), 1596 '<bundledpackage> tags must contain only the filename of a package release ' . 1597 'in the bundle'); 1598 } 1599 1600 function _binaryPackageMustBePackagename() 1601 { 1602 $this->_stack->push(__FUNCTION__, 'error', array(), 1603 '<binarypackage> tags must contain the name of a package that is ' . 1604 'a compiled version of this extsrc/zendextsrc package'); 1605 } 1606 1607 function _fileNotFound($file) 1608 { 1609 $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), 1610 'File "%file%" in package.xml does not exist'); 1611 } 1612 1613 function _notInContents($file, $tag) 1614 { 1615 $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag), 1616 '<%tag% name="%file%"> is invalid, file is not in <contents>'); 1617 } 1618 1619 function _cannotValidateNoPathSet() 1620 { 1621 $this->_stack->push(__FUNCTION__, 'error', array(), 1622 'Cannot validate files, no path to package file is set (use setPackageFile())'); 1623 } 1624 1625 function _usesroletaskMustHaveChannelOrUri($role, $tag) 1626 { 1627 $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), 1628 '<%tag%> must contain either <uri>, or <channel> and <package>'); 1629 } 1630 1631 function _usesroletaskMustHavePackage($role, $tag) 1632 { 1633 $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), 1634 '<%tag%> must contain <package>'); 1635 } 1636 1637 function _usesroletaskMustHaveRoleTask($tag, $type) 1638 { 1639 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type), 1640 '<%tag%> must contain <%type%> defining the %type% to be used'); 1641 } 1642 1643 function _cannotConflictWithAllOs($type) 1644 { 1645 $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), 1646 '%tag% cannot conflict with all OSes'); 1647 } 1648 1649 function _invalidDepGroupName($name) 1650 { 1651 $this->_stack->push(__FUNCTION__, 'error', array('group' => $name), 1652 'Invalid dependency group name "%name%"'); 1653 } 1654 1655 function _multipleToplevelDirNotAllowed() 1656 { 1657 $this->_stack->push(__FUNCTION__, 'error', array(), 1658 'Multiple top-level <dir> tags are not allowed. Enclose them ' . 1659 'in a <dir name="/">'); 1660 } 1661 1662 function _multipleInstallAs($file) 1663 { 1664 $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), 1665 'Only one <install> tag is allowed for file "%file%"'); 1666 } 1667 1668 function _ignoreAndInstallAs($file) 1669 { 1670 $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), 1671 'Cannot have both <ignore> and <install> tags for file "%file%"'); 1672 } 1673 1674 function _analyzeBundledPackages() 1675 { 1676 if (!$this->_isValid) { 1677 return false; 1678 } 1679 if (!$this->_pf->getPackageType() == 'bundle') { 1680 return false; 1681 } 1682 if (!isset($this->_pf->_packageFile)) { 1683 return false; 1684 } 1685 $dir_prefix = dirname($this->_pf->_packageFile); 1686 $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : 1687 array('PEAR_Common', 'log'); 1688 $info = $this->_pf->getContents(); 1689 $info = $info['bundledpackage']; 1690 if (!is_array($info)) { 1691 $info = array($info); 1692 } 1693 $pkg = &new PEAR_PackageFile($this->_pf->_config); 1694 foreach ($info as $package) { 1695 if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) { 1696 $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package); 1697 $this->_isValid = 0; 1698 continue; 1699 } 1700 call_user_func_array($log, array(1, "Analyzing bundled package $package")); 1701 PEAR::pushErrorHandling(PEAR_ERROR_RETURN); 1702 $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package, 1703 PEAR_VALIDATE_NORMAL); 1704 PEAR::popErrorHandling(); 1705 if (PEAR::isError($ret)) { 1706 call_user_func_array($log, array(0, "ERROR: package $package is not a valid " . 1707 'package')); 1708 $inf = $ret->getUserInfo(); 1709 if (is_array($inf)) { 1710 foreach ($inf as $err) { 1711 call_user_func_array($log, array(1, $err['message'])); 1712 } 1713 } 1714 return false; 1715 } 1716 } 1717 return true; 1718 } 1719 1720 function _analyzePhpFiles() 1721 { 1722 if (!$this->_isValid) { 1723 return false; 1724 } 1725 if (!isset($this->_pf->_packageFile)) { 1726 $this->_cannotValidateNoPathSet(); 1727 return false; 1728 } 1729 $dir_prefix = dirname($this->_pf->_packageFile); 1730 $common = new PEAR_Common; 1731 $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : 1732 array(&$common, 'log'); 1733 $info = $this->_pf->getContents(); 1734 if (!$info || !isset($info['dir']['file'])) { 1735 $this->_tagCannotBeEmpty('contents><dir'); 1736 return false; 1737 } 1738 $info = $info['dir']['file']; 1739 if (isset($info['attribs'])) { 1740 $info = array($info); 1741 } 1742 $provides = array(); 1743 foreach ($info as $fa) { 1744 $fa = $fa['attribs']; 1745 $file = $fa['name']; 1746 if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { 1747 $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); 1748 $this->_isValid = 0; 1749 continue; 1750 } 1751 if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { 1752 call_user_func_array($log, array(1, "Analyzing $file")); 1753 $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); 1754 if ($srcinfo) { 1755 $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); 1756 } 1757 } 1758 } 1759 $this->_packageName = $pn = $this->_pf->getPackage(); 1760 $pnl = strlen($pn); 1761 foreach ($provides as $key => $what) { 1762 if (isset($what['explicit']) || !$what) { 1763 // skip conformance checks if the provides entry is 1764 // specified in the package.xml file 1765 continue; 1766 } 1767 extract($what); 1768 if ($type == 'class') { 1769 if (!strncasecmp($name, $pn, $pnl)) { 1770 continue; 1771 } 1772 $this->_stack->push(__FUNCTION__, 'warning', 1773 array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), 1774 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); 1775 } elseif ($type == 'function') { 1776 if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { 1777 continue; 1778 } 1779 $this->_stack->push(__FUNCTION__, 'warning', 1780 array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), 1781 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); 1782 } 1783 } 1784 return $this->_isValid; 1785 } 1786 1787 /** 1788 * Analyze the source code of the given PHP file 1789 * 1790 * @param string Filename of the PHP file 1791 * @param boolean whether to analyze $file as the file contents 1792 * @return mixed 1793 */ 1794 function analyzeSourceCode($file, $string = false) 1795 { 1796 if (!function_exists("token_get_all")) { 1797 $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), 1798 'Parser error: token_get_all() function must exist to analyze source code'); 1799 return false; 1800 } 1801 if (!defined('T_DOC_COMMENT')) { 1802 define('T_DOC_COMMENT', T_COMMENT); 1803 } 1804 if (!defined('T_INTERFACE')) { 1805 define('T_INTERFACE', -1); 1806 } 1807 if (!defined('T_IMPLEMENTS')) { 1808 define('T_IMPLEMENTS', -1); 1809 } 1810 if ($string) { 1811 $contents = $file; 1812 } else { 1813 if (!$fp = @fopen($file, "r")) { 1814 return false; 1815 } 1816 fclose($fp); 1817 $contents = file_get_contents($file); 1818 } 1819 $tokens = token_get_all($contents); 1820 /* 1821 for ($i = 0; $i < sizeof($tokens); $i++) { 1822 @list($token, $data) = $tokens[$i]; 1823 if (is_string($token)) { 1824 var_dump($token); 1825 } else { 1826 print token_name($token) . ' '; 1827 var_dump(rtrim($data)); 1828 } 1829 } 1830 */ 1831 $look_for = 0; 1832 $paren_level = 0; 1833 $bracket_level = 0; 1834 $brace_level = 0; 1835 $lastphpdoc = ''; 1836 $current_class = ''; 1837 $current_interface = ''; 1838 $current_class_level = -1; 1839 $current_function = ''; 1840 $current_function_level = -1; 1841 $declared_classes = array(); 1842 $declared_interfaces = array(); 1843 $declared_functions = array(); 1844 $declared_methods = array(); 1845 $used_classes = array(); 1846 $used_functions = array(); 1847 $extends = array(); 1848 $implements = array(); 1849 $nodeps = array(); 1850 $inquote = false; 1851 $interface = false; 1852 for ($i = 0; $i < sizeof($tokens); $i++) { 1853 if (is_array($tokens[$i])) { 1854 list($token, $data) = $tokens[$i]; 1855 } else { 1856 $token = $tokens[$i]; 1857 $data = ''; 1858 } 1859 if ($inquote) { 1860 if ($token != '"' && $token != T_END_HEREDOC) { 1861 continue; 1862 } else { 1863 $inquote = false; 1864 continue; 1865 } 1866 } 1867 switch ($token) { 1868 case T_WHITESPACE : 1869 continue; 1870 case ';': 1871 if ($interface) { 1872 $current_function = ''; 1873 $current_function_level = -1; 1874 } 1875 break; 1876 case '"': 1877 case T_START_HEREDOC: 1878 $inquote = true; 1879 break; 1880 case T_CURLY_OPEN: 1881 case T_DOLLAR_OPEN_CURLY_BRACES: 1882 case '{': $brace_level++; continue 2; 1883 case '}': 1884 $brace_level--; 1885 if ($current_class_level == $brace_level) { 1886 $current_class = ''; 1887 $current_class_level = -1; 1888 } 1889 if ($current_function_level == $brace_level) { 1890 $current_function = ''; 1891 $current_function_level = -1; 1892 } 1893 continue 2; 1894 case '[': $bracket_level++; continue 2; 1895 case ']': $bracket_level--; continue 2; 1896 case '(': $paren_level++; continue 2; 1897 case ')': $paren_level--; continue 2; 1898 case T_INTERFACE: 1899 $interface = true; 1900 case T_CLASS: 1901 if (($current_class_level != -1) || ($current_function_level != -1)) { 1902 $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), 1903 'Parser error: invalid PHP found in file "%file%"'); 1904 return false; 1905 } 1906 case T_FUNCTION: 1907 case T_NEW: 1908 case T_EXTENDS: 1909 case T_IMPLEMENTS: 1910 $look_for = $token; 1911 continue 2; 1912 case T_STRING: 1913 if (version_compare(zend_version(), '2.0', '<')) { 1914 if (in_array(strtolower($data), 1915 array('public', 'private', 'protected', 'abstract', 1916 'interface', 'implements', 'throw') 1917 )) { 1918 $this->_stack->push(__FUNCTION__, 'warning', array( 1919 'file' => $file), 1920 'Error, PHP5 token encountered in %file%,' . 1921 ' analysis should be in PHP5'); 1922 } 1923 } 1924 if ($look_for == T_CLASS) { 1925 $current_class = $data; 1926 $current_class_level = $brace_level; 1927 $declared_classes[] = $current_class; 1928 } elseif ($look_for == T_INTERFACE) { 1929 $current_interface = $data; 1930 $current_class_level = $brace_level; 1931 $declared_interfaces[] = $current_interface; 1932 } elseif ($look_for == T_IMPLEMENTS) { 1933 $implements[$current_class] = $data; 1934 } elseif ($look_for == T_EXTENDS) { 1935 $extends[$current_class] = $data; 1936 } elseif ($look_for == T_FUNCTION) { 1937 if ($current_class) { 1938 $current_function = "$current_class::$data"; 1939 $declared_methods[$current_class][] = $data; 1940 } elseif ($current_interface) { 1941 $current_function = "$current_interface::$data"; 1942 $declared_methods[$current_interface][] = $data; 1943 } else { 1944 $current_function = $data; 1945 $declared_functions[] = $current_function; 1946 } 1947 $current_function_level = $brace_level; 1948 $m = array(); 1949 } elseif ($look_for == T_NEW) { 1950 $used_classes[$data] = true; 1951 } 1952 $look_for = 0; 1953 continue 2; 1954 case T_VARIABLE: 1955 $look_for = 0; 1956 continue 2; 1957 case T_DOC_COMMENT: 1958 case T_COMMENT: 1959 if (preg_match('!^/\*\*\s!', $data)) { 1960 $lastphpdoc = $data; 1961 if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { 1962 $nodeps = array_merge($nodeps, $m[1]); 1963 } 1964 } 1965 continue 2; 1966 case T_DOUBLE_COLON: 1967 if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { 1968 $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file), 1969 'Parser error: invalid PHP found in file "%file%"'); 1970 return false; 1971 } 1972 $class = $tokens[$i - 1][1]; 1973 if (strtolower($class) != 'parent') { 1974 $used_classes[$class] = true; 1975 } 1976 continue 2; 1977 } 1978 } 1979 return array( 1980 "source_file" => $file, 1981 "declared_classes" => $declared_classes, 1982 "declared_interfaces" => $declared_interfaces, 1983 "declared_methods" => $declared_methods, 1984 "declared_functions" => $declared_functions, 1985 "used_classes" => array_diff(array_keys($used_classes), $nodeps), 1986 "inheritance" => $extends, 1987 "implements" => $implements, 1988 ); 1989 } 1990 1991 /** 1992 * Build a "provides" array from data returned by 1993 * analyzeSourceCode(). The format of the built array is like 1994 * this: 1995 * 1996 * array( 1997 * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), 1998 * ... 1999 * ) 2000 * 2001 * 2002 * @param array $srcinfo array with information about a source file 2003 * as returned by the analyzeSourceCode() method. 2004 * 2005 * @return void 2006 * 2007 * @access private 2008 * 2009 */ 2010 function _buildProvidesArray($srcinfo) 2011 { 2012 if (!$this->_isValid) { 2013 return array(); 2014 } 2015 $providesret = array(); 2016 $file = basename($srcinfo['source_file']); 2017 $pn = $this->_pf->getPackage(); 2018 $pnl = strlen($pn); 2019 foreach ($srcinfo['declared_classes'] as $class) { 2020 $key = "class;$class"; 2021 if (isset($providesret[$key])) { 2022 continue; 2023 } 2024 $providesret[$key] = 2025 array('file'=> $file, 'type' => 'class', 'name' => $class); 2026 if (isset($srcinfo['inheritance'][$class])) { 2027 $providesret[$key]['extends'] = 2028 $srcinfo['inheritance'][$class]; 2029 } 2030 } 2031 foreach ($srcinfo['declared_methods'] as $class => $methods) { 2032 foreach ($methods as $method) { 2033 $function = "$class::$method"; 2034 $key = "function;$function"; 2035 if ($method{0} == '_' || !strcasecmp($method, $class) || 2036 isset($providesret[$key])) { 2037 continue; 2038 } 2039 $providesret[$key] = 2040 array('file'=> $file, 'type' => 'function', 'name' => $function); 2041 } 2042 } 2043 2044 foreach ($srcinfo['declared_functions'] as $function) { 2045 $key = "function;$function"; 2046 if ($function{0} == '_' || isset($providesret[$key])) { 2047 continue; 2048 } 2049 if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { 2050 $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; 2051 } 2052 $providesret[$key] = 2053 array('file'=> $file, 'type' => 'function', 'name' => $function); 2054 } 2055 return $providesret; 2056 } 2057 } 2058 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |