3 * PEAR_Common, the base class for the PEAR Installer
\r
5 * PHP versions 4 and 5
\r
7 * LICENSE: This source file is subject to version 3.0 of the PHP license
\r
8 * that is available through the world-wide-web at the following URI:
\r
9 * http://www.php.net/license/3_0.txt. If you did not receive a copy of
\r
10 * the PHP License and are unable to obtain it through the web, please
\r
11 * send a note to license@php.net so we can mail you a copy immediately.
\r
15 * @author Stig Bakken <ssb@php.net>
\r
16 * @author Tomas V. V. Cox <cox@idecnet.com>
\r
17 * @author Greg Beaver <cellog@php.net>
\r
18 * @copyright 1997-2008 The PHP Group
\r
19 * @license http://www.php.net/license/3_0.txt PHP License 3.0
\r
20 * @version CVS: $Id: Common.php 8901 2009-11-11 19:10:19Z cindy $
\r
21 * @link http://pear.php.net/package/PEAR
\r
22 * @since File available since Release 0.1.0
\r
23 * @deprecated File deprecated since Release 1.4.0a1
\r
27 * Include error handling
\r
29 require_once 'PEAR.php';
\r
31 // {{{ constants and globals
\r
34 * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
\r
36 define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
\r
37 define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
\r
38 define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/');
\r
40 // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
\r
41 define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
\r
42 define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '$/i');
\r
44 // XXX far from perfect :-)
\r
45 define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
\r
46 ')(-([.0-9a-zA-Z]+))?');
\r
47 define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
\r
50 define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9_\.]+');
\r
51 define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '$/');
\r
53 // this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
\r
54 define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(\/[a-zA-Z0-9-]+)*');
\r
55 define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '$/i');
\r
57 define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
\r
58 . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
\r
59 define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '$/i');
\r
61 define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
\r
62 . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
\r
63 define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '$/');
\r
66 * List of temporary files and directories registered by
\r
67 * PEAR_Common::addTempFile().
\r
70 $GLOBALS['_PEAR_Common_tempfiles'] = array();
\r
73 * Valid maintainer roles
\r
76 $GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
\r
79 * Valid release states
\r
82 $GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
\r
85 * Valid dependency types
\r
88 $GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
\r
91 * Valid dependency relations
\r
94 $GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
\r
100 $GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
\r
103 * Valid replacement types
\r
106 $GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
\r
109 * Valid "provide" types
\r
112 $GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
\r
115 * Valid "provide" types
\r
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');
\r
123 * Class providing common functionality for PEAR administration classes.
\r
126 * @author Stig Bakken <ssb@php.net>
\r
127 * @author Tomas V. V. Cox <cox@idecnet.com>
\r
128 * @author Greg Beaver <cellog@php.net>
\r
129 * @copyright 1997-2008 The PHP Group
\r
130 * @license http://www.php.net/license/3_0.txt PHP License 3.0
\r
131 * @version Release: 1.4.4
\r
132 * @link http://pear.php.net/package/PEAR
\r
133 * @since Class available since Release 1.4.0a1
\r
134 * @deprecated This class will disappear, and its components will be spread
\r
135 * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
\r
137 class PEAR_Common extends PEAR
\r
141 /** stack of elements, gives some sort of XML context */
\r
142 var $element_stack = array();
\r
144 /** name of currently parsed XML element */
\r
145 var $current_element;
\r
147 /** array of attributes of the currently parsed XML element */
\r
148 var $current_attributes = array();
\r
150 /** assoc with information about a package */
\r
151 var $pkginfo = array();
\r
154 * User Interface object (PEAR_Frontend_* class). If null,
\r
155 * the log() method uses print.
\r
161 * Configuration object (PEAR_Config).
\r
164 var $config = null;
\r
166 var $current_path = null;
\r
169 * PEAR_SourceAnalyzer instance
\r
172 var $source_analyzer = null;
\r
174 * Flag variable used to mark a valid package file
\r
178 var $_validPackageFile;
\r
185 * PEAR_Common constructor
\r
189 function PEAR_Common()
\r
192 $this->config = &PEAR_Config::singleton();
\r
193 $this->debug = $this->config->get('verbose');
\r
200 * PEAR_Common destructor
\r
204 function _PEAR_Common()
\r
206 // doesn't work due to bug #14744
\r
207 //$tempfiles = $this->_tempfiles;
\r
208 $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
\r
209 while ($file = array_shift($tempfiles)) {
\r
210 if (@is_dir($file)) {
\r
211 if (!class_exists('System')) {
\r
212 require_once 'System.php';
\r
214 System::rm(array('-rf', $file));
\r
215 } elseif (file_exists($file)) {
\r
222 // {{{ addTempFile()
\r
225 * Register a temporary file or directory. When the destructor is
\r
226 * executed, all registered temporary files and directories are
\r
229 * @param string $file name of file or directory
\r
235 function addTempFile($file)
\r
237 if (!class_exists('PEAR_Frontend')) {
\r
238 require_once 'PEAR/Frontend.php';
\r
240 PEAR_Frontend::addTempFile($file);
\r
247 * Wrapper to System::mkDir(), creates a directory as well as
\r
248 * any necessary parent directories.
\r
250 * @param string $dir directory name
\r
252 * @return bool TRUE on success, or a PEAR error
\r
256 function mkDirHier($dir)
\r
258 $this->log(2, "+ create dir $dir");
\r
259 if (!class_exists('System')) {
\r
260 require_once 'System.php';
\r
262 return System::mkDir(array('-p', $dir));
\r
271 * @param int $level log level (0 is quiet, higher is noisier)
\r
272 * @param string $msg message to write to the log
\r
279 function log($level, $msg, $append_crlf = true)
\r
281 if ($this->debug >= $level) {
\r
282 if (!class_exists('PEAR_Frontend')) {
\r
283 require_once 'PEAR/Frontend.php';
\r
285 $ui = &PEAR_Frontend::singleton();
\r
286 if (is_a($ui, 'PEAR_Frontend')) {
\r
287 $ui->log($msg, $append_crlf);
\r
298 * Create and register a temporary directory.
\r
300 * @param string $tmpdir (optional) Directory to use as tmpdir.
\r
301 * Will use system defaults (for example
\r
302 * /tmp or c:\windows\temp) if not specified
\r
304 * @return string name of created directory
\r
308 function mkTempDir($tmpdir = '')
\r
311 $topt = array('-t', $tmpdir);
\r
315 $topt = array_merge($topt, array('-d', 'pear'));
\r
316 if (!class_exists('System')) {
\r
317 require_once 'System.php';
\r
319 if (!$tmpdir = System::mktemp($topt)) {
\r
322 $this->addTempFile($tmpdir);
\r
327 // {{{ setFrontendObject()
\r
330 * Set object that represents the frontend to be used.
\r
332 * @param object Reference of the frontend object
\r
336 function setFrontendObject(&$ui)
\r
343 // {{{ infoFromTgzFile()
\r
346 * Returns information about a package file. Expects the name of
\r
347 * a gzipped tar file as input.
\r
349 * @param string $file name of .tgz file
\r
351 * @return array array with package information
\r
354 * @deprecated use PEAR_PackageFile->fromTgzFile() instead
\r
357 function infoFromTgzFile($file)
\r
359 $packagefile = new PEAR_PackageFile($this->config);
\r
360 $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
\r
361 if (PEAR::isError($pf)) {
\r
362 $errs = $pf->getUserinfo();
\r
363 if (is_array($errs)) {
\r
364 foreach ($errs as $error) {
\r
365 $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
\r
370 return $this->_postProcessValidPackagexml($pf);
\r
374 // {{{ infoFromDescriptionFile()
\r
377 * Returns information about a package file. Expects the name of
\r
378 * a package xml file as input.
\r
380 * @param string $descfile name of package xml file
\r
382 * @return array array with package information
\r
385 * @deprecated use PEAR_PackageFile->fromPackageFile() instead
\r
388 function infoFromDescriptionFile($descfile)
\r
390 $packagefile = new PEAR_PackageFile($this->config);
\r
391 $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
\r
392 if (PEAR::isError($pf)) {
\r
393 $errs = $pf->getUserinfo();
\r
394 if (is_array($errs)) {
\r
395 foreach ($errs as $error) {
\r
396 $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
\r
401 return $this->_postProcessValidPackagexml($pf);
\r
405 // {{{ infoFromString()
\r
408 * Returns information about a package file. Expects the contents
\r
409 * of a package xml file as input.
\r
411 * @param string $data contents of package.xml file
\r
413 * @return array array with package information
\r
416 * @deprecated use PEAR_PackageFile->fromXmlstring() instead
\r
419 function infoFromString($data)
\r
421 $packagefile = new PEAR_PackageFile($this->config);
\r
422 $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
\r
423 if (PEAR::isError($pf)) {
\r
424 $errs = $pf->getUserinfo();
\r
425 if (is_array($errs)) {
\r
426 foreach ($errs as $error) {
\r
427 $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
\r
432 return $this->_postProcessValidPackagexml($pf);
\r
437 * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
\r
440 function _postProcessValidPackagexml(&$pf)
\r
442 if (is_a($pf, 'PEAR_PackageFile_v2')) {
\r
443 // sort of make this into a package.xml 1.0-style array
\r
444 // changelog is not converted to old format.
\r
445 $arr = $pf->toArray(true);
\r
446 $arr = array_merge($arr, $arr['old']);
\r
447 unset($arr['old']);
\r
448 unset($arr['xsdversion']);
\r
449 unset($arr['contents']);
\r
450 unset($arr['compatible']);
\r
451 unset($arr['channel']);
\r
452 unset($arr['uri']);
\r
453 unset($arr['dependencies']);
\r
454 unset($arr['phprelease']);
\r
455 unset($arr['extsrcrelease']);
\r
456 unset($arr['extbinrelease']);
\r
457 unset($arr['bundle']);
\r
458 unset($arr['lead']);
\r
459 unset($arr['developer']);
\r
460 unset($arr['helper']);
\r
461 unset($arr['contributor']);
\r
462 $arr['filelist'] = $pf->getFilelist();
\r
463 $this->pkginfo = $arr;
\r
466 $this->pkginfo = $pf->toArray();
\r
467 return $this->pkginfo;
\r
470 // {{{ infoFromAny()
\r
473 * Returns package information from different sources
\r
475 * This method is able to extract information about a package
\r
476 * from a .tgz archive or from a XML package definition file.
\r
479 * @param string Filename of the source ('package.xml', '<package>.tgz')
\r
481 * @deprecated use PEAR_PackageFile->fromAnyFile() instead
\r
483 function infoFromAny($info)
\r
485 if (is_string($info) && file_exists($info)) {
\r
486 $packagefile = new PEAR_PackageFile($this->config);
\r
487 $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
\r
488 if (PEAR::isError($pf)) {
\r
489 $errs = $pf->getUserinfo();
\r
490 if (is_array($errs)) {
\r
491 foreach ($errs as $error) {
\r
492 $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
\r
497 return $this->_postProcessValidPackagexml($pf);
\r
503 // {{{ xmlFromInfo()
\r
506 * Return an XML document based on the package info (as returned
\r
507 * by the PEAR_Common::infoFrom* methods).
\r
509 * @param array $pkginfo package info
\r
511 * @return string XML data
\r
514 * @deprecated use a PEAR_PackageFile_v* object's generator instead
\r
516 function xmlFromInfo($pkginfo)
\r
518 $config = &PEAR_Config::singleton();
\r
519 $packagefile = new PEAR_PackageFile($config);
\r
520 $pf = &$packagefile->fromArray($pkginfo);
\r
521 $gen = &$pf->getDefaultGenerator();
\r
522 return $gen->toXml(PEAR_VALIDATE_PACKAGING);
\r
526 // {{{ validatePackageInfo()
\r
529 * Validate XML package definition file.
\r
531 * @param string $info Filename of the package archive or of the
\r
532 * package definition file
\r
533 * @param array $errors Array that will contain the errors
\r
534 * @param array $warnings Array that will contain the warnings
\r
535 * @param string $dir_prefix (optional) directory where source files
\r
536 * may be found, or empty if they are not available
\r
539 * @deprecated use the validation of PEAR_PackageFile objects
\r
541 function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
\r
543 $config = &PEAR_Config::singleton();
\r
544 $packagefile = new PEAR_PackageFile($config);
\r
545 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
\r
546 if (strpos($info, '<?xml') !== false) {
\r
547 $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
\r
549 $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
\r
551 PEAR::staticPopErrorHandling();
\r
552 if (PEAR::isError($pf)) {
\r
553 $errs = $pf->getUserinfo();
\r
554 if (is_array($errs)) {
\r
555 foreach ($errs as $error) {
\r
556 if ($error['level'] == 'error') {
\r
557 $errors[] = $error['message'];
\r
559 $warnings[] = $error['message'];
\r
569 // {{{ buildProvidesArray()
\r
572 * Build a "provides" array from data returned by
\r
573 * analyzeSourceCode(). The format of the built array is like
\r
577 * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
\r
582 * @param array $srcinfo array with information about a source file
\r
583 * as returned by the analyzeSourceCode() method.
\r
590 function buildProvidesArray($srcinfo)
\r
592 $file = basename($srcinfo['source_file']);
\r
594 if (isset($this->_packageName)) {
\r
595 $pn = $this->_packageName;
\r
597 $pnl = strlen($pn);
\r
598 foreach ($srcinfo['declared_classes'] as $class) {
\r
599 $key = "class;$class";
\r
600 if (isset($this->pkginfo['provides'][$key])) {
\r
603 $this->pkginfo['provides'][$key] =
\r
604 array('file'=> $file, 'type' => 'class', 'name' => $class);
\r
605 if (isset($srcinfo['inheritance'][$class])) {
\r
606 $this->pkginfo['provides'][$key]['extends'] =
\r
607 $srcinfo['inheritance'][$class];
\r
610 foreach ($srcinfo['declared_methods'] as $class => $methods) {
\r
611 foreach ($methods as $method) {
\r
612 $function = "$class::$method";
\r
613 $key = "function;$function";
\r
614 if ($method{0} == '_' || !strcasecmp($method, $class) ||
\r
615 isset($this->pkginfo['provides'][$key])) {
\r
618 $this->pkginfo['provides'][$key] =
\r
619 array('file'=> $file, 'type' => 'function', 'name' => $function);
\r
623 foreach ($srcinfo['declared_functions'] as $function) {
\r
624 $key = "function;$function";
\r
625 if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
\r
628 if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
\r
629 $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
\r
631 $this->pkginfo['provides'][$key] =
\r
632 array('file'=> $file, 'type' => 'function', 'name' => $function);
\r
637 // {{{ analyzeSourceCode()
\r
640 * Analyze the source code of the given PHP file
\r
642 * @param string Filename of the PHP file
\r
646 function analyzeSourceCode($file)
\r
648 if (!function_exists("token_get_all")) {
\r
651 if (!defined('T_DOC_COMMENT')) {
\r
652 define('T_DOC_COMMENT', T_COMMENT);
\r
654 if (!defined('T_INTERFACE')) {
\r
655 define('T_INTERFACE', -1);
\r
657 if (!defined('T_IMPLEMENTS')) {
\r
658 define('T_IMPLEMENTS', -1);
\r
660 if (!$fp = @fopen($file, "r")) {
\r
663 if (function_exists('file_get_contents')) {
\r
665 $contents = file_get_contents($file);
\r
667 $contents = fread($fp, filesize($file));
\r
670 $tokens = token_get_all($contents);
\r
672 for ($i = 0; $i < sizeof($tokens); $i++) {
\r
673 @list($token, $data) = $tokens[$i];
\r
674 if (is_string($token)) {
\r
677 print token_name($token) . ' ';
\r
678 var_dump(rtrim($data));
\r
684 $bracket_level = 0;
\r
687 $current_class = '';
\r
688 $current_interface = '';
\r
689 $current_class_level = -1;
\r
690 $current_function = '';
\r
691 $current_function_level = -1;
\r
692 $declared_classes = array();
\r
693 $declared_interfaces = array();
\r
694 $declared_functions = array();
\r
695 $declared_methods = array();
\r
696 $used_classes = array();
\r
697 $used_functions = array();
\r
698 $extends = array();
\r
699 $implements = array();
\r
702 $interface = false;
\r
703 for ($i = 0; $i < sizeof($tokens); $i++) {
\r
704 if (is_array($tokens[$i])) {
\r
705 list($token, $data) = $tokens[$i];
\r
707 $token = $tokens[$i];
\r
711 if ($token != '"') {
\r
723 $current_function = '';
\r
724 $current_function_level = -1;
\r
731 case T_DOLLAR_OPEN_CURLY_BRACES:
\r
732 case '{': $brace_level++; continue 2;
\r
735 if ($current_class_level == $brace_level) {
\r
736 $current_class = '';
\r
737 $current_class_level = -1;
\r
739 if ($current_function_level == $brace_level) {
\r
740 $current_function = '';
\r
741 $current_function_level = -1;
\r
744 case '[': $bracket_level++; continue 2;
\r
745 case ']': $bracket_level--; continue 2;
\r
746 case '(': $paren_level++; continue 2;
\r
747 case ')': $paren_level--; continue 2;
\r
751 if (($current_class_level != -1) || ($current_function_level != -1)) {
\r
752 PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
\r
753 PEAR_COMMON_ERROR_INVALIDPHP);
\r
760 $look_for = $token;
\r
763 if (version_compare(zend_version(), '2.0', '<')) {
\r
764 if (in_array(strtolower($data),
\r
765 array('public', 'private', 'protected', 'abstract',
\r
766 'interface', 'implements', 'throw')
\r
768 PEAR::raiseError('Error: PHP5 token encountered in ' . $file .
\r
769 'packaging should be done in PHP 5');
\r
773 if ($look_for == T_CLASS) {
\r
774 $current_class = $data;
\r
775 $current_class_level = $brace_level;
\r
776 $declared_classes[] = $current_class;
\r
777 } elseif ($look_for == T_INTERFACE) {
\r
778 $current_interface = $data;
\r
779 $current_class_level = $brace_level;
\r
780 $declared_interfaces[] = $current_interface;
\r
781 } elseif ($look_for == T_IMPLEMENTS) {
\r
782 $implements[$current_class] = $data;
\r
783 } elseif ($look_for == T_EXTENDS) {
\r
784 $extends[$current_class] = $data;
\r
785 } elseif ($look_for == T_FUNCTION) {
\r
786 if ($current_class) {
\r
787 $current_function = "$current_class::$data";
\r
788 $declared_methods[$current_class][] = $data;
\r
789 } elseif ($current_interface) {
\r
790 $current_function = "$current_interface::$data";
\r
791 $declared_methods[$current_interface][] = $data;
\r
793 $current_function = $data;
\r
794 $declared_functions[] = $current_function;
\r
796 $current_function_level = $brace_level;
\r
798 } elseif ($look_for == T_NEW) {
\r
799 $used_classes[$data] = true;
\r
806 case T_DOC_COMMENT:
\r
808 if (preg_match('!^/\*\*\s!', $data)) {
\r
809 $lastphpdoc = $data;
\r
810 if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
\r
811 $nodeps = array_merge($nodeps, $m[1]);
\r
815 case T_DOUBLE_COLON:
\r
816 if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
\r
817 PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
\r
818 PEAR_COMMON_ERROR_INVALIDPHP);
\r
821 $class = $tokens[$i - 1][1];
\r
822 if (strtolower($class) != 'parent') {
\r
823 $used_classes[$class] = true;
\r
829 "source_file" => $file,
\r
830 "declared_classes" => $declared_classes,
\r
831 "declared_interfaces" => $declared_interfaces,
\r
832 "declared_methods" => $declared_methods,
\r
833 "declared_functions" => $declared_functions,
\r
834 "used_classes" => array_diff(array_keys($used_classes), $nodeps),
\r
835 "inheritance" => $extends,
\r
836 "implements" => $implements,
\r
841 // {{{ betterStates()
\r
844 * Return an array containing all of the states that are more stable than
\r
845 * or equal to the passed in state
\r
847 * @param string Release state
\r
848 * @param boolean Determines whether to include $state in the list
\r
849 * @return false|array False if $state is not a valid release state
\r
851 function betterStates($state, $include = false)
\r
853 static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
\r
854 $i = array_search($state, $states);
\r
855 if ($i === false) {
\r
861 return array_slice($states, $i + 1);
\r
865 // {{{ detectDependencies()
\r
867 function detectDependencies($any, $status_callback = null)
\r
869 if (!function_exists("token_get_all")) {
\r
872 if (PEAR::isError($info = $this->infoFromAny($any))) {
\r
873 return $this->raiseError($info);
\r
875 if (!is_array($info)) {
\r
879 $used_c = $decl_c = $decl_f = $decl_m = array();
\r
880 foreach ($info['filelist'] as $file => $fa) {
\r
881 $tmp = $this->analyzeSourceCode($file);
\r
882 $used_c = @array_merge($used_c, $tmp['used_classes']);
\r
883 $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
\r
884 $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
\r
885 $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
\r
886 $inheri = @array_merge($inheri, $tmp['inheritance']);
\r
888 $used_c = array_unique($used_c);
\r
889 $decl_c = array_unique($decl_c);
\r
890 $undecl_c = array_diff($used_c, $decl_c);
\r
891 return array('used_classes' => $used_c,
\r
892 'declared_classes' => $decl_c,
\r
893 'declared_methods' => $decl_m,
\r
894 'declared_functions' => $decl_f,
\r
895 'undeclared_classes' => $undecl_c,
\r
896 'inheritance' => $inheri,
\r
901 // {{{ getUserRoles()
\r
904 * Get the valid roles for a PEAR package maintainer
\r
909 function getUserRoles()
\r
911 return $GLOBALS['_PEAR_Common_maintainer_roles'];
\r
915 // {{{ getReleaseStates()
\r
918 * Get the valid package release states of packages
\r
923 function getReleaseStates()
\r
925 return $GLOBALS['_PEAR_Common_release_states'];
\r
929 // {{{ getDependencyTypes()
\r
932 * Get the implemented dependency types (php, ext, pkg etc.)
\r
937 function getDependencyTypes()
\r
939 return $GLOBALS['_PEAR_Common_dependency_types'];
\r
943 // {{{ getDependencyRelations()
\r
946 * Get the implemented dependency relations (has, lt, ge etc.)
\r
951 function getDependencyRelations()
\r
953 return $GLOBALS['_PEAR_Common_dependency_relations'];
\r
957 // {{{ getFileRoles()
\r
960 * Get the implemented file roles
\r
965 function getFileRoles()
\r
967 return $GLOBALS['_PEAR_Common_file_roles'];
\r
971 // {{{ getReplacementTypes()
\r
974 * Get the implemented file replacement types in
\r
979 function getReplacementTypes()
\r
981 return $GLOBALS['_PEAR_Common_replacement_types'];
\r
985 // {{{ getProvideTypes()
\r
988 * Get the implemented file replacement types in
\r
993 function getProvideTypes()
\r
995 return $GLOBALS['_PEAR_Common_provide_types'];
\r
999 // {{{ getScriptPhases()
\r
1002 * Get the implemented file replacement types in
\r
1007 function getScriptPhases()
\r
1009 return $GLOBALS['_PEAR_Common_script_phases'];
\r
1013 // {{{ validPackageName()
\r
1016 * Test whether a string contains a valid package name.
\r
1018 * @param string $name the package name to test
\r
1024 function validPackageName($name)
\r
1026 return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
\r
1031 // {{{ validPackageVersion()
\r
1034 * Test whether a string contains a valid package version.
\r
1036 * @param string $ver the package version to test
\r
1042 function validPackageVersion($ver)
\r
1044 return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
\r
1050 // {{{ downloadHttp()
\r
1053 * Download a file through HTTP. Considers suggested file name in
\r
1054 * Content-disposition: header and can run a callback function for
\r
1055 * different events. The callback will be called with two
\r
1056 * parameters: the callback type, and parameters. The implemented
\r
1057 * callback types are:
\r
1059 * 'setup' called at the very beginning, parameter is a UI object
\r
1060 * that should be used for all output
\r
1061 * 'message' the parameter is a string with an informational message
\r
1062 * 'saveas' may be used to save with a different file name, the
\r
1063 * parameter is the filename that is about to be used.
\r
1064 * If a 'saveas' callback returns a non-empty string,
\r
1065 * that file name will be used as the filename instead.
\r
1066 * Note that $save_dir will not be affected by this, only
\r
1067 * the basename of the file.
\r
1068 * 'start' download is starting, parameter is number of bytes
\r
1069 * that are expected, or -1 if unknown
\r
1070 * 'bytesread' parameter is the number of bytes read so far
\r
1071 * 'done' download is complete, parameter is the total number
\r
1073 * 'connfailed' if the TCP connection fails, this callback is called
\r
1074 * with array(host,port,errno,errmsg)
\r
1075 * 'writefailed' if writing to disk fails, this callback is called
\r
1076 * with array(destfile,errmsg)
\r
1078 * If an HTTP proxy has been configured (http_proxy PEAR_Config
\r
1079 * setting), the proxy will be used.
\r
1081 * @param string $url the URL to download
\r
1082 * @param object $ui PEAR_Frontend_* instance
\r
1083 * @param object $config PEAR_Config instance
\r
1084 * @param string $save_dir (optional) directory to save file in
\r
1085 * @param mixed $callback (optional) function/method to call for status
\r
1088 * @return string Returns the full path of the downloaded file or a PEAR
\r
1089 * error on failure. If the error is caused by
\r
1090 * socket-related errors, the error object will
\r
1091 * have the fsockopen error code available through
\r
1095 * @deprecated in favor of PEAR_Downloader::downloadHttp()
\r
1097 function downloadHttp($url, &$ui, $save_dir = '.', $callback = null)
\r
1099 if (!class_exists('PEAR_Downloader')) {
\r
1100 require_once 'PEAR/Downloader.php';
\r
1102 return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback);
\r
1108 * @param string $path relative or absolute include path
\r
1112 function isIncludeable($path)
\r
1114 if (file_exists($path) && is_readable($path)) {
\r
1117 $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
\r
1118 foreach ($ipath as $include) {
\r
1119 $test = realpath($include . DIRECTORY_SEPARATOR . $path);
\r
1120 if (file_exists($test) && is_readable($test)) {
\r
1127 require_once 'PEAR/Config.php';
\r
1128 require_once 'PEAR/PackageFile.php';
\r
1129 if (!function_exists('file_get_contents')) {
\r
1130 function file_get_contents($filename)
\r
1132 $fp = fopen($filename, 'rb');
\r
1134 while (!feof($fp)) {
\r
1135 $ret .= fread($fp, 8092);;
\r