PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/pear/PEAR/PackageFile/v1.php

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