PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/pear/PEAR/PackageFile/v1.php

https://github.com/oilcf/agilebill
PHP | 1596 lines | 1150 code | 145 blank | 301 comment | 146 complexity | 1d8a2fbb3d8cd41fd4bca0a5e3f2404e MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, LGPL-2.0
  1. <?php
  2. /**
  3. * PEAR_PackageFile_v1, package.xml version 1.0
  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 Greg Beaver <cellog@php.net>
  16. * @copyright 1997-2005 The PHP Group
  17. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  18. * @version CVS: $Id: v1.php,v 1.67 2005/10/27 05:07:24 cellog Exp $
  19. * @link http://pear.php.net/package/PEAR
  20. * @since File available since Release 1.4.0a1
  21. */
  22. /**
  23. * For error handling
  24. */
  25. require_once 'PEAR/ErrorStack.php';
  26. /**
  27. * Error code if parsing is attempted with no xml extension
  28. */
  29. define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
  30. /**
  31. * Error code if creating the xml parser resource fails
  32. */
  33. define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
  34. /**
  35. * Error code used for all sax xml parsing errors
  36. */
  37. define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
  38. /**
  39. * Error code used when there is no name
  40. */
  41. define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
  42. /**
  43. * Error code when a package name is not valid
  44. */
  45. define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
  46. /**
  47. * Error code used when no summary is parsed
  48. */
  49. define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
  50. /**
  51. * Error code for summaries that are more than 1 line
  52. */
  53. define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
  54. /**
  55. * Error code used when no description is present
  56. */
  57. define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
  58. /**
  59. * Error code used when no license is present
  60. */
  61. define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
  62. /**
  63. * Error code used when a <version> version number is not present
  64. */
  65. define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
  66. /**
  67. * Error code used when a <version> version number is invalid
  68. */
  69. define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
  70. /**
  71. * Error code when release state is missing
  72. */
  73. define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
  74. /**
  75. * Error code when release state is invalid
  76. */
  77. define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
  78. /**
  79. * Error code when release state is missing
  80. */
  81. define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
  82. /**
  83. * Error code when release state is invalid
  84. */
  85. define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
  86. /**
  87. * Error code when no release notes are found
  88. */
  89. define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
  90. /**
  91. * Error code when no maintainers are found
  92. */
  93. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
  94. /**
  95. * Error code when a maintainer has no handle
  96. */
  97. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
  98. /**
  99. * Error code when a maintainer has no handle
  100. */
  101. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
  102. /**
  103. * Error code when a maintainer has no name
  104. */
  105. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
  106. /**
  107. * Error code when a maintainer has no email
  108. */
  109. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
  110. /**
  111. * Error code when a maintainer has no handle
  112. */
  113. define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
  114. /**
  115. * Error code when a dependency is not a PHP dependency, but has no name
  116. */
  117. define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
  118. /**
  119. * Error code when a dependency has no type (pkg, php, etc.)
  120. */
  121. define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
  122. /**
  123. * Error code when a dependency has no relation (lt, ge, has, etc.)
  124. */
  125. define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
  126. /**
  127. * Error code when a dependency is not a 'has' relation, but has no version
  128. */
  129. define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
  130. /**
  131. * Error code when a dependency has an invalid relation
  132. */
  133. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
  134. /**
  135. * Error code when a dependency has an invalid type
  136. */
  137. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
  138. /**
  139. * Error code when a dependency has an invalid optional option
  140. */
  141. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
  142. /**
  143. * Error code when a dependency is a pkg dependency, and has an invalid package name
  144. */
  145. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
  146. /**
  147. * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
  148. */
  149. define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
  150. /**
  151. * Error code when rel="has" and version attribute is present.
  152. */
  153. define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
  154. /**
  155. * Error code when type="php" and dependency name is present
  156. */
  157. define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
  158. /**
  159. * Error code when a configure option has no name
  160. */
  161. define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
  162. /**
  163. * Error code when a configure option has no name
  164. */
  165. define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
  166. /**
  167. * Error code when a file in the filelist has an invalid role
  168. */
  169. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
  170. /**
  171. * Error code when a file in the filelist has no role
  172. */
  173. define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
  174. /**
  175. * Error code when analyzing a php source file that has parse errors
  176. */
  177. define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
  178. /**
  179. * Error code when analyzing a php source file reveals a source element
  180. * without a package name prefix
  181. */
  182. define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
  183. /**
  184. * Error code when an unknown channel is specified
  185. */
  186. define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
  187. /**
  188. * Error code when no files are found in the filelist
  189. */
  190. define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
  191. /**
  192. * Error code when a file is not valid php according to _analyzeSourceCode()
  193. */
  194. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
  195. /**
  196. * Error code when the channel validator returns an error or warning
  197. */
  198. define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
  199. /**
  200. * Error code when a php5 package is packaged in php4 (analysis doesn't work)
  201. */
  202. define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
  203. /**
  204. * Error code when a file is listed in package.xml but does not exist
  205. */
  206. define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
  207. /**
  208. * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
  209. */
  210. define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
  211. /**
  212. * Error code when a package.xml contains non-ISO-8859-1 characters
  213. */
  214. define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49);
  215. /**
  216. * Error code when a dependency is not a 'has' relation, but has no version
  217. */
  218. define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
  219. /**
  220. * Error code when a package has no lead developer
  221. */
  222. define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
  223. /**
  224. * Error code when a filename begins with "."
  225. */
  226. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52);
  227. /**
  228. * package.xml encapsulator
  229. * @category pear
  230. * @package PEAR
  231. * @author Greg Beaver <cellog@php.net>
  232. * @copyright 1997-2005 The PHP Group
  233. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  234. * @version Release: 1.4.5
  235. * @link http://pear.php.net/package/PEAR
  236. * @since Class available since Release 1.4.0a1
  237. */
  238. class PEAR_PackageFile_v1
  239. {
  240. /**
  241. * @access private
  242. * @var PEAR_ErrorStack
  243. * @access private
  244. */
  245. var $_stack;
  246. /**
  247. * A registry object, used to access the package name validation regex for non-standard channels
  248. * @var PEAR_Registry
  249. * @access private
  250. */
  251. var $_registry;
  252. /**
  253. * An object that contains a log method that matches PEAR_Common::log's signature
  254. * @var object
  255. * @access private
  256. */
  257. var $_logger;
  258. /**
  259. * Parsed package information
  260. * @var array
  261. * @access private
  262. */
  263. var $_packageInfo;
  264. /**
  265. * path to package.xml
  266. * @var string
  267. * @access private
  268. */
  269. var $_packageFile;
  270. /**
  271. * path to package .tgz or false if this is a local/extracted package.xml
  272. * @var string
  273. * @access private
  274. */
  275. var $_archiveFile;
  276. /**
  277. * @var int
  278. * @access private
  279. */
  280. var $_isValid = 0;
  281. /**
  282. * Determines whether this packagefile was initialized only with partial package info
  283. *
  284. * If this package file was constructed via parsing REST, it will only contain
  285. *
  286. * - package name
  287. * - channel name
  288. * - dependencies
  289. * @var boolean
  290. * @access private
  291. */
  292. var $_incomplete = true;
  293. /**
  294. * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
  295. * @param string Name of Error Stack class to use.
  296. */
  297. function PEAR_PackageFile_v1()
  298. {
  299. $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1');
  300. $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  301. $this->_isValid = 0;
  302. }
  303. function installBinary($installer)
  304. {
  305. return false;
  306. }
  307. function isExtension($name)
  308. {
  309. return false;
  310. }
  311. function setConfig(&$config)
  312. {
  313. $this->_config = &$config;
  314. $this->_registry = &$config->getRegistry();
  315. }
  316. function setRequestedGroup()
  317. {
  318. // placeholder
  319. }
  320. /**
  321. * For saving in the registry.
  322. *
  323. * Set the last version that was installed
  324. * @param string
  325. */
  326. function setLastInstalledVersion($version)
  327. {
  328. $this->_packageInfo['_lastversion'] = $version;
  329. }
  330. /**
  331. * @return string|false
  332. */
  333. function getLastInstalledVersion()
  334. {
  335. if (isset($this->_packageInfo['_lastversion'])) {
  336. return $this->_packageInfo['_lastversion'];
  337. }
  338. return false;
  339. }
  340. function getInstalledBinary()
  341. {
  342. return false;
  343. }
  344. function listPostinstallScripts()
  345. {
  346. return false;
  347. }
  348. function initPostinstallScripts()
  349. {
  350. return false;
  351. }
  352. function setLogger(&$logger)
  353. {
  354. if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
  355. return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
  356. }
  357. $this->_logger = &$logger;
  358. }
  359. function setPackagefile($file, $archive = false)
  360. {
  361. $this->_packageFile = $file;
  362. $this->_archiveFile = $archive ? $archive : $file;
  363. }
  364. function getPackageFile()
  365. {
  366. return isset($this->_packageFile) ? $this->_packageFile : false;
  367. }
  368. function getPackageType()
  369. {
  370. return 'php';
  371. }
  372. function getArchiveFile()
  373. {
  374. return $this->_archiveFile;
  375. }
  376. function packageInfo($field)
  377. {
  378. if (!is_string($field) || empty($field) ||
  379. !isset($this->_packageInfo[$field])) {
  380. return false;
  381. }
  382. return $this->_packageInfo[$field];
  383. }
  384. function setDirtree($path)
  385. {
  386. $this->_packageInfo['dirtree'][$path] = true;
  387. }
  388. function getDirtree()
  389. {
  390. if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
  391. return $this->_packageInfo['dirtree'];
  392. }
  393. return false;
  394. }
  395. function resetDirtree()
  396. {
  397. unset($this->_packageInfo['dirtree']);
  398. }
  399. function fromArray($pinfo)
  400. {
  401. $this->_incomplete = false;
  402. $this->_packageInfo = $pinfo;
  403. }
  404. function isIncomplete()
  405. {
  406. return $this->_incomplete;
  407. }
  408. function getChannel()
  409. {
  410. return 'pear.php.net';
  411. }
  412. function getUri()
  413. {
  414. return false;
  415. }
  416. function getTime()
  417. {
  418. return false;
  419. }
  420. function getExtends()
  421. {
  422. if (isset($this->_packageInfo['extends'])) {
  423. return $this->_packageInfo['extends'];
  424. }
  425. return false;
  426. }
  427. /**
  428. * @return array
  429. */
  430. function toArray()
  431. {
  432. if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
  433. return false;
  434. }
  435. return $this->getArray();
  436. }
  437. function getArray()
  438. {
  439. return $this->_packageInfo;
  440. }
  441. function getName()
  442. {
  443. return $this->getPackage();
  444. }
  445. function getPackage()
  446. {
  447. if (isset($this->_packageInfo['package'])) {
  448. return $this->_packageInfo['package'];
  449. }
  450. return false;
  451. }
  452. /**
  453. * WARNING - don't use this unless you know what you are doing
  454. */
  455. function setRawPackage($package)
  456. {
  457. $this->_packageInfo['package'] = $package;
  458. }
  459. function setPackage($package)
  460. {
  461. $this->_packageInfo['package'] = $package;
  462. $this->_isValid = false;
  463. }
  464. function getVersion()
  465. {
  466. if (isset($this->_packageInfo['version'])) {
  467. return $this->_packageInfo['version'];
  468. }
  469. return false;
  470. }
  471. function setVersion($version)
  472. {
  473. $this->_packageInfo['version'] = $version;
  474. $this->_isValid = false;
  475. }
  476. function clearMaintainers()
  477. {
  478. unset($this->_packageInfo['maintainers']);
  479. }
  480. function getMaintainers()
  481. {
  482. if (isset($this->_packageInfo['maintainers'])) {
  483. return $this->_packageInfo['maintainers'];
  484. }
  485. return false;
  486. }
  487. /**
  488. * Adds a new maintainer - no checking of duplicates is performed, use
  489. * updatemaintainer for that purpose.
  490. */
  491. function addMaintainer($role, $handle, $name, $email)
  492. {
  493. $this->_packageInfo['maintainers'][] =
  494. array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
  495. $this->_isValid = false;
  496. }
  497. function updateMaintainer($role, $handle, $name, $email)
  498. {
  499. $found = false;
  500. if (!isset($this->_packageInfo['maintainers']) ||
  501. !is_array($this->_packageInfo['maintainers'])) {
  502. return $this->addMaintainer($role, $handle, $name, $email);
  503. }
  504. foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
  505. if ($maintainer['handle'] == $handle) {
  506. $found = $i;
  507. break;
  508. }
  509. }
  510. if ($found !== false) {
  511. unset($this->_packageInfo['maintainers'][$found]);
  512. $this->_packageInfo['maintainers'] =
  513. array_values($this->_packageInfo['maintainers']);
  514. }
  515. $this->addMaintainer($role, $handle, $name, $email);
  516. }
  517. function deleteMaintainer($handle)
  518. {
  519. $found = false;
  520. foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
  521. if ($maintainer['handle'] == $handle) {
  522. $found = $i;
  523. break;
  524. }
  525. }
  526. if ($found !== false) {
  527. unset($this->_packageInfo['maintainers'][$found]);
  528. $this->_packageInfo['maintainers'] =
  529. array_values($this->_packageInfo['maintainers']);
  530. return true;
  531. }
  532. return false;
  533. }
  534. function getState()
  535. {
  536. if (isset($this->_packageInfo['release_state'])) {
  537. return $this->_packageInfo['release_state'];
  538. }
  539. return false;
  540. }
  541. function setRawState($state)
  542. {
  543. $this->_packageInfo['release_state'] = $state;
  544. }
  545. function setState($state)
  546. {
  547. $this->_packageInfo['release_state'] = $state;
  548. $this->_isValid = false;
  549. }
  550. function getDate()
  551. {
  552. if (isset($this->_packageInfo['release_date'])) {
  553. return $this->_packageInfo['release_date'];
  554. }
  555. return false;
  556. }
  557. function setDate($date)
  558. {
  559. $this->_packageInfo['release_date'] = $date;
  560. $this->_isValid = false;
  561. }
  562. function getLicense()
  563. {
  564. if (isset($this->_packageInfo['release_license'])) {
  565. return $this->_packageInfo['release_license'];
  566. }
  567. return false;
  568. }
  569. function setLicense($date)
  570. {
  571. $this->_packageInfo['release_license'] = $date;
  572. $this->_isValid = false;
  573. }
  574. function getSummary()
  575. {
  576. if (isset($this->_packageInfo['summary'])) {
  577. return $this->_packageInfo['summary'];
  578. }
  579. return false;
  580. }
  581. function setSummary($summary)
  582. {
  583. $this->_packageInfo['summary'] = $summary;
  584. $this->_isValid = false;
  585. }
  586. function getDescription()
  587. {
  588. if (isset($this->_packageInfo['description'])) {
  589. return $this->_packageInfo['description'];
  590. }
  591. return false;
  592. }
  593. function setDescription($desc)
  594. {
  595. $this->_packageInfo['description'] = $desc;
  596. $this->_isValid = false;
  597. }
  598. function getNotes()
  599. {
  600. if (isset($this->_packageInfo['release_notes'])) {
  601. return $this->_packageInfo['release_notes'];
  602. }
  603. return false;
  604. }
  605. function setNotes($notes)
  606. {
  607. $this->_packageInfo['release_notes'] = $notes;
  608. $this->_isValid = false;
  609. }
  610. function getDeps()
  611. {
  612. if (isset($this->_packageInfo['release_deps'])) {
  613. return $this->_packageInfo['release_deps'];
  614. }
  615. return false;
  616. }
  617. /**
  618. * Reset dependencies prior to adding new ones
  619. */
  620. function clearDeps()
  621. {
  622. unset($this->_packageInfo['release_deps']);
  623. }
  624. function addPhpDep($version, $rel)
  625. {
  626. $this->_isValid = false;
  627. $this->_packageInfo['release_deps'][] =
  628. array('type' => 'php',
  629. 'rel' => $rel,
  630. 'version' => $version);
  631. }
  632. function addPackageDep($name, $version, $rel, $optional = 'no')
  633. {
  634. $this->_isValid = false;
  635. $dep =
  636. array('type' => 'pkg',
  637. 'name' => $name,
  638. 'rel' => $rel,
  639. 'optional' => $optional);
  640. if ($rel != 'has' && $rel != 'not') {
  641. $dep['version'] = $version;
  642. }
  643. $this->_packageInfo['release_deps'][] = $dep;
  644. }
  645. function addExtensionDep($name, $version, $rel, $optional = 'no')
  646. {
  647. $this->_isValid = false;
  648. $this->_packageInfo['release_deps'][] =
  649. array('type' => 'ext',
  650. 'name' => $name,
  651. 'rel' => $rel,
  652. 'version' => $version,
  653. 'optional' => $optional);
  654. }
  655. /**
  656. * WARNING - do not use this function directly unless you know what you're doing
  657. */
  658. function setDeps($deps)
  659. {
  660. $this->_packageInfo['release_deps'] = $deps;
  661. }
  662. function hasDeps()
  663. {
  664. return isset($this->_packageInfo['release_deps']) &&
  665. count($this->_packageInfo['release_deps']);
  666. }
  667. function getDependencyGroup($group)
  668. {
  669. return false;
  670. }
  671. function isCompatible($pf)
  672. {
  673. return false;
  674. }
  675. function isSubpackageOf($p)
  676. {
  677. return $p->isSubpackage($this);
  678. }
  679. function isSubpackage($p)
  680. {
  681. return false;
  682. }
  683. function dependsOn($package, $channel)
  684. {
  685. if (strtolower($channel) != 'pear.php.net') {
  686. return false;
  687. }
  688. if (!($deps = $this->getDeps())) {
  689. return false;
  690. }
  691. foreach ($deps as $dep) {
  692. if ($dep['type'] != 'pkg') {
  693. continue;
  694. }
  695. if (strtolower($dep['name']) == strtolower($package)) {
  696. return true;
  697. }
  698. }
  699. return false;
  700. }
  701. function getConfigureOptions()
  702. {
  703. if (isset($this->_packageInfo['configure_options'])) {
  704. return $this->_packageInfo['configure_options'];
  705. }
  706. return false;
  707. }
  708. function hasConfigureOptions()
  709. {
  710. return isset($this->_packageInfo['configure_options']) &&
  711. count($this->_packageInfo['configure_options']);
  712. }
  713. function addConfigureOption($name, $prompt, $default = false)
  714. {
  715. $o = array('name' => $name, 'prompt' => $prompt);
  716. if ($default !== false) {
  717. $o['default'] = $default;
  718. }
  719. if (!isset($this->_packageInfo['configure_options'])) {
  720. $this->_packageInfo['configure_options'] = array();
  721. }
  722. $this->_packageInfo['configure_options'][] = $o;
  723. }
  724. function clearConfigureOptions()
  725. {
  726. unset($this->_packageInfo['configure_options']);
  727. }
  728. function getProvides()
  729. {
  730. if (isset($this->_packageInfo['provides'])) {
  731. return $this->_packageInfo['provides'];
  732. }
  733. return false;
  734. }
  735. function addFile($dir, $file, $attrs)
  736. {
  737. $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
  738. if ($dir == '/' || $dir == '') {
  739. $dir = '';
  740. } else {
  741. $dir .= '/';
  742. }
  743. $file = $dir . $file;
  744. $file = preg_replace('![\\/]+!', '/', $file);
  745. $this->_packageInfo['filelist'][$file] = $attrs;
  746. }
  747. function getInstallationFilelist()
  748. {
  749. return $this->getFilelist();
  750. }
  751. function getFilelist()
  752. {
  753. if (isset($this->_packageInfo['filelist'])) {
  754. return $this->_packageInfo['filelist'];
  755. }
  756. return false;
  757. }
  758. function setFileAttribute($file, $attr, $value)
  759. {
  760. $this->_packageInfo['filelist'][$file][$attr] = $value;
  761. }
  762. function resetFilelist()
  763. {
  764. $this->_packageInfo['filelist'] = array();
  765. }
  766. function setInstalledAs($file, $path)
  767. {
  768. if ($path) {
  769. return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
  770. }
  771. unset($this->_packageInfo['filelist'][$file]['installed_as']);
  772. }
  773. function installedFile($file, $atts)
  774. {
  775. if (isset($this->_packageInfo['filelist'][$file])) {
  776. $this->_packageInfo['filelist'][$file] =
  777. array_merge($this->_packageInfo['filelist'][$file], $atts);
  778. } else {
  779. $this->_packageInfo['filelist'][$file] = $atts;
  780. }
  781. }
  782. function getChangelog()
  783. {
  784. if (isset($this->_packageInfo['changelog'])) {
  785. return $this->_packageInfo['changelog'];
  786. }
  787. return false;
  788. }
  789. function getPackagexmlVersion()
  790. {
  791. return '1.0';
  792. }
  793. /**
  794. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  795. * @param boolean determines whether to purge the error stack after retrieving
  796. * @return array
  797. */
  798. function getValidationWarnings($purge = true)
  799. {
  800. return $this->_stack->getErrors($purge);
  801. }
  802. // }}}
  803. /**
  804. * Validation error. Also marks the object contents as invalid
  805. * @param error code
  806. * @param array error information
  807. * @access private
  808. */
  809. function _validateError($code, $params = array())
  810. {
  811. $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
  812. $this->_isValid = false;
  813. }
  814. /**
  815. * Validation warning. Does not mark the object contents invalid.
  816. * @param error code
  817. * @param array error information
  818. * @access private
  819. */
  820. function _validateWarning($code, $params = array())
  821. {
  822. $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
  823. }
  824. /**
  825. * @param integer error code
  826. * @access protected
  827. */
  828. function _getErrorMessage()
  829. {
  830. return array(
  831. PEAR_PACKAGEFILE_ERROR_NO_NAME =>
  832. 'Missing Package Name',
  833. PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
  834. 'No summary found',
  835. PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
  836. 'Summary should be on one line',
  837. PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
  838. 'Missing description',
  839. PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
  840. 'Missing license',
  841. PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
  842. 'No release version found',
  843. PEAR_PACKAGEFILE_ERROR_NO_STATE =>
  844. 'No release state found',
  845. PEAR_PACKAGEFILE_ERROR_NO_DATE =>
  846. 'No release date found',
  847. PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
  848. 'No release notes found',
  849. PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
  850. 'Package must have at least one lead maintainer',
  851. PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
  852. 'No maintainers found, at least one must be defined',
  853. PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
  854. 'Maintainer %index% has no handle (user ID at channel server)',
  855. PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
  856. 'Maintainer %index% has no role',
  857. PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
  858. 'Maintainer %index% has no name',
  859. PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
  860. 'Maintainer %index% has no email',
  861. PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
  862. 'Dependency %index% is not a php dependency, and has no name',
  863. PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
  864. 'Dependency %index% has no relation (rel)',
  865. PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
  866. 'Dependency %index% has no type',
  867. PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
  868. 'PHP Dependency %index% has a name attribute of "%name%" which will be' .
  869. ' ignored!',
  870. PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
  871. 'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
  872. 'and has no version',
  873. PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
  874. 'Dependency %index% is a type="php" dependency, ' .
  875. 'and has no version',
  876. PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
  877. 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
  878. PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
  879. 'Dependency %index% has invalid optional value "%opt%", should be yes or no',
  880. PEAR_PACKAGEFILE_PHP_NO_NOT =>
  881. 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
  882. ' to exclude specific versions',
  883. PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
  884. 'Configure Option %index% has no name',
  885. PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
  886. 'Configure Option %index% has no prompt',
  887. PEAR_PACKAGEFILE_ERROR_NO_FILES =>
  888. 'No files in <filelist> section of package.xml',
  889. PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
  890. 'File "%file%" has no role, expecting one of "%roles%"',
  891. PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
  892. 'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
  893. PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
  894. 'File "%file%" cannot start with ".", cannot package or install',
  895. PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
  896. 'Parser error: invalid PHP found in file "%file%"',
  897. PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
  898. 'in %file%: %type% "%name%" not prefixed with package name "%package%"',
  899. PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
  900. 'Parser error: invalid PHP file "%file%"',
  901. PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
  902. 'Channel validator error: field "%field%" - %reason%',
  903. PEAR_PACKAGEFILE_ERROR_PHP5 =>
  904. 'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
  905. PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
  906. 'File "%file%" in package.xml does not exist',
  907. PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
  908. 'Package.xml contains non-ISO-8859-1 characters, and may not validate',
  909. );
  910. }
  911. /**
  912. * Validate XML package definition file.
  913. *
  914. * @access public
  915. * @return boolean
  916. */
  917. function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
  918. {
  919. if (($this->_isValid & $state) == $state) {
  920. return true;
  921. }
  922. $this->_isValid = true;
  923. $info = $this->_packageInfo;
  924. if (empty($info['package'])) {
  925. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
  926. $this->_packageName = $pn = 'unknown';
  927. } else {
  928. $this->_packageName = $pn = $info['package'];
  929. }
  930. if (empty($info['summary'])) {
  931. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
  932. } elseif (strpos(trim($info['summary']), "\n") !== false) {
  933. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
  934. array('summary' => $info['summary']));
  935. }
  936. if (empty($info['description'])) {
  937. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
  938. }
  939. if (empty($info['release_license'])) {
  940. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
  941. }
  942. if (empty($info['version'])) {
  943. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
  944. }
  945. if (empty($info['release_state'])) {
  946. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
  947. }
  948. if (empty($info['release_date'])) {
  949. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
  950. }
  951. if (empty($info['release_notes'])) {
  952. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
  953. }
  954. if (empty($info['maintainers'])) {
  955. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
  956. } else {
  957. $haslead = false;
  958. $i = 1;
  959. foreach ($info['maintainers'] as $m) {
  960. if (empty($m['handle'])) {
  961. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
  962. array('index' => $i));
  963. }
  964. if (empty($m['role'])) {
  965. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
  966. array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
  967. } elseif ($m['role'] == 'lead') {
  968. $haslead = true;
  969. }
  970. if (empty($m['name'])) {
  971. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
  972. array('index' => $i));
  973. }
  974. if (empty($m['email'])) {
  975. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
  976. array('index' => $i));
  977. }
  978. $i++;
  979. }
  980. if (!$haslead) {
  981. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
  982. }
  983. }
  984. if (!empty($info['release_deps'])) {
  985. $i = 1;
  986. foreach ($info['release_deps'] as $d) {
  987. if (!isset($d['type']) || empty($d['type'])) {
  988. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
  989. array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
  990. continue;
  991. }
  992. if (!isset($d['rel']) || empty($d['rel'])) {
  993. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
  994. array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
  995. continue;
  996. }
  997. if (!empty($d['optional'])) {
  998. if (!in_array($d['optional'], array('yes', 'no'))) {
  999. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
  1000. array('index' => $i, 'opt' => $d['optional']));
  1001. }
  1002. }
  1003. if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
  1004. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
  1005. array('index' => $i));
  1006. } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
  1007. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
  1008. array('index' => $i, 'rel' => $d['rel']));
  1009. }
  1010. if ($d['type'] == 'php' && !empty($d['name'])) {
  1011. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
  1012. array('index' => $i, 'name' => $d['name']));
  1013. } elseif ($d['type'] != 'php' && empty($d['name'])) {
  1014. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
  1015. array('index' => $i));
  1016. }
  1017. if ($d['type'] == 'php' && empty($d['version'])) {
  1018. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
  1019. array('index' => $i));
  1020. }
  1021. if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
  1022. $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
  1023. array('index' => $i));
  1024. }
  1025. $i++;
  1026. }
  1027. }
  1028. if (!empty($info['configure_options'])) {
  1029. $i = 1;
  1030. foreach ($info['configure_options'] as $c) {
  1031. if (empty($c['name'])) {
  1032. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
  1033. array('index' => $i));
  1034. }
  1035. if (empty($c['prompt'])) {
  1036. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
  1037. array('index' => $i));
  1038. }
  1039. $i++;
  1040. }
  1041. }
  1042. if (empty($info['filelist'])) {
  1043. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
  1044. $errors[] = 'no files';
  1045. } else {
  1046. foreach ($info['filelist'] as $file => $fa) {
  1047. if (empty($fa['role'])) {
  1048. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
  1049. array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
  1050. continue;
  1051. } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
  1052. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
  1053. array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
  1054. }
  1055. if ($file{0} == '.' && $file{1} == '/') {
  1056. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  1057. array('file' => $file));
  1058. }
  1059. }
  1060. }
  1061. if (isset($this->_registry) && $this->_isValid) {
  1062. $chan = $this->_registry->getChannel('pear.php.net');
  1063. $validator = $chan->getValidationObject();
  1064. $validator->setPackageFile($this);
  1065. $validator->validate($state);
  1066. $failures = $validator->getFailures();
  1067. foreach ($failures['errors'] as $error) {
  1068. $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
  1069. }
  1070. foreach ($failures['warnings'] as $warning) {
  1071. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
  1072. }
  1073. }
  1074. if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
  1075. if ($this->_analyzePhpFiles()) {
  1076. $this->_isValid = true;
  1077. }
  1078. }
  1079. if ($this->_isValid) {
  1080. return $this->_isValid = $state;
  1081. }
  1082. return $this->_isValid = 0;
  1083. }
  1084. function _analyzePhpFiles()
  1085. {
  1086. if (!$this->_isValid) {
  1087. return false;
  1088. }
  1089. if (!isset($this->_packageFile)) {
  1090. return false;
  1091. }
  1092. $dir_prefix = dirname($this->_packageFile);
  1093. $common = new PEAR_Common;
  1094. $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
  1095. array($common, 'log');
  1096. $info = $this->getFilelist();
  1097. foreach ($info as $file => $fa) {
  1098. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
  1099. $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
  1100. array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
  1101. continue;
  1102. }
  1103. if ($fa['role'] == 'php' && $dir_prefix) {
  1104. call_user_func_array($log, array(1, "Analyzing $file"));
  1105. $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
  1106. if ($srcinfo) {
  1107. $this->_buildProvidesArray($srcinfo);
  1108. }
  1109. }
  1110. }
  1111. $this->_packageName = $pn = $this->getPackage();
  1112. $pnl = strlen($pn);
  1113. if (isset($this->_packageInfo['provides'])) {
  1114. foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
  1115. if (isset($what['explicit'])) {
  1116. // skip conformance checks if the provides entry is
  1117. // specified in the package.xml file
  1118. continue;
  1119. }
  1120. extract($what);
  1121. if ($type == 'class') {
  1122. if (!strncasecmp($name, $pn, $pnl)) {
  1123. continue;
  1124. }
  1125. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
  1126. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
  1127. } elseif ($type == 'function') {
  1128. if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
  1129. continue;
  1130. }
  1131. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
  1132. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
  1133. }
  1134. }
  1135. }
  1136. return $this->_isValid;
  1137. }
  1138. /**
  1139. * Get the default xml generator object
  1140. *
  1141. * @return PEAR_PackageFile_Generator_v1
  1142. */
  1143. function &getDefaultGenerator()
  1144. {
  1145. if (!class_exists('PEAR_PackageFile_Generator_v1')) {
  1146. require_once 'PEAR/PackageFile/Generator/v1.php';
  1147. }
  1148. $a = &new PEAR_PackageFile_Generator_v1($this);
  1149. return $a;
  1150. }
  1151. /**
  1152. * Get the contents of a file listed within the package.xml
  1153. * @param string
  1154. * @return string
  1155. */
  1156. function getFileContents($file)
  1157. {
  1158. if ($this->_archiveFile == $this->_packageFile) { // unpacked
  1159. $dir = dirname($this->_packageFile);
  1160. $file = $dir . DIRECTORY_SEPARATOR . $file;
  1161. $file = str_replace(array('/', '\\'),
  1162. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
  1163. if (file_exists($file) && is_readable($file)) {
  1164. return implode('', file($file));
  1165. }
  1166. } else { // tgz
  1167. if (!class_exists('Archive_Tar')) {
  1168. require_once 'Archive/Tar.php';
  1169. }
  1170. $tar = &new Archive_Tar($this->_archiveFile);
  1171. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  1172. if ($file != 'package.xml' && $file != 'package2.xml') {
  1173. $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
  1174. }
  1175. $file = $tar->extractInString($file);
  1176. $tar->popErrorHandling();
  1177. if (PEAR::isError($file)) {
  1178. return PEAR::raiseError("Cannot locate file '$file' in archive");
  1179. }
  1180. return $file;
  1181. }
  1182. }
  1183. // {{{ analyzeSourceCode()
  1184. /**
  1185. * Analyze the source code of the given PHP file
  1186. *
  1187. * @param string Filename of the PHP file
  1188. * @return mixed
  1189. * @access private
  1190. */
  1191. function _analyzeSourceCode($file)
  1192. {
  1193. if (!function_exists("token_get_all")) {
  1194. return false;
  1195. }
  1196. if (!defined('T_DOC_COMMENT')) {
  1197. define('T_DOC_COMMENT', T_COMMENT);
  1198. }
  1199. if (!defined('T_INTERFACE')) {
  1200. define('T_INTERFACE', -1);
  1201. }
  1202. if (!defined('T_IMPLEMENTS')) {
  1203. define('T_IMPLEMENTS', -1);
  1204. }
  1205. if (!$fp = @fopen($file, "r")) {
  1206. return false;
  1207. }
  1208. if (function_exists('file_get_contents')) {
  1209. fclose($fp);
  1210. $contents = file_get_contents($file);
  1211. } else {
  1212. $contents = @fread($fp, filesize($file));
  1213. fclose($fp);
  1214. }
  1215. $tokens = token_get_all($contents);
  1216. /*
  1217. for ($i = 0; $i < sizeof($tokens); $i++) {
  1218. @list($token, $data) = $tokens[$i];
  1219. if (is_string($token)) {
  1220. var_dump($token);
  1221. } else {
  1222. print token_name($token) . ' ';
  1223. var_dump(rtrim($data));
  1224. }
  1225. }
  1226. */
  1227. $look_for = 0;
  1228. $paren_level = 0;
  1229. $bracket_level = 0;
  1230. $brace_level = 0;
  1231. $lastphpdoc = '';
  1232. $current_class = '';
  1233. $current_interface = '';
  1234. $current_class_level = -1;
  1235. $current_function = '';
  1236. $current_function_level = -1;
  1237. $declared_classes = array();
  1238. $declared_interfaces = array();
  1239. $declared_functions = array();
  1240. $declared_methods = array();
  1241. $used_classes = array();
  1242. $used_functions = array();
  1243. $extends = array();
  1244. $implements = array();
  1245. $nodeps = array();
  1246. $inquote = false;
  1247. $interface = false;
  1248. for ($i = 0; $i < sizeof($tokens); $i++) {
  1249. if (is_array($tokens[$i])) {
  1250. list($token, $data) = $tokens[$i];
  1251. } else {
  1252. $token = $tokens[$i];
  1253. $data = '';
  1254. }
  1255. if ($inquote) {
  1256. if ($token != '"' && $token != T_END_HEREDOC) {
  1257. continue;
  1258. } else {
  1259. $inquote = false;
  1260. continue;
  1261. }
  1262. }
  1263. switch ($token) {
  1264. case T_WHITESPACE :
  1265. continue;
  1266. case ';':
  1267. if ($interface) {
  1268. $current_function = '';
  1269. $current_function_level = -1;
  1270. }
  1271. break;
  1272. case '"':
  1273. case T_START_HEREDOC:
  1274. $inquote = true;
  1275. break;
  1276. case T_CURLY_OPEN:
  1277. case T_DOLLAR_OPEN_CURLY_BRACES:
  1278. case '{': $brace_level++; continue 2;
  1279. case '}':
  1280. $brace_level--;
  1281. if ($current_class_level == $brace_level) {
  1282. $current_class = '';
  1283. $current_class_level = -1;
  1284. }
  1285. if ($current_function_level == $brace_level) {
  1286. $current_function = '';
  1287. $current_function_level = -1;
  1288. }
  1289. continue 2;
  1290. case '[': $bracket_level++; continue 2;
  1291. case ']': $bracket_level--; continue 2;
  1292. case '(': $paren_level++; continue 2;
  1293. case ')': $paren_level--; continue 2;
  1294. case T_INTERFACE:
  1295. $interface = true;
  1296. case T_CLASS:
  1297. if (($current_class_level != -1) || ($current_function_level != -1)) {
  1298. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
  1299. array('file' => $file));
  1300. return false;
  1301. }
  1302. case T_FUNCTION:
  1303. case T_NEW:
  1304. case T_EXTENDS:
  1305. case T_IMPLEMENTS:
  1306. $look_for = $token;
  1307. continue 2;
  1308. case T_STRING:
  1309. if (version_compare(zend_version(), '2.0', '<')) {
  1310. if (in_array(strtolower($data),
  1311. array('public', 'private', 'protected', 'abstract',
  1312. 'interface', 'implements', 'throw')
  1313. )) {
  1314. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5,
  1315. array($file));
  1316. }
  1317. }
  1318. if ($look_for == T_CLASS) {
  1319. $current_class = $data;
  1320. $current_class_level = $brace_level;
  1321. $declared_classes[] = $current_class;
  1322. } elseif ($look_for == T_INTERFACE) {
  1323. $current_interface = $data;
  1324. $current_class_level = $brace_level;
  1325. $declared_interfaces[] = $current_interface;
  1326. } elseif ($look_for == T_IMPLEMENTS) {
  1327. $implements[$current_class] = $data;
  1328. } elseif ($look_for == T_EXTENDS) {
  1329. $extends[$current_class] = $data;
  1330. } elseif ($look_for == T_FUNCTION) {
  1331. if ($current_class) {
  1332. $current_function = "$current_class::$data";
  1333. $declared_methods[$current_class][] = $data;
  1334. } elseif ($current_interface) {
  1335. $current_function = "$current_interface::$data";
  1336. $declared_methods[$current_interface][] = $data;
  1337. } else {
  1338. $current_function = $data;
  1339. $declared_functions[] = $current_function;
  1340. }
  1341. $current_function_level = $brace_level;
  1342. $m = array();
  1343. } elseif ($look_for == T_NEW) {
  1344. $used_classes[$data] = true;
  1345. }
  1346. $look_for = 0;
  1347. continue 2;
  1348. case T_VARIABLE:
  1349. $look_for = 0;
  1350. continue 2;
  1351. case T_DOC_COMMENT:
  1352. case T_COMMENT:
  1353. if (preg_match('!^/\*\*\s!', $data)) {
  1354. $lastphpdoc = $data;
  1355. if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  1356. $nodeps = array_merge($nodeps, $m[1]);
  1357. }
  1358. }
  1359. continue 2;
  1360. case T_DOUBLE_COLON:
  1361. if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
  1362. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
  1363. array('file' => $file));
  1364. return false;
  1365. }
  1366. $class = $tokens[$i - 1][1];
  1367. if (strtolower($class) != 'parent') {
  1368. $used_classes[$class] = true;
  1369. }
  1370. continue 2;
  1371. }
  1372. }
  1373. return array(
  1374. "source_file" => $file,
  1375. "declared_classes" => $declared_classes,
  1376. "declared_interfaces" => $declared_interfaces,
  1377. "declared_methods" => $declared_methods,
  1378. "declared_functions" => $declared_functions,
  1379. "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  1380. "inheritance" => $extends,
  1381. "implements" => $implements,
  1382. );
  1383. }
  1384. /**
  1385. * Build a "provides" array from data returned by
  1386. * analyzeSourceCode(). The format of the built array is like
  1387. * this:
  1388. *
  1389. * array(
  1390. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  1391. * ...
  1392. * )
  1393. *
  1394. *
  1395. * @param array $srcinfo array with information about a source file
  1396. * as returned by the analyzeSourceCode() method.
  1397. *
  1398. * @return void
  1399. *
  1400. * @access private
  1401. *
  1402. */
  1403. function _buildProvidesArray($srcinfo)
  1404. {
  1405. if (!$this->_isValid) {
  1406. return false;
  1407. }
  1408. $file = basename($srcinfo['source_file']);
  1409. $pn = $this->getPackage();
  1410. $pnl = strlen($pn);
  1411. foreach ($srcinfo['declared_classes'] as $class) {
  1412. $key = "class;$class";
  1413. if (isset($this->_packageInfo['provides'][$key])) {
  1414. continue;
  1415. }
  1416. $this->_packageInfo['provides'][$key] =
  1417. array('file'=> $file, 'type' => 'class', 'name' => $class);
  1418. if (isset($srcinfo['inheritance'][$class])) {
  1419. $this->_packageInfo['provides'][$key]['extends'] =
  1420. $srcinfo['inheritance'][$class];
  1421. }
  1422. }
  1423. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  1424. foreach ($methods as $method) {
  1425. $function = "$class::$method";
  1426. $key = "function;$function";
  1427. if ($method{0} == '_' || !strcasecmp($method, $class) ||
  1428. isset($this->_packageInfo['provides'][$key])) {
  1429. continue;
  1430. }
  1431. $this->_packageInfo['provides'][$key] =
  1432. array('file'=> $file, 'type' => 'function', 'name' => $function);
  1433. }
  1434. }
  1435. foreach ($srcinfo['declared_functions'] as $function) {
  1436. $key = "function;$function";
  1437. if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) {
  1438. continue;
  1439. }
  1440. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  1441. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  1442. }
  1443. $this->_packageInfo['provides'][$key] =
  1444. array('file'=> $file, 'type' => 'function', 'name' => $function);
  1445. }
  1446. }
  1447. // }}}
  1448. }
  1449. ?>