1<?php 2/** 3 * PEAR_Common, the base class for the PEAR Installer 4 * 5 * PHP versions 4 and 5 6 * 7 * LICENSE: This source file is subject to version 3.0 of the PHP license 8 * that is available through the world-wide-web at the following URI: 9 * http://www.php.net/license/3_0.txt. If you did not receive a copy of 10 * the PHP License and are unable to obtain it through the web, please 11 * send a note to license@php.net so we can mail you a copy immediately. 12 * 13 * @category pear 14 * @package PEAR 15 * @author Stig Bakken <ssb@php.net> 16 * @author Tomas V. V. Cox <cox@idecnet.com> 17 * @author Greg Beaver <cellog@php.net> 18 * @copyright 1997-2006 The PHP Group 19 * @license http://www.php.net/license/3_0.txt PHP License 3.0 20 * @version CVS: $Id: Common.php,v 1.155 2006/03/02 18:14:12 cellog Exp $ 21 * @link http://pear.php.net/package/PEAR 22 * @since File available since Release 0.1.0 23 * @deprecated File deprecated since Release 1.4.0a1 24 */ 25 26/** 27 * Include error handling 28 */ 29require_once 'PEAR.php'; 30 31// {{{ constants and globals 32 33/** 34 * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() 35 */ 36define('PEAR_COMMON_ERROR_INVALIDPHP', 1); 37define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); 38define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/'); 39 40// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 41define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); 42define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '$/i'); 43 44// XXX far from perfect :-) 45define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . 46 ')(-([.0-9a-zA-Z]+))?'); 47define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . 48 '$/'); 49 50define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); 51define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '$/'); 52 53// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED 54define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); 55define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '$/i'); 56 57define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' 58 . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); 59define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '$/i'); 60 61define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' 62 . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); 63define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '$/'); 64 65/** 66 * List of temporary files and directories registered by 67 * PEAR_Common::addTempFile(). 68 * @var array 69 */ 70$GLOBALS['_PEAR_Common_tempfiles'] = array(); 71 72/** 73 * Valid maintainer roles 74 * @var array 75 */ 76$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); 77 78/** 79 * Valid release states 80 * @var array 81 */ 82$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); 83 84/** 85 * Valid dependency types 86 * @var array 87 */ 88$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); 89 90/** 91 * Valid dependency relations 92 * @var array 93 */ 94$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); 95 96/** 97 * Valid file roles 98 * @var array 99 */ 100$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); 101 102/** 103 * Valid replacement types 104 * @var array 105 */ 106$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); 107 108/** 109 * Valid "provide" types 110 * @var array 111 */ 112$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); 113 114/** 115 * Valid "provide" types 116 * @var array 117 */ 118$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); 119 120// }}} 121 122/** 123 * Class providing common functionality for PEAR administration classes. 124 * @category pear 125 * @package PEAR 126 * @author Stig Bakken <ssb@php.net> 127 * @author Tomas V. V. Cox <cox@idecnet.com> 128 * @author Greg Beaver <cellog@php.net> 129 * @copyright 1997-2006 The PHP Group 130 * @license http://www.php.net/license/3_0.txt PHP License 3.0 131 * @version Release: 1.4.11 132 * @link http://pear.php.net/package/PEAR 133 * @since Class available since Release 1.4.0a1 134 * @deprecated This class will disappear, and its components will be spread 135 * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 136 */ 137class PEAR_Common extends PEAR 138{ 139 // {{{ properties 140 141 /** stack of elements, gives some sort of XML context */ 142 var $element_stack = array(); 143 144 /** name of currently parsed XML element */ 145 var $current_element; 146 147 /** array of attributes of the currently parsed XML element */ 148 var $current_attributes = array(); 149 150 /** assoc with information about a package */ 151 var $pkginfo = array(); 152 153 /** 154 * User Interface object (PEAR_Frontend_* class). If null, 155 * the log() method uses print. 156 * @var object 157 */ 158 var $ui = null; 159 160 /** 161 * Configuration object (PEAR_Config). 162 * @var object 163 */ 164 var $config = null; 165 166 var $current_path = null; 167 168 /** 169 * PEAR_SourceAnalyzer instance 170 * @var object 171 */ 172 var $source_analyzer = null; 173 /** 174 * Flag variable used to mark a valid package file 175 * @var boolean 176 * @access private 177 */ 178 var $_validPackageFile; 179 180 // }}} 181 182 // {{{ constructor 183 184 /** 185 * PEAR_Common constructor 186 * 187 * @access public 188 */ 189 function PEAR_Common() 190 { 191 parent::PEAR(); 192 $this->config = &PEAR_Config::singleton(); 193 $this->debug = $this->config->get('verbose'); 194 } 195 196 // }}} 197 // {{{ destructor 198 199 /** 200 * PEAR_Common destructor 201 * 202 * @access private 203 */ 204 function _PEAR_Common() 205 { 206 // doesn't work due to bug #14744 207 //$tempfiles = $this->_tempfiles; 208 $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; 209 while ($file = array_shift($tempfiles)) { 210 if (@is_dir($file)) { 211 if (!class_exists('System')) { 212 require_once 'System.php'; 213 } 214 System::rm(array('-rf', $file)); 215 } elseif (file_exists($file)) { 216 unlink($file); 217 } 218 } 219 } 220 221 // }}} 222 // {{{ addTempFile() 223 224 /** 225 * Register a temporary file or directory. When the destructor is 226 * executed, all registered temporary files and directories are 227 * removed. 228 * 229 * @param string $file name of file or directory 230 * 231 * @return void 232 * 233 * @access public 234 */ 235 function addTempFile($file) 236 { 237 if (!class_exists('PEAR_Frontend')) { 238 require_once 'PEAR/Frontend.php'; 239 } 240 PEAR_Frontend::addTempFile($file); 241 } 242 243 // }}} 244 // {{{ mkDirHier() 245 246 /** 247 * Wrapper to System::mkDir(), creates a directory as well as 248 * any necessary parent directories. 249 * 250 * @param string $dir directory name 251 * 252 * @return bool TRUE on success, or a PEAR error 253 * 254 * @access public 255 */ 256 function mkDirHier($dir) 257 { 258 $this->log(2, "+ create dir $dir"); 259 if (!class_exists('System')) { 260 require_once 'System.php'; 261 } 262 return System::mkDir(array('-p', $dir)); 263 } 264 265 // }}} 266 // {{{ log() 267 268 /** 269 * Logging method. 270 * 271 * @param int $level log level (0 is quiet, higher is noisier) 272 * @param string $msg message to write to the log 273 * 274 * @return void 275 * 276 * @access public 277 * @static 278 */ 279 function log($level, $msg, $append_crlf = true) 280 { 281 if ($this->debug >= $level) { 282 if (!class_exists('PEAR_Frontend')) { 283 require_once 'PEAR/Frontend.php'; 284 } 285 $ui = &PEAR_Frontend::singleton(); 286 if (is_a($ui, 'PEAR_Frontend')) { 287 $ui->log($msg, $append_crlf); 288 } else { 289 print "$msg\n"; 290 } 291 } 292 } 293 294 // }}} 295 // {{{ mkTempDir() 296 297 /** 298 * Create and register a temporary directory. 299 * 300 * @param string $tmpdir (optional) Directory to use as tmpdir. 301 * Will use system defaults (for example 302 * /tmp or c:\windows\temp) if not specified 303 * 304 * @return string name of created directory 305 * 306 * @access public 307 */ 308 function mkTempDir($tmpdir = '') 309 { 310 if ($tmpdir) { 311 $topt = array('-t', $tmpdir); 312 } else { 313 $topt = array(); 314 } 315 $topt = array_merge($topt, array('-d', 'pear')); 316 if (!class_exists('System')) { 317 require_once 'System.php'; 318 } 319 if (!$tmpdir = System::mktemp($topt)) { 320 return false; 321 } 322 $this->addTempFile($tmpdir); 323 return $tmpdir; 324 } 325 326 // }}} 327 // {{{ setFrontendObject() 328 329 /** 330 * Set object that represents the frontend to be used. 331 * 332 * @param object Reference of the frontend object 333 * @return void 334 * @access public 335 */ 336 function setFrontendObject(&$ui) 337 { 338 $this->ui = &$ui; 339 } 340 341 // }}} 342 343 // {{{ infoFromTgzFile() 344 345 /** 346 * Returns information about a package file. Expects the name of 347 * a gzipped tar file as input. 348 * 349 * @param string $file name of .tgz file 350 * 351 * @return array array with package information 352 * 353 * @access public 354 * @deprecated use PEAR_PackageFile->fromTgzFile() instead 355 * 356 */ 357 function infoFromTgzFile($file) 358 { 359 $packagefile = &new PEAR_PackageFile($this->config); 360 $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); 361 if (PEAR::isError($pf)) { 362 $errs = $pf->getUserinfo(); 363 if (is_array($errs)) { 364 foreach ($errs as $error) { 365 $e = $this->raiseError($error['message'], $error['code'], null, null, $error); 366 } 367 } 368 return $pf; 369 } 370 return $this->_postProcessValidPackagexml($pf); 371 } 372 373 // }}} 374 // {{{ infoFromDescriptionFile() 375 376 /** 377 * Returns information about a package file. Expects the name of 378 * a package xml file as input. 379 * 380 * @param string $descfile name of package xml file 381 * 382 * @return array array with package information 383 * 384 * @access public 385 * @deprecated use PEAR_PackageFile->fromPackageFile() instead 386 * 387 */ 388 function infoFromDescriptionFile($descfile) 389 { 390 $packagefile = &new PEAR_PackageFile($this->config); 391 $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); 392 if (PEAR::isError($pf)) { 393 $errs = $pf->getUserinfo(); 394 if (is_array($errs)) { 395 foreach ($errs as $error) { 396 $e = $this->raiseError($error['message'], $error['code'], null, null, $error); 397 } 398 } 399 return $pf; 400 } 401 return $this->_postProcessValidPackagexml($pf); 402 } 403 404 // }}} 405 // {{{ infoFromString() 406 407 /** 408 * Returns information about a package file. Expects the contents 409 * of a package xml file as input. 410 * 411 * @param string $data contents of package.xml file 412 * 413 * @return array array with package information 414 * 415 * @access public 416 * @deprecated use PEAR_PackageFile->fromXmlstring() instead 417 * 418 */ 419 function infoFromString($data) 420 { 421 $packagefile = &new PEAR_PackageFile($this->config); 422 $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); 423 if (PEAR::isError($pf)) { 424 $errs = $pf->getUserinfo(); 425 if (is_array($errs)) { 426 foreach ($errs as $error) { 427 $e = $this->raiseError($error['message'], $error['code'], null, null, $error); 428 } 429 } 430 return $pf; 431 } 432 return $this->_postProcessValidPackagexml($pf); 433 } 434 // }}} 435 436 /** 437 * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 438 * @return array 439 */ 440 function _postProcessValidPackagexml(&$pf) 441 { 442 if (is_a($pf, 'PEAR_PackageFile_v2')) { 443 // sort of make this into a package.xml 1.0-style array 444 // changelog is not converted to old format. 445 $arr = $pf->toArray(true); 446 $arr = array_merge($arr, $arr['old']); 447 unset($arr['old']); 448 unset($arr['xsdversion']); 449 unset($arr['contents']); 450 unset($arr['compatible']); 451 unset($arr['channel']); 452 unset($arr['uri']); 453 unset($arr['dependencies']); 454 unset($arr['phprelease']); 455 unset($arr['extsrcrelease']); 456 unset($arr['extbinrelease']); 457 unset($arr['bundle']); 458 unset($arr['lead']); 459 unset($arr['developer']); 460 unset($arr['helper']); 461 unset($arr['contributor']); 462 $arr['filelist'] = $pf->getFilelist(); 463 $this->pkginfo = $arr; 464 return $arr; 465 } else { 466 $this->pkginfo = $pf->toArray(); 467 return $this->pkginfo; 468 } 469 } 470 // {{{ infoFromAny() 471 472 /** 473 * Returns package information from different sources 474 * 475 * This method is able to extract information about a package 476 * from a .tgz archive or from a XML package definition file. 477 * 478 * @access public 479 * @param string Filename of the source ('package.xml', '<package>.tgz') 480 * @return string 481 * @deprecated use PEAR_PackageFile->fromAnyFile() instead 482 */ 483 function infoFromAny($info) 484 { 485 if (is_string($info) && file_exists($info)) { 486 $packagefile = &new PEAR_PackageFile($this->config); 487 $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); 488 if (PEAR::isError($pf)) { 489 $errs = $pf->getUserinfo(); 490 if (is_array($errs)) { 491 foreach ($errs as $error) { 492 $e = $this->raiseError($error['message'], $error['code'], null, null, $error); 493 } 494 } 495 return $pf; 496 } 497 return $this->_postProcessValidPackagexml($pf); 498 } 499 return $info; 500 } 501 502 // }}} 503 // {{{ xmlFromInfo() 504 505 /** 506 * Return an XML document based on the package info (as returned 507 * by the PEAR_Common::infoFrom* methods). 508 * 509 * @param array $pkginfo package info 510 * 511 * @return string XML data 512 * 513 * @access public 514 * @deprecated use a PEAR_PackageFile_v* object's generator instead 515 */ 516 function xmlFromInfo($pkginfo) 517 { 518 $config = &PEAR_Config::singleton(); 519 $packagefile = &new PEAR_PackageFile($config); 520 $pf = &$packagefile->fromArray($pkginfo); 521 $gen = &$pf->getDefaultGenerator(); 522 return $gen->toXml(PEAR_VALIDATE_PACKAGING); 523 } 524 525 // }}} 526 // {{{ validatePackageInfo() 527 528 /** 529 * Validate XML package definition file. 530 * 531 * @param string $info Filename of the package archive or of the 532 * package definition file 533 * @param array $errors Array that will contain the errors 534 * @param array $warnings Array that will contain the warnings 535 * @param string $dir_prefix (optional) directory where source files 536 * may be found, or empty if they are not available 537 * @access public 538 * @return boolean 539 * @deprecated use the validation of PEAR_PackageFile objects 540 */ 541 function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') 542 { 543 $config = &PEAR_Config::singleton(); 544 $packagefile = &new PEAR_PackageFile($config); 545 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); 546 if (strpos($info, '<?xml') !== false) { 547 $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); 548 } else { 549 $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); 550 } 551 PEAR::staticPopErrorHandling(); 552 if (PEAR::isError($pf)) { 553 $errs = $pf->getUserinfo(); 554 if (is_array($errs)) { 555 foreach ($errs as $error) { 556 if ($error['level'] == 'error') { 557 $errors[] = $error['message']; 558 } else { 559 $warnings[] = $error['message']; 560 } 561 } 562 } 563 return false; 564 } 565 return true; 566 } 567 568 // }}} 569 // {{{ buildProvidesArray() 570 571 /** 572 * Build a "provides" array from data returned by 573 * analyzeSourceCode(). The format of the built array is like 574 * this: 575 * 576 * array( 577 * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), 578 * ... 579 * ) 580 * 581 * 582 * @param array $srcinfo array with information about a source file 583 * as returned by the analyzeSourceCode() method. 584 * 585 * @return void 586 * 587 * @access public 588 * 589 */ 590 function buildProvidesArray($srcinfo) 591 { 592 $file = basename($srcinfo['source_file']); 593 $pn = ''; 594 if (isset($this->_packageName)) { 595 $pn = $this->_packageName; 596 } 597 $pnl = strlen($pn); 598 foreach ($srcinfo['declared_classes'] as $class) { 599 $key = "class;$class"; 600 if (isset($this->pkginfo['provides'][$key])) { 601 continue; 602 } 603 $this->pkginfo['provides'][$key] = 604 array('file'=> $file, 'type' => 'class', 'name' => $class); 605 if (isset($srcinfo['inheritance'][$class])) { 606 $this->pkginfo['provides'][$key]['extends'] = 607 $srcinfo['inheritance'][$class]; 608 } 609 } 610 foreach ($srcinfo['declared_methods'] as $class => $methods) { 611 foreach ($methods as $method) { 612 $function = "$class::$method"; 613 $key = "function;$function"; 614 if ($method{0} == '_' || !strcasecmp($method, $class) || 615 isset($this->pkginfo['provides'][$key])) { 616 continue; 617 } 618 $this->pkginfo['provides'][$key] = 619 array('file'=> $file, 'type' => 'function', 'name' => $function); 620 } 621 } 622 623 foreach ($srcinfo['declared_functions'] as $function) { 624 $key = "function;$function"; 625 if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { 626 continue; 627 } 628 if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { 629 $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; 630 } 631 $this->pkginfo['provides'][$key] = 632 array('file'=> $file, 'type' => 'function', 'name' => $function); 633 } 634 } 635 636 // }}} 637 // {{{ analyzeSourceCode() 638 639 /** 640 * Analyze the source code of the given PHP file 641 * 642 * @param string Filename of the PHP file 643 * @return mixed 644 * @access public 645 */ 646 function analyzeSourceCode($file) 647 { 648 if (!function_exists("token_get_all")) { 649 return false; 650 } 651 if (!defined('T_DOC_COMMENT')) { 652 define('T_DOC_COMMENT', T_COMMENT); 653 } 654 if (!defined('T_INTERFACE')) { 655 define('T_INTERFACE', -1); 656 } 657 if (!defined('T_IMPLEMENTS')) { 658 define('T_IMPLEMENTS', -1); 659 } 660 if (!$fp = @fopen($file, "r")) { 661 return false; 662 } 663 if (function_exists('file_get_contents')) { 664 fclose($fp); 665 $contents = file_get_contents($file); 666 } else { 667 $contents = fread($fp, filesize($file)); 668 fclose($fp); 669 } 670 $tokens = token_get_all($contents); 671/* 672 for ($i = 0; $i < sizeof($tokens); $i++) { 673 @list($token, $data) = $tokens[$i]; 674 if (is_string($token)) { 675 var_dump($token); 676 } else { 677 print token_name($token) . ' '; 678 var_dump(rtrim($data)); 679 } 680 } 681*/ 682 $look_for = 0; 683 $paren_level = 0; 684 $bracket_level = 0; 685 $brace_level = 0; 686 $lastphpdoc = ''; 687 $current_class = ''; 688 $current_interface = ''; 689 $current_class_level = -1; 690 $current_function = ''; 691 $current_function_level = -1; 692 $declared_classes = array(); 693 $declared_interfaces = array(); 694 $declared_functions = array(); 695 $declared_methods = array(); 696 $used_classes = array(); 697 $used_functions = array(); 698 $extends = array(); 699 $implements = array(); 700 $nodeps = array(); 701 $inquote = false; 702 $interface = false; 703 for ($i = 0; $i < sizeof($tokens); $i++) { 704 if (is_array($tokens[$i])) { 705 list($token, $data) = $tokens[$i]; 706 } else { 707 $token = $tokens[$i]; 708 $data = ''; 709 } 710 if ($inquote) { 711 if ($token != '"') { 712 continue; 713 } else { 714 $inquote = false; 715 continue; 716 } 717 } 718 switch ($token) { 719 case T_WHITESPACE: 720 continue; 721 case ';': 722 if ($interface) { 723 $current_function = ''; 724 $current_function_level = -1; 725 } 726 break; 727 case '"': 728 $inquote = true; 729 break; 730 case T_CURLY_OPEN: 731 case T_DOLLAR_OPEN_CURLY_BRACES: 732 case '{': $brace_level++; continue 2; 733 case '}': 734 $brace_level--; 735 if ($current_class_level == $brace_level) { 736 $current_class = ''; 737 $current_class_level = -1; 738 } 739 if ($current_function_level == $brace_level) { 740 $current_function = ''; 741 $current_function_level = -1; 742 } 743 continue 2; 744 case '[': $bracket_level++; continue 2; 745 case ']': $bracket_level--; continue 2; 746 case '(': $paren_level++; continue 2; 747 case ')': $paren_level--; continue 2; 748 case T_INTERFACE: 749 $interface = true; 750 case T_CLASS: 751 if (($current_class_level != -1) || ($current_function_level != -1)) { 752 PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", 753 PEAR_COMMON_ERROR_INVALIDPHP); 754 return false; 755 } 756 case T_FUNCTION: 757 case T_NEW: 758 case T_EXTENDS: 759 case T_IMPLEMENTS: 760 $look_for = $token; 761 continue 2; 762 case T_STRING: 763 if (version_compare(zend_version(), '2.0', '<')) { 764 if (in_array(strtolower($data), 765 array('public', 'private', 'protected', 'abstract', 766 'interface', 'implements', 'throw') 767 )) { 768 PEAR::raiseError('Error: PHP5 token encountered in ' . $file . 769 'packaging should be done in PHP 5'); 770 return false; 771 } 772 } 773 if ($look_for == T_CLASS) { 774 $current_class = $data; 775 $current_class_level = $brace_level; 776 $declared_classes[] = $current_class; 777 } elseif ($look_for == T_INTERFACE) { 778 $current_interface = $data; 779 $current_class_level = $brace_level; 780 $declared_interfaces[] = $current_interface; 781 } elseif ($look_for == T_IMPLEMENTS) { 782 $implements[$current_class] = $data; 783 } elseif ($look_for == T_EXTENDS) { 784 $extends[$current_class] = $data; 785 } elseif ($look_for == T_FUNCTION) { 786 if ($current_class) { 787 $current_function = "$current_class::$data"; 788 $declared_methods[$current_class][] = $data; 789 } elseif ($current_interface) { 790 $current_function = "$current_interface::$data"; 791 $declared_methods[$current_interface][] = $data; 792 } else { 793 $current_function = $data; 794 $declared_functions[] = $current_function; 795 } 796 $current_function_level = $brace_level; 797 $m = array(); 798 } elseif ($look_for == T_NEW) { 799 $used_classes[$data] = true; 800 } 801 $look_for = 0; 802 continue 2; 803 case T_VARIABLE: 804 $look_for = 0; 805 continue 2; 806 case T_DOC_COMMENT: 807 case T_COMMENT: 808 if (preg_match('!^/\*\*\s!', $data)) { 809 $lastphpdoc = $data; 810 if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { 811 $nodeps = array_merge($nodeps, $m[1]); 812 } 813 } 814 continue 2; 815 case T_DOUBLE_COLON: 816 if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { 817 PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", 818 PEAR_COMMON_ERROR_INVALIDPHP); 819 return false; 820 } 821 $class = $tokens[$i - 1][1]; 822 if (strtolower($class) != 'parent') { 823 $used_classes[$class] = true; 824 } 825 continue 2; 826 } 827 } 828 return array( 829 "source_file" => $file, 830 "declared_classes" => $declared_classes, 831 "declared_interfaces" => $declared_interfaces, 832 "declared_methods" => $declared_methods, 833 "declared_functions" => $declared_functions, 834 "used_classes" => array_diff(array_keys($used_classes), $nodeps), 835 "inheritance" => $extends, 836 "implements" => $implements, 837 ); 838 } 839 840 // }}} 841 // {{{ betterStates() 842 843 /** 844 * Return an array containing all of the states that are more stable than 845 * or equal to the passed in state 846 * 847 * @param string Release state 848 * @param boolean Determines whether to include $state in the list 849 * @return false|array False if $state is not a valid release state 850 */ 851 function betterStates($state, $include = false) 852 { 853 static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); 854 $i = array_search($state, $states); 855 if ($i === false) { 856 return false; 857 } 858 if ($include) { 859 $i--; 860 } 861 return array_slice($states, $i + 1); 862 } 863 864 // }}} 865 // {{{ detectDependencies() 866 867 function detectDependencies($any, $status_callback = null) 868 { 869 if (!function_exists("token_get_all")) { 870 return false; 871 } 872 if (PEAR::isError($info = $this->infoFromAny($any))) { 873 return $this->raiseError($info); 874 } 875 if (!is_array($info)) { 876 return false; 877 } 878 $deps = array(); 879 $used_c = $decl_c = $decl_f = $decl_m = array(); 880 foreach ($info['filelist'] as $file => $fa) { 881 $tmp = $this->analyzeSourceCode($file); 882 $used_c = @array_merge($used_c, $tmp['used_classes']); 883 $decl_c = @array_merge($decl_c, $tmp['declared_classes']); 884 $decl_f = @array_merge($decl_f, $tmp['declared_functions']); 885 $decl_m = @array_merge($decl_m, $tmp['declared_methods']); 886 $inheri = @array_merge($inheri, $tmp['inheritance']); 887 } 888 $used_c = array_unique($used_c); 889 $decl_c = array_unique($decl_c); 890 $undecl_c = array_diff($used_c, $decl_c); 891 return array('used_classes' => $used_c, 892 'declared_classes' => $decl_c, 893 'declared_methods' => $decl_m, 894 'declared_functions' => $decl_f, 895 'undeclared_classes' => $undecl_c, 896 'inheritance' => $inheri, 897 ); 898 } 899 900 // }}} 901 // {{{ getUserRoles() 902 903 /** 904 * Get the valid roles for a PEAR package maintainer 905 * 906 * @return array 907 * @static 908 */ 909 function getUserRoles() 910 { 911 return $GLOBALS['_PEAR_Common_maintainer_roles']; 912 } 913 914 // }}} 915 // {{{ getReleaseStates() 916 917 /** 918 * Get the valid package release states of packages 919 * 920 * @return array 921 * @static 922 */ 923 function getReleaseStates() 924 { 925 return $GLOBALS['_PEAR_Common_release_states']; 926 } 927 928 // }}} 929 // {{{ getDependencyTypes() 930 931 /** 932 * Get the implemented dependency types (php, ext, pkg etc.) 933 * 934 * @return array 935 * @static 936 */ 937 function getDependencyTypes() 938 { 939 return $GLOBALS['_PEAR_Common_dependency_types']; 940 } 941 942 // }}} 943 // {{{ getDependencyRelations() 944 945 /** 946 * Get the implemented dependency relations (has, lt, ge etc.) 947 * 948 * @return array 949 * @static 950 */ 951 function getDependencyRelations() 952 { 953 return $GLOBALS['_PEAR_Common_dependency_relations']; 954 } 955 956 // }}} 957 // {{{ getFileRoles() 958 959 /** 960 * Get the implemented file roles 961 * 962 * @return array 963 * @static 964 */ 965 function getFileRoles() 966 { 967 return $GLOBALS['_PEAR_Common_file_roles']; 968 } 969 970 // }}} 971 // {{{ getReplacementTypes() 972 973 /** 974 * Get the implemented file replacement types in 975 * 976 * @return array 977 * @static 978 */ 979 function getReplacementTypes() 980 { 981 return $GLOBALS['_PEAR_Common_replacement_types']; 982 } 983 984 // }}} 985 // {{{ getProvideTypes() 986 987 /** 988 * Get the implemented file replacement types in 989 * 990 * @return array 991 * @static 992 */ 993 function getProvideTypes() 994 { 995 return $GLOBALS['_PEAR_Common_provide_types']; 996 } 997 998 // }}} 999 // {{{ getScriptPhases() 1000 1001 /** 1002 * Get the implemented file replacement types in 1003 * 1004 * @return array 1005 * @static 1006 */ 1007 function getScriptPhases() 1008 { 1009 return $GLOBALS['_PEAR_Common_script_phases']; 1010 } 1011 1012 // }}} 1013 // {{{ validPackageName() 1014 1015 /** 1016 * Test whether a string contains a valid package name. 1017 * 1018 * @param string $name the package name to test 1019 * 1020 * @return bool 1021 * 1022 * @access public 1023 */ 1024 function validPackageName($name) 1025 { 1026 return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); 1027 } 1028 1029 1030 // }}} 1031 // {{{ validPackageVersion() 1032 1033 /** 1034 * Test whether a string contains a valid package version. 1035 * 1036 * @param string $ver the package version to test 1037 * 1038 * @return bool 1039 * 1040 * @access public 1041 */ 1042 function validPackageVersion($ver) 1043 { 1044 return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); 1045 } 1046 1047 1048 // }}} 1049 1050 // {{{ downloadHttp() 1051 1052 /** 1053 * Download a file through HTTP. Considers suggested file name in 1054 * Content-disposition: header and can run a callback function for 1055 * different events. The callback will be called with two 1056 * parameters: the callback type, and parameters. The implemented 1057 * callback types are: 1058 * 1059 * 'setup' called at the very beginning, parameter is a UI object 1060 * that should be used for all output 1061 * 'message' the parameter is a string with an informational message 1062 * 'saveas' may be used to save with a different file name, the 1063 * parameter is the filename that is about to be used. 1064 * If a 'saveas' callback returns a non-empty string, 1065 * that file name will be used as the filename instead. 1066 * Note that $save_dir will not be affected by this, only 1067 * the basename of the file. 1068 * 'start' download is starting, parameter is number of bytes 1069 * that are expected, or -1 if unknown 1070 * 'bytesread' parameter is the number of bytes read so far 1071 * 'done' download is complete, parameter is the total number 1072 * of bytes read 1073 * 'connfailed' if the TCP connection fails, this callback is called 1074 * with array(host,port,errno,errmsg) 1075 * 'writefailed' if writing to disk fails, this callback is called 1076 * with array(destfile,errmsg) 1077 * 1078 * If an HTTP proxy has been configured (http_proxy PEAR_Config 1079 * setting), the proxy will be used. 1080 * 1081 * @param string $url the URL to download 1082 * @param object $ui PEAR_Frontend_* instance 1083 * @param object $config PEAR_Config instance 1084 * @param string $save_dir (optional) directory to save file in 1085 * @param mixed $callback (optional) function/method to call for status 1086 * updates 1087 * 1088 * @return string Returns the full path of the downloaded file or a PEAR 1089 * error on failure. If the error is caused by 1090 * socket-related errors, the error object will 1091 * have the fsockopen error code available through 1092 * getCode(). 1093 * 1094 * @access public 1095 * @deprecated in favor of PEAR_Downloader::downloadHttp() 1096 */ 1097 function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) 1098 { 1099 if (!class_exists('PEAR_Downloader')) { 1100 require_once 'PEAR/Downloader.php'; 1101 } 1102 return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); 1103 } 1104 1105 // }}} 1106 1107 /** 1108 * @param string $path relative or absolute include path 1109 * @return boolean 1110 * @static 1111 */ 1112 function isIncludeable($path) 1113 { 1114 if (file_exists($path) && is_readable($path)) { 1115 return true; 1116 } 1117 $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); 1118 foreach ($ipath as $include) { 1119 $test = realpath($include . DIRECTORY_SEPARATOR . $path); 1120 if (file_exists($test) && is_readable($test)) { 1121 return true; 1122 } 1123 } 1124 return false; 1125 } 1126} 1127require_once 'PEAR/Config.php'; 1128require_once 'PEAR/PackageFile.php'; 1129?>