PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/common/libraries/plugin/pear/PEAR/PackageFile/v2/Validator.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 2256 lines | 2171 code | 19 blank | 66 comment | 278 complexity | 939495a9b98b68cb3755a54e99e0f7f4 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * PEAR_PackageFile_v2, package.xml version 2.0, read/write version
  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-2008 The PHP Group
  17. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  18. * @version CVS: $Id: Validator.php 137 2009-11-09 13:24:37Z vanpouckesven $
  19. * @link http://pear.php.net/package/PEAR
  20. * @since File available since Release 1.4.0a8
  21. */
  22. /**
  23. * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its
  24. * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller
  25. * @category pear
  26. * @package PEAR
  27. * @author Greg Beaver <cellog@php.net>
  28. * @copyright 1997-2008 The PHP Group
  29. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  30. * @version Release: 1.7.2
  31. * @link http://pear.php.net/package/PEAR
  32. * @since Class available since Release 1.4.0a8
  33. * @access private
  34. */
  35. class PEAR_PackageFile_v2_Validator
  36. {
  37. /**
  38. * @var array
  39. */
  40. var $_packageInfo;
  41. /**
  42. * @var PEAR_PackageFile_v2
  43. */
  44. var $_pf;
  45. /**
  46. * @var PEAR_ErrorStack
  47. */
  48. var $_stack;
  49. /**
  50. * @var int
  51. */
  52. var $_isValid = 0;
  53. /**
  54. * @var int
  55. */
  56. var $_filesValid = 0;
  57. /**
  58. * @var int
  59. */
  60. var $_curState = 0;
  61. /**
  62. * @param PEAR_PackageFile_v2
  63. * @param int
  64. */
  65. function validate(&$pf, $state = PEAR_VALIDATE_NORMAL)
  66. {
  67. $this->_pf = &$pf;
  68. $this->_curState = $state;
  69. $this->_packageInfo = $this->_pf->getArray();
  70. $this->_isValid = $this->_pf->_isValid;
  71. $this->_filesValid = $this->_pf->_filesValid;
  72. $this->_stack = &$pf->_stack;
  73. $this->_stack->getErrors(true);
  74. if (($this->_isValid & $state) == $state)
  75. {
  76. return true;
  77. }
  78. if (! isset($this->_packageInfo) || ! is_array($this->_packageInfo))
  79. {
  80. return false;
  81. }
  82. if (! isset($this->_packageInfo['attribs']['version']) || ($this->_packageInfo['attribs']['version'] != '2.0' && $this->_packageInfo['attribs']['version'] != '2.1'))
  83. {
  84. $this->_noPackageVersion();
  85. }
  86. $structure = array('name', 'channel|uri', '*extends', // can't be multiple, but this works fine
  87. 'summary', 'description', '+lead', // these all need content checks
  88. '*developer',
  89. '*contributor', '*helper', 'date', '*time', 'version', 'stability', 'license->?uri->?filesource',
  90. 'notes', 'contents', //special validation needed
  91. '*compatible', 'dependencies', //special validation needed
  92. '*usesrole', '*usestask', // reserve these for 1.4.0a1 to implement
  93. // this will allow a package.xml to gracefully say it
  94. // needs a certain package installed in order to implement a role or task
  95. '*providesextension',
  96. '*srcpackage|*srcuri',
  97. '+phprelease|+extsrcrelease|+extbinrelease|' . '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed
  98. '*changelog');
  99. $test = $this->_packageInfo;
  100. if (isset($test['dependencies']) && isset($test['dependencies']['required']) && isset($test['dependencies']['required']['pearinstaller']) && isset($test['dependencies']['required']['pearinstaller']['min']) && version_compare('1.7.2', $test['dependencies']['required']['pearinstaller']['min'], '<'))
  101. {
  102. $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']);
  103. return false;
  104. }
  105. // ignore post-installation array fields
  106. if (array_key_exists('filelist', $test))
  107. {
  108. unset($test['filelist']);
  109. }
  110. if (array_key_exists('_lastmodified', $test))
  111. {
  112. unset($test['_lastmodified']);
  113. }
  114. if (array_key_exists('#binarypackage', $test))
  115. {
  116. unset($test['#binarypackage']);
  117. }
  118. if (array_key_exists('old', $test))
  119. {
  120. unset($test['old']);
  121. }
  122. if (array_key_exists('_lastversion', $test))
  123. {
  124. unset($test['_lastversion']);
  125. }
  126. if (! $this->_stupidSchemaValidate($structure, $test, '<package>'))
  127. {
  128. return false;
  129. }
  130. if (empty($this->_packageInfo['name']))
  131. {
  132. $this->_tagCannotBeEmpty('name');
  133. }
  134. $test = isset($this->_packageInfo['uri']) ? 'uri' : 'channel';
  135. if (empty($this->_packageInfo[$test]))
  136. {
  137. $this->_tagCannotBeEmpty($test);
  138. }
  139. if (is_array($this->_packageInfo['license']) && (! isset($this->_packageInfo['license']['_content']) || empty($this->_packageInfo['license']['_content'])))
  140. {
  141. $this->_tagCannotBeEmpty('license');
  142. }
  143. elseif (empty($this->_packageInfo['license']))
  144. {
  145. $this->_tagCannotBeEmpty('license');
  146. }
  147. if (empty($this->_packageInfo['summary']))
  148. {
  149. $this->_tagCannotBeEmpty('summary');
  150. }
  151. if (empty($this->_packageInfo['description']))
  152. {
  153. $this->_tagCannotBeEmpty('description');
  154. }
  155. if (empty($this->_packageInfo['date']))
  156. {
  157. $this->_tagCannotBeEmpty('date');
  158. }
  159. if (empty($this->_packageInfo['notes']))
  160. {
  161. $this->_tagCannotBeEmpty('notes');
  162. }
  163. if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time']))
  164. {
  165. $this->_tagCannotBeEmpty('time');
  166. }
  167. if (isset($this->_packageInfo['dependencies']))
  168. {
  169. $this->_validateDependencies();
  170. }
  171. if (isset($this->_packageInfo['compatible']))
  172. {
  173. $this->_validateCompatible();
  174. }
  175. if (! isset($this->_packageInfo['bundle']))
  176. {
  177. if (empty($this->_packageInfo['contents']))
  178. {
  179. $this->_tagCannotBeEmpty('contents');
  180. }
  181. if (! isset($this->_packageInfo['contents']['dir']))
  182. {
  183. $this->_filelistMustContainDir('contents');
  184. return false;
  185. }
  186. if (isset($this->_packageInfo['contents']['file']))
  187. {
  188. $this->_filelistCannotContainFile('contents');
  189. return false;
  190. }
  191. }
  192. $this->_validateMaintainers();
  193. $this->_validateStabilityVersion();
  194. $fail = false;
  195. if (array_key_exists('usesrole', $this->_packageInfo))
  196. {
  197. $roles = $this->_packageInfo['usesrole'];
  198. if (! is_array($roles) || ! isset($roles[0]))
  199. {
  200. $roles = array($roles);
  201. }
  202. foreach ($roles as $role)
  203. {
  204. if (! isset($role['role']))
  205. {
  206. $this->_usesroletaskMustHaveRoleTask('usesrole', 'role');
  207. $fail = true;
  208. }
  209. else
  210. {
  211. if (! isset($role['channel']))
  212. {
  213. if (! isset($role['uri']))
  214. {
  215. $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole');
  216. $fail = true;
  217. }
  218. }
  219. elseif (! isset($role['package']))
  220. {
  221. $this->_usesroletaskMustHavePackage($role['role'], 'usesrole');
  222. $fail = true;
  223. }
  224. }
  225. }
  226. }
  227. if (array_key_exists('usestask', $this->_packageInfo))
  228. {
  229. $roles = $this->_packageInfo['usestask'];
  230. if (! is_array($roles) || ! isset($roles[0]))
  231. {
  232. $roles = array($roles);
  233. }
  234. foreach ($roles as $role)
  235. {
  236. if (! isset($role['task']))
  237. {
  238. $this->_usesroletaskMustHaveRoleTask('usestask', 'task');
  239. $fail = true;
  240. }
  241. else
  242. {
  243. if (! isset($role['channel']))
  244. {
  245. if (! isset($role['uri']))
  246. {
  247. $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask');
  248. $fail = true;
  249. }
  250. }
  251. elseif (! isset($role['package']))
  252. {
  253. $this->_usesroletaskMustHavePackage($role['task'], 'usestask');
  254. $fail = true;
  255. }
  256. }
  257. }
  258. }
  259. if ($fail)
  260. {
  261. return false;
  262. }
  263. $list = $this->_packageInfo['contents'];
  264. if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0]))
  265. {
  266. $this->_multipleToplevelDirNotAllowed();
  267. return $this->_isValid = 0;
  268. }
  269. $this->_validateFilelist();
  270. $this->_validateRelease();
  271. if (! $this->_stack->hasErrors())
  272. {
  273. $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true);
  274. if (PEAR :: isError($chan))
  275. {
  276. $this->_unknownChannel($this->_pf->getChannel());
  277. }
  278. else
  279. {
  280. $valpack = $chan->getValidationPackage();
  281. // for channel validator packages, always use the default PEAR validator.
  282. // otherwise, they can't be installed or packaged
  283. $validator = $chan->getValidationObject($this->_pf->getPackage());
  284. if (! $validator)
  285. {
  286. $this->_stack->push(__FUNCTION__, 'error', array_merge(array('channel' => $chan->getName(),
  287. 'package' => $this->_pf->getPackage()), $valpack), 'package "%channel%/%package%" cannot be properly validated without ' . 'validation package "%channel%/%name%-%version%"');
  288. return $this->_isValid = 0;
  289. }
  290. $validator->setPackageFile($this->_pf);
  291. $validator->validate($state);
  292. $failures = $validator->getFailures();
  293. foreach ($failures['errors'] as $error)
  294. {
  295. $this->_stack->push(__FUNCTION__, 'error', $error, 'Channel validator error: field "%field%" - %reason%');
  296. }
  297. foreach ($failures['warnings'] as $warning)
  298. {
  299. $this->_stack->push(__FUNCTION__, 'warning', $warning, 'Channel validator warning: field "%field%" - %reason%');
  300. }
  301. }
  302. }
  303. $this->_pf->_isValid = $this->_isValid = ! $this->_stack->hasErrors('error');
  304. if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && ! $this->_filesValid)
  305. {
  306. if ($this->_pf->getPackageType() == 'bundle')
  307. {
  308. if ($this->_analyzeBundledPackages())
  309. {
  310. $this->_filesValid = $this->_pf->_filesValid = true;
  311. }
  312. else
  313. {
  314. $this->_pf->_isValid = $this->_isValid = 0;
  315. }
  316. }
  317. else
  318. {
  319. if (! $this->_analyzePhpFiles())
  320. {
  321. $this->_pf->_isValid = $this->_isValid = 0;
  322. }
  323. else
  324. {
  325. $this->_filesValid = $this->_pf->_filesValid = true;
  326. }
  327. }
  328. }
  329. if ($this->_isValid)
  330. {
  331. return $this->_pf->_isValid = $this->_isValid = $state;
  332. }
  333. return $this->_pf->_isValid = $this->_isValid = 0;
  334. }
  335. function _stupidSchemaValidate($structure, $xml, $root)
  336. {
  337. if (! is_array($xml))
  338. {
  339. $xml = array();
  340. }
  341. $keys = array_keys($xml);
  342. reset($keys);
  343. $key = current($keys);
  344. while ($key == 'attribs' || $key == '_contents')
  345. {
  346. $key = next($keys);
  347. }
  348. $unfoundtags = $optionaltags = array();
  349. $ret = true;
  350. $mismatch = false;
  351. foreach ($structure as $struc)
  352. {
  353. if ($key)
  354. {
  355. $tag = $xml[$key];
  356. }
  357. $test = $this->_processStructure($struc);
  358. if (isset($test['choices']))
  359. {
  360. $loose = true;
  361. foreach ($test['choices'] as $choice)
  362. {
  363. if ($key == $choice['tag'])
  364. {
  365. $key = next($keys);
  366. while ($key == 'attribs' || $key == '_contents')
  367. {
  368. $key = next($keys);
  369. }
  370. $unfoundtags = $optionaltags = array();
  371. $mismatch = false;
  372. if ($key && $key != $choice['tag'] && isset($choice['multiple']))
  373. {
  374. $unfoundtags[] = $choice['tag'];
  375. $optionaltags[] = $choice['tag'];
  376. if ($key)
  377. {
  378. $mismatch = true;
  379. }
  380. }
  381. $ret &= $this->_processAttribs($choice, $tag, $root);
  382. continue 2;
  383. }
  384. else
  385. {
  386. $unfoundtags[] = $choice['tag'];
  387. $mismatch = true;
  388. }
  389. if (! isset($choice['multiple']) || $choice['multiple'] != '*')
  390. {
  391. $loose = false;
  392. }
  393. else
  394. {
  395. $optionaltags[] = $choice['tag'];
  396. }
  397. }
  398. if (! $loose)
  399. {
  400. $this->_invalidTagOrder($unfoundtags, $key, $root);
  401. return false;
  402. }
  403. }
  404. else
  405. {
  406. if ($key != $test['tag'])
  407. {
  408. if (isset($test['multiple']) && $test['multiple'] != '*')
  409. {
  410. $unfoundtags[] = $test['tag'];
  411. $this->_invalidTagOrder($unfoundtags, $key, $root);
  412. return false;
  413. }
  414. else
  415. {
  416. if ($key)
  417. {
  418. $mismatch = true;
  419. }
  420. $unfoundtags[] = $test['tag'];
  421. $optionaltags[] = $test['tag'];
  422. }
  423. if (! isset($test['multiple']))
  424. {
  425. $this->_invalidTagOrder($unfoundtags, $key, $root);
  426. return false;
  427. }
  428. continue;
  429. }
  430. else
  431. {
  432. $unfoundtags = $optionaltags = array();
  433. $mismatch = false;
  434. }
  435. $key = next($keys);
  436. while ($key == 'attribs' || $key == '_contents')
  437. {
  438. $key = next($keys);
  439. }
  440. if ($key && $key != $test['tag'] && isset($test['multiple']))
  441. {
  442. $unfoundtags[] = $test['tag'];
  443. $optionaltags[] = $test['tag'];
  444. $mismatch = true;
  445. }
  446. $ret &= $this->_processAttribs($test, $tag, $root);
  447. continue;
  448. }
  449. }
  450. if (! $mismatch && count($optionaltags))
  451. {
  452. // don't error out on any optional tags
  453. $unfoundtags = array_diff($unfoundtags, $optionaltags);
  454. }
  455. if (count($unfoundtags))
  456. {
  457. $this->_invalidTagOrder($unfoundtags, $key, $root);
  458. }
  459. elseif ($key)
  460. {
  461. // unknown tags
  462. $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
  463. while ($key = next($keys))
  464. {
  465. $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
  466. }
  467. }
  468. return $ret;
  469. }
  470. function _processAttribs($choice, $tag, $context)
  471. {
  472. if (isset($choice['attribs']))
  473. {
  474. if (! is_array($tag))
  475. {
  476. $tag = array($tag);
  477. }
  478. $tags = $tag;
  479. if (! isset($tags[0]))
  480. {
  481. $tags = array($tags);
  482. }
  483. $ret = true;
  484. foreach ($tags as $i => $tag)
  485. {
  486. if (! is_array($tag) || ! isset($tag['attribs']))
  487. {
  488. foreach ($choice['attribs'] as $attrib)
  489. {
  490. if ($attrib{0} != '?')
  491. {
  492. $ret &= $this->_tagHasNoAttribs($choice['tag'], $context);
  493. continue 2;
  494. }
  495. }
  496. }
  497. foreach ($choice['attribs'] as $attrib)
  498. {
  499. if ($attrib{0} != '?')
  500. {
  501. if (! isset($tag['attribs'][$attrib]))
  502. {
  503. $ret &= $this->_tagMissingAttribute($choice['tag'], $attrib, $context);
  504. }
  505. }
  506. }
  507. }
  508. return $ret;
  509. }
  510. return true;
  511. }
  512. function _processStructure($key)
  513. {
  514. $ret = array();
  515. if (count($pieces = explode('|', $key)) > 1)
  516. {
  517. $ret['choices'] = array();
  518. foreach ($pieces as $piece)
  519. {
  520. $ret['choices'][] = $this->_processStructure($piece);
  521. }
  522. return $ret;
  523. }
  524. $multi = $key{0};
  525. if ($multi == '+' || $multi == '*')
  526. {
  527. $ret['multiple'] = $key{0};
  528. $key = substr($key, 1);
  529. }
  530. if (count($attrs = explode('->', $key)) > 1)
  531. {
  532. $ret['tag'] = array_shift($attrs);
  533. $ret['attribs'] = $attrs;
  534. }
  535. else
  536. {
  537. $ret['tag'] = $key;
  538. }
  539. return $ret;
  540. }
  541. function _validateStabilityVersion()
  542. {
  543. $structure = array('release', 'api');
  544. $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], '<version>');
  545. $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '<stability>');
  546. if ($a)
  547. {
  548. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $this->_packageInfo['version']['release']))
  549. {
  550. $this->_invalidVersion('release', $this->_packageInfo['version']['release']);
  551. }
  552. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $this->_packageInfo['version']['api']))
  553. {
  554. $this->_invalidVersion('api', $this->_packageInfo['version']['api']);
  555. }
  556. if (! in_array($this->_packageInfo['stability']['release'], array('snapshot', 'devel', 'alpha', 'beta',
  557. 'stable')))
  558. {
  559. $this->_invalidState('release', $this->_packageInfo['stability']['release']);
  560. }
  561. if (! in_array($this->_packageInfo['stability']['api'], array('devel', 'alpha', 'beta', 'stable')))
  562. {
  563. $this->_invalidState('api', $this->_packageInfo['stability']['api']);
  564. }
  565. }
  566. }
  567. function _validateMaintainers()
  568. {
  569. $structure = array('name', 'user', 'email', 'active');
  570. foreach (array('lead', 'developer', 'contributor', 'helper') as $type)
  571. {
  572. if (! isset($this->_packageInfo[$type]))
  573. {
  574. continue;
  575. }
  576. if (isset($this->_packageInfo[$type][0]))
  577. {
  578. foreach ($this->_packageInfo[$type] as $lead)
  579. {
  580. $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>');
  581. }
  582. }
  583. else
  584. {
  585. $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type], '<' . $type . '>');
  586. }
  587. }
  588. }
  589. function _validatePhpDep($dep, $installcondition = false)
  590. {
  591. $structure = array('min', '*max', '*exclude');
  592. $type = $installcondition ? '<installcondition><php>' : '<dependencies><required><php>';
  593. $this->_stupidSchemaValidate($structure, $dep, $type);
  594. if (isset($dep['min']))
  595. {
  596. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', $dep['min']))
  597. {
  598. $this->_invalidVersion($type . '<min>', $dep['min']);
  599. }
  600. }
  601. if (isset($dep['max']))
  602. {
  603. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', $dep['max']))
  604. {
  605. $this->_invalidVersion($type . '<max>', $dep['max']);
  606. }
  607. }
  608. if (isset($dep['exclude']))
  609. {
  610. if (! is_array($dep['exclude']))
  611. {
  612. $dep['exclude'] = array($dep['exclude']);
  613. }
  614. foreach ($dep['exclude'] as $exclude)
  615. {
  616. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', $exclude))
  617. {
  618. $this->_invalidVersion($type . '<exclude>', $exclude);
  619. }
  620. }
  621. }
  622. }
  623. function _validatePearinstallerDep($dep)
  624. {
  625. $structure = array('min', '*max', '*recommended', '*exclude');
  626. $this->_stupidSchemaValidate($structure, $dep, '<dependencies><required><pearinstaller>');
  627. if (isset($dep['min']))
  628. {
  629. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['min']))
  630. {
  631. $this->_invalidVersion('<dependencies><required><pearinstaller><min>', $dep['min']);
  632. }
  633. }
  634. if (isset($dep['max']))
  635. {
  636. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['max']))
  637. {
  638. $this->_invalidVersion('<dependencies><required><pearinstaller><max>', $dep['max']);
  639. }
  640. }
  641. if (isset($dep['recommended']))
  642. {
  643. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['recommended']))
  644. {
  645. $this->_invalidVersion('<dependencies><required><pearinstaller><recommended>', $dep['recommended']);
  646. }
  647. }
  648. if (isset($dep['exclude']))
  649. {
  650. if (! is_array($dep['exclude']))
  651. {
  652. $dep['exclude'] = array($dep['exclude']);
  653. }
  654. foreach ($dep['exclude'] as $exclude)
  655. {
  656. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $exclude))
  657. {
  658. $this->_invalidVersion('<dependencies><required><pearinstaller><exclude>', $exclude);
  659. }
  660. }
  661. }
  662. }
  663. function _validatePackageDep($dep, $group, $type = '<package>')
  664. {
  665. if (isset($dep['uri']))
  666. {
  667. if (isset($dep['conflicts']))
  668. {
  669. $structure = array('name', 'uri', 'conflicts', '*providesextension');
  670. }
  671. else
  672. {
  673. $structure = array('name', 'uri', '*providesextension');
  674. }
  675. }
  676. else
  677. {
  678. if (isset($dep['conflicts']))
  679. {
  680. $structure = array('name', 'channel', '*min', '*max', '*exclude', 'conflicts', '*providesextension');
  681. }
  682. else
  683. {
  684. $structure = array('name', 'channel', '*min', '*max', '*recommended', '*exclude', '*nodefault',
  685. '*providesextension');
  686. }
  687. }
  688. if (isset($dep['name']))
  689. {
  690. $type .= '<name>' . $dep['name'] . '</name>';
  691. }
  692. $this->_stupidSchemaValidate($structure, $dep, '<dependencies>' . $group . $type);
  693. if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || isset($dep['recommended']) || isset($dep['exclude'])))
  694. {
  695. $this->_uriDepsCannotHaveVersioning('<dependencies>' . $group . $type);
  696. }
  697. if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri')
  698. {
  699. $this->_DepchannelCannotBeUri('<dependencies>' . $group . $type);
  700. }
  701. if (isset($dep['min']))
  702. {
  703. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['min']))
  704. {
  705. $this->_invalidVersion('<dependencies>' . $group . $type . '<min>', $dep['min']);
  706. }
  707. }
  708. if (isset($dep['max']))
  709. {
  710. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['max']))
  711. {
  712. $this->_invalidVersion('<dependencies>' . $group . $type . '<max>', $dep['max']);
  713. }
  714. }
  715. if (isset($dep['recommended']))
  716. {
  717. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['recommended']))
  718. {
  719. $this->_invalidVersion('<dependencies>' . $group . $type . '<recommended>', $dep['recommended']);
  720. }
  721. }
  722. if (isset($dep['exclude']))
  723. {
  724. if (! is_array($dep['exclude']))
  725. {
  726. $dep['exclude'] = array($dep['exclude']);
  727. }
  728. foreach ($dep['exclude'] as $exclude)
  729. {
  730. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $exclude))
  731. {
  732. $this->_invalidVersion('<dependencies>' . $group . $type . '<exclude>', $exclude);
  733. }
  734. }
  735. }
  736. }
  737. function _validateSubpackageDep($dep, $group)
  738. {
  739. $this->_validatePackageDep($dep, $group, '<subpackage>');
  740. if (isset($dep['providesextension']))
  741. {
  742. $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : '');
  743. }
  744. if (isset($dep['conflicts']))
  745. {
  746. $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : '');
  747. }
  748. }
  749. function _validateExtensionDep($dep, $group = false, $installcondition = false)
  750. {
  751. if (isset($dep['conflicts']))
  752. {
  753. $structure = array('name', '*min', '*max', '*exclude', 'conflicts');
  754. }
  755. else
  756. {
  757. $structure = array('name', '*min', '*max', '*recommended', '*exclude');
  758. }
  759. if ($installcondition)
  760. {
  761. $type = '<installcondition><extension>';
  762. }
  763. else
  764. {
  765. $type = '<dependencies>' . $group . '<extension>';
  766. }
  767. if (isset($dep['name']))
  768. {
  769. $type .= '<name>' . $dep['name'] . '</name>';
  770. }
  771. $this->_stupidSchemaValidate($structure, $dep, $type);
  772. if (isset($dep['min']))
  773. {
  774. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['min']))
  775. {
  776. $this->_invalidVersion(substr($type, 1) . '<min', $dep['min']);
  777. }
  778. }
  779. if (isset($dep['max']))
  780. {
  781. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['max']))
  782. {
  783. $this->_invalidVersion(substr($type, 1) . '<max', $dep['max']);
  784. }
  785. }
  786. if (isset($dep['recommended']))
  787. {
  788. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $dep['recommended']))
  789. {
  790. $this->_invalidVersion(substr($type, 1) . '<recommended', $dep['recommended']);
  791. }
  792. }
  793. if (isset($dep['exclude']))
  794. {
  795. if (! is_array($dep['exclude']))
  796. {
  797. $dep['exclude'] = array($dep['exclude']);
  798. }
  799. foreach ($dep['exclude'] as $exclude)
  800. {
  801. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $exclude))
  802. {
  803. $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
  804. }
  805. }
  806. }
  807. }
  808. function _validateOsDep($dep, $installcondition = false)
  809. {
  810. $structure = array('name', '*conflicts');
  811. $type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>';
  812. if ($this->_stupidSchemaValidate($structure, $dep, $type))
  813. {
  814. if ($dep['name'] == '*')
  815. {
  816. if (array_key_exists('conflicts', $dep))
  817. {
  818. $this->_cannotConflictWithAllOs($type);
  819. }
  820. }
  821. }
  822. }
  823. function _validateArchDep($dep, $installcondition = false)
  824. {
  825. $structure = array('pattern', '*conflicts');
  826. $type = $installcondition ? '<installcondition><arch>' : '<dependencies><required><arch>';
  827. $this->_stupidSchemaValidate($structure, $dep, $type);
  828. }
  829. function _validateInstallConditions($cond, $release)
  830. {
  831. $structure = array('*php', '*extension', '*os', '*arch');
  832. if (! $this->_stupidSchemaValidate($structure, $cond, $release))
  833. {
  834. return false;
  835. }
  836. foreach (array('php', 'extension', 'os', 'arch') as $type)
  837. {
  838. if (isset($cond[$type]))
  839. {
  840. $iter = $cond[$type];
  841. if (! is_array($iter) || ! isset($iter[0]))
  842. {
  843. $iter = array($iter);
  844. }
  845. foreach ($iter as $package)
  846. {
  847. if ($type == 'extension')
  848. {
  849. $this->{"_validate{$type}Dep"}($package, false, true);
  850. }
  851. else
  852. {
  853. $this->{"_validate{$type}Dep"}($package, true);
  854. }
  855. }
  856. }
  857. }
  858. }
  859. function _validateDependencies()
  860. {
  861. $structure = array('required', '*optional', '*group->name->hint');
  862. if (! $this->_stupidSchemaValidate($structure, $this->_packageInfo['dependencies'], '<dependencies>'))
  863. {
  864. return false;
  865. }
  866. foreach (array('required', 'optional') as $simpledep)
  867. {
  868. if (isset($this->_packageInfo['dependencies'][$simpledep]))
  869. {
  870. if ($simpledep == 'optional')
  871. {
  872. $structure = array('*package', '*subpackage', '*extension');
  873. }
  874. else
  875. {
  876. $structure = array('php', 'pearinstaller', '*package', '*subpackage', '*extension', '*os', '*arch');
  877. }
  878. if ($this->_stupidSchemaValidate($structure, $this->_packageInfo['dependencies'][$simpledep], "<dependencies><$simpledep>"))
  879. {
  880. foreach (array('package', 'subpackage', 'extension') as $type)
  881. {
  882. if (isset($this->_packageInfo['dependencies'][$simpledep][$type]))
  883. {
  884. $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
  885. if (! isset($iter[0]))
  886. {
  887. $iter = array($iter);
  888. }
  889. foreach ($iter as $package)
  890. {
  891. if ($type != 'extension')
  892. {
  893. if (isset($package['uri']))
  894. {
  895. if (isset($package['channel']))
  896. {
  897. $this->_UrlOrChannel($type, $package['name']);
  898. }
  899. }
  900. else
  901. {
  902. if (! isset($package['channel']))
  903. {
  904. $this->_NoChannel($type, $package['name']);
  905. }
  906. }
  907. }
  908. $this->{"_validate{$type}Dep"}($package, "<$simpledep>");
  909. }
  910. }
  911. }
  912. if ($simpledep == 'optional')
  913. {
  914. continue;
  915. }
  916. foreach (array('php', 'pearinstaller', 'os', 'arch') as $type)
  917. {
  918. if (isset($this->_packageInfo['dependencies'][$simpledep][$type]))
  919. {
  920. $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
  921. if (! isset($iter[0]))
  922. {
  923. $iter = array($iter);
  924. }
  925. foreach ($iter as $package)
  926. {
  927. $this->{"_validate{$type}Dep"}($package);
  928. }
  929. }
  930. }
  931. }
  932. }
  933. }
  934. if (isset($this->_packageInfo['dependencies']['group']))
  935. {
  936. $groups = $this->_packageInfo['dependencies']['group'];
  937. if (! isset($groups[0]))
  938. {
  939. $groups = array($groups);
  940. }
  941. $structure = array('*package', '*subpackage', '*extension');
  942. foreach ($groups as $group)
  943. {
  944. if ($this->_stupidSchemaValidate($structure, $group, '<group>'))
  945. {
  946. if (! PEAR_Validate :: validGroupName($group['attribs']['name']))
  947. {
  948. $this->_invalidDepGroupName($group['attribs']['name']);
  949. }
  950. foreach (array('package', 'subpackage', 'extension') as $type)
  951. {
  952. if (isset($group[$type]))
  953. {
  954. $iter = $group[$type];
  955. if (! isset($iter[0]))
  956. {
  957. $iter = array($iter);
  958. }
  959. foreach ($iter as $package)
  960. {
  961. if ($type != 'extension')
  962. {
  963. if (isset($package['uri']))
  964. {
  965. if (isset($package['channel']))
  966. {
  967. $this->_UrlOrChannelGroup($type, $package['name'], $group['name']);
  968. }
  969. }
  970. else
  971. {
  972. if (! isset($package['channel']))
  973. {
  974. $this->_NoChannelGroup($type, $package['name'], $group['name']);
  975. }
  976. }
  977. }
  978. $this->{"_validate{$type}Dep"}($package, '<group name="' . $group['attribs']['name'] . '">');
  979. }
  980. }
  981. }
  982. }
  983. }
  984. }
  985. }
  986. function _validateCompatible()
  987. {
  988. $compat = $this->_packageInfo['compatible'];
  989. if (! isset($compat[0]))
  990. {
  991. $compat = array($compat);
  992. }
  993. $required = array('name', 'channel', 'min', 'max', '*exclude');
  994. foreach ($compat as $package)
  995. {
  996. $type = '<compatible>';
  997. if (is_array($package) && array_key_exists('name', $package))
  998. {
  999. $type .= '<name>' . $package['name'] . '</name>';
  1000. }
  1001. $this->_stupidSchemaValidate($required, $package, $type);
  1002. if (is_array($package) && array_key_exists('min', $package))
  1003. {
  1004. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $package['min']))
  1005. {
  1006. $this->_invalidVersion(substr($type, 1) . '<min', $package['min']);
  1007. }
  1008. }
  1009. if (is_array($package) && array_key_exists('max', $package))
  1010. {
  1011. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $package['max']))
  1012. {
  1013. $this->_invalidVersion(substr($type, 1) . '<max', $package['max']);
  1014. }
  1015. }
  1016. if (is_array($package) && array_key_exists('exclude', $package))
  1017. {
  1018. if (! is_array($package['exclude']))
  1019. {
  1020. $package['exclude'] = array($package['exclude']);
  1021. }
  1022. foreach ($package['exclude'] as $exclude)
  1023. {
  1024. if (! preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', $exclude))
  1025. {
  1026. $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
  1027. }
  1028. }
  1029. }
  1030. }
  1031. }
  1032. function _validateBundle($list)
  1033. {
  1034. if (! is_array($list) || ! isset($list['bundledpackage']))
  1035. {
  1036. return $this->_NoBundledPackages();
  1037. }
  1038. if (! is_array($list['bundledpackage']) || ! isset($list['bundledpackage'][0]))
  1039. {
  1040. return $this->_AtLeast2BundledPackages();
  1041. }
  1042. foreach ($list['bundledpackage'] as $package)
  1043. {
  1044. if (! is_string($package))
  1045. {
  1046. $this->_bundledPackagesMustBeFilename();
  1047. }
  1048. }
  1049. }
  1050. function _validateFilelist($list = false, $allowignore = false, $dirs = '')
  1051. {
  1052. $iscontents = false;
  1053. if (! $list)
  1054. {
  1055. $iscontents = true;
  1056. $list = $this->_packageInfo['contents'];
  1057. if (isset($this->_packageInfo['bundle']))
  1058. {
  1059. return $this->_validateBundle($list);
  1060. }
  1061. }
  1062. if ($allowignore)
  1063. {
  1064. $struc = array('*install->name->as', '*ignore->name');
  1065. }
  1066. else
  1067. {
  1068. $struc = array('*dir->name->?baseinstalldir', '*file->name->role->?baseinstalldir->?md5sum');
  1069. if (isset($list['dir']) && isset($list['file']))
  1070. {
  1071. // stave off validation errors without requiring a set order.
  1072. $_old = $list;
  1073. if (isset($list['attribs']))
  1074. {
  1075. $list = array('attribs' => $_old['attribs']);
  1076. }
  1077. $list['dir'] = $_old['dir'];
  1078. $list['file'] = $_old['file'];
  1079. }
  1080. }
  1081. if (! isset($list['attribs']) || ! isset($list['attribs']['name']))
  1082. {
  1083. $unknown = $allowignore ? '<filelist>' : '<dir name="*unknown*">';
  1084. $dirname = $iscontents ? '<contents>' : $unknown;
  1085. }
  1086. else
  1087. {
  1088. $dirname = '<dir name="' . $list['attribs']['name'] . '">';
  1089. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $list['attribs']['name'])))
  1090. {
  1091. // file contains .. parent directory or . cur directory
  1092. $this->_invalidDirName($list['attribs']['name']);
  1093. }
  1094. }
  1095. $res = $this->_stupidSchemaValidate($struc, $list, $dirname);
  1096. if ($allowignore && $res)
  1097. {
  1098. $ignored_or_installed = array();
  1099. $this->_pf->getFilelist();
  1100. $fcontents = $this->_pf->getContents();
  1101. $filelist = array();
  1102. if (! isset($fcontents['dir']['file'][0]))
  1103. {
  1104. $fcontents['dir']['file'] = array($fcontents['dir']['file']);
  1105. }
  1106. foreach ($fcontents['dir']['file'] as $file)
  1107. {
  1108. $filelist[$file['attribs']['name']] = true;
  1109. }
  1110. if (isset($list['install']))
  1111. {
  1112. if (! isset($list['install'][0]))
  1113. {
  1114. $list['install'] = array($list['install']);
  1115. }
  1116. foreach ($list['install'] as $file)
  1117. {
  1118. if (! isset($filelist[$file['attribs']['name']]))
  1119. {
  1120. $this->_notInContents($file['attribs']['name'], 'install');
  1121. continue;
  1122. }
  1123. if (array_key_exists($file['attribs']['name'], $ignored_or_installed))
  1124. {
  1125. $this->_multipleInstallAs($file['attribs']['name']);
  1126. }
  1127. if (! isset($ignored_or_installed[$file['attribs']['name']]))
  1128. {
  1129. $ignored_or_installed[$file['attribs']['name']] = array();
  1130. }
  1131. $ignored_or_installed[$file['attribs']['name']][] = 1;
  1132. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file['attribs']['as'])))
  1133. {
  1134. // file contains .. parent directory or . cur directory references
  1135. $this->_invalidFileInstallAs($file['attribs']['name'], $file['attribs']['as']);
  1136. }
  1137. }
  1138. }
  1139. if (isset($list['ignore']))
  1140. {
  1141. if (! isset($list['ignore'][0]))
  1142. {
  1143. $list['ignore'] = array($list['ignore']);
  1144. }
  1145. foreach ($list['ignore'] as $file)
  1146. {
  1147. if (! isset($filelist[$file['attribs']['name']]))
  1148. {
  1149. $this->_notInContents($file['attribs']['name'], 'ignore');
  1150. continue;
  1151. }
  1152. if (array_key_exists($file['attribs']['name'], $ignored_or_installed))
  1153. {
  1154. $this->_ignoreAndInstallAs($file['attribs']['name']);
  1155. }
  1156. }
  1157. }
  1158. }
  1159. if (! $allowignore && isset($list['file']))
  1160. {
  1161. if (is_string($list['file']))
  1162. {
  1163. $this->_oldStyleFileNotAllowed();
  1164. return false;
  1165. }
  1166. if (! isset($list['file'][0]))
  1167. {
  1168. // single file
  1169. $list['file'] = array($list['file']);
  1170. }
  1171. foreach ($list['file'] as $i => $file)
  1172. {
  1173. if (isset($file['attribs']) && isset($file['attribs']['name']))
  1174. {
  1175. if ($file['attribs']['name']{0} == '.' && $file['attribs']['name']{1} == '/')
  1176. {
  1177. // name is something like "./doc/whatever.txt"
  1178. $this->_invalidFileName($file['attribs']['name'], $dirname);
  1179. }
  1180. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file['attribs']['name'])))
  1181. {
  1182. // file contains .. parent directory or . cur directory
  1183. $this->_invalidFileName($file['attribs']['name'], $dirname);
  1184. }
  1185. }
  1186. if (isset($file['attribs']) && isset($file['attribs']['role']))
  1187. {
  1188. if (! $this->_validateRole($file['attribs']['role']))
  1189. {
  1190. if (isset($this->_packageInfo['usesrole']))
  1191. {
  1192. $roles = $this->_packageInfo['usesrole'];
  1193. if (! isset($roles[0]))
  1194. {
  1195. $roles = array($roles);
  1196. }
  1197. foreach ($roles as $role)
  1198. {
  1199. if ($role['role'] = $file['attribs']['role'])
  1200. {
  1201. $msg = 'This package contains role "%role%" and requires ' . 'package "%package%" to be used';
  1202. if (isset($role['uri']))
  1203. {
  1204. $params = array('role' => $role['role'], 'package' => $role['uri']);
  1205. }
  1206. else
  1207. {
  1208. $params = array('role' => $role['role'],
  1209. 'package' => $this->_pf->_registry->parsedPackageNameToString(array(
  1210. 'package' => $role['package'], 'channel' => $role['channel']), true));
  1211. }
  1212. $this->_stack->push('_mustInstallRole', 'error', $params, $msg);
  1213. }
  1214. }
  1215. }
  1216. $this->_invalidFileRole($file['attribs']['name'], $dirname, $file['attribs']['role']);
  1217. }
  1218. }
  1219. if (! isset($file['attribs']))
  1220. {
  1221. continue;
  1222. }
  1223. $save = $file['attribs'];
  1224. if ($dirs)
  1225. {
  1226. $save['name'] = $dirs . '/' . $save['name'];
  1227. }
  1228. unset($file['attribs']);
  1229. if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING)
  1230. { // has tasks
  1231. foreach ($file as $task => $value)
  1232. {
  1233. if ($tagClass = $this->_pf->getTask($task))
  1234. {
  1235. if (! is_array($value) || ! isset($value[0]))
  1236. {
  1237. $value = array($value);
  1238. }
  1239. foreach ($value as $v)
  1240. {
  1241. $ret = call_user_func(array($tagClass, 'validateXml'), $this->_pf, $v, $this->_pf->_config, $save);
  1242. if (is_array($ret))
  1243. {
  1244. $this->_invalidTask($task, $ret, isset($save['name']) ? $save['name'] : '');
  1245. }
  1246. }
  1247. }
  1248. else
  1249. {
  1250. if (isset($this->_packageInfo['usestask']))
  1251. {
  1252. $roles = $this->_packageInfo['usestask'];
  1253. if (! isset($roles[0]))
  1254. {
  1255. $roles = array($roles);
  1256. }
  1257. foreach ($roles as $role)
  1258. {
  1259. if ($role['task'] = $task)
  1260. {
  1261. $msg = 'This package contains task "%task%" and requires ' . 'package "%package%" to be used';
  1262. if (isset($role['uri']))
  1263. {
  1264. $params = array('task' => $role['task'], 'package' => $role['uri']);
  1265. }

Large files files are truncated, but you can click here to view the full file