PageRenderTime 102ms CodeModel.GetById 20ms RepoModel.GetById 9ms app.codeStats 0ms

/common/libraries/plugin/pear/PEAR/Common.php

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