PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/PEAR/PEAR/PackageFile/v1.php

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