PageRenderTime 69ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/pear/PEAR/PackageFile/v1.php

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