PageRenderTime 32ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/inc/app/siteinvoice/lib/PEAR/PEAR/Downloader/Package.php

https://github.com/lux/sitellite
PHP | 1605 lines | 1350 code | 46 blank | 209 comment | 358 complexity | adbf3946360600a2f4887772cd943ef6 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, GPL-3.0
  1. <?php
  2. /**
  3. * PEAR_Downloader_Package
  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: Package.php,v 1.1 2005/07/02 21:12:31 lux Exp $
  19. * @link http://pear.php.net/package/PEAR
  20. * @since File available since Release 1.4.0a1
  21. */
  22. /**
  23. * Coordinates download parameters and manages their dependencies
  24. * prior to downloading them.
  25. *
  26. * Input can come from three sources:
  27. *
  28. * - local files (archives or package.xml)
  29. * - remote files (downloadable urls)
  30. * - abstract package names
  31. *
  32. * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  33. * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  34. * format returned of dependencies is slightly different from that used in package.xml.
  35. *
  36. * This class hides the differences between these elements, and makes automatic
  37. * dependency resolution a piece of cake. It also manages conflicts when
  38. * two classes depend on incompatible dependencies, or differing versions of the same
  39. * package dependency. In addition, download will not be attempted if the php version is
  40. * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  41. * installed.
  42. * @category pear
  43. * @package PEAR
  44. * @author Greg Beaver <cellog@php.net>
  45. * @copyright 1997-2005 The PHP Group
  46. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  47. * @version Release: 1.4.0a12
  48. * @link http://pear.php.net/package/PEAR
  49. * @since Class available since Release 1.4.0a1
  50. */
  51. class PEAR_Downloader_Package
  52. {
  53. /**
  54. * @var PEAR_Downloader
  55. */
  56. var $_downloader;
  57. /**
  58. * @var PEAR_Config
  59. */
  60. var $_config;
  61. /**
  62. * @var PEAR_Registry
  63. */
  64. var $_registry;
  65. /**
  66. * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  67. */
  68. var $_packagefile;
  69. /**
  70. * @var array
  71. */
  72. var $_parsedname;
  73. /**
  74. * @var array
  75. */
  76. var $_downloadURL;
  77. /**
  78. * @var array
  79. */
  80. var $_downloadDeps = array();
  81. /**
  82. * @var boolean
  83. */
  84. var $_valid = false;
  85. /**
  86. * @var boolean
  87. */
  88. var $_analyzed = false;
  89. /**
  90. * if this or a parent package was invoked with Package-state, this is set to the
  91. * state variable.
  92. *
  93. * This allows temporary reassignment of preferred_state for a parent package and all of
  94. * its dependencies.
  95. * @var string|false
  96. */
  97. var $_explicitState = false;
  98. /**
  99. * If this package is invoked with Package#group, this variable will be true
  100. */
  101. var $_explicitGroup = false;
  102. /**
  103. * Package type local|url|xmlrpc
  104. * @var string
  105. */
  106. var $_type;
  107. /**
  108. * Contents of package.xml, if downloaded from a remote channel
  109. * @var string|false
  110. * @access private
  111. */
  112. var $_rawpackagefile;
  113. /**
  114. * @var boolean
  115. * @access private
  116. */
  117. var $_validated = false;
  118. /**
  119. * @param PEAR_Config
  120. */
  121. function PEAR_Downloader_Package(&$downloader)
  122. {
  123. $this->_downloader = &$downloader;
  124. $this->_config = &$this->_downloader->config;
  125. $this->_registry = &$this->_config->getRegistry();
  126. $this->_valid = $this->_analyzed = false;
  127. }
  128. /**
  129. * Parse the input and determine whether this is a local file, a remote uri, or an
  130. * abstract package name.
  131. *
  132. * This is the heart of the PEAR_Downloader_Package(), and is used in
  133. * {@link PEAR_Downloader::download()}
  134. * @param string
  135. * @return void|PEAR_Error
  136. */
  137. function initialize($param)
  138. {
  139. $origErr = $this->_fromFile($param);
  140. if (!$this->_valid) {
  141. $options = $this->_downloader->getOptions();
  142. if (isset($options['offline'])) {
  143. if (PEAR::isError($origErr)) {
  144. if (!isset($options['soft'])) {
  145. $this->log(0, $origErr->getMessage());
  146. }
  147. }
  148. return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
  149. }
  150. $err = $this->_fromUrl($param);
  151. if (PEAR::isError($err) || !$this->_valid) {
  152. if ($this->_type == 'url') {
  153. if (PEAR::isError($err)) {
  154. if (!isset($options['soft'])) {
  155. $this->_downloader->log(0, $err->getMessage());
  156. }
  157. }
  158. return PEAR::raiseError("Invalid or missing remote package file");
  159. }
  160. $err = $this->_fromString($param);
  161. if (PEAR::isError($err) || !$this->_valid) {
  162. if (isset($this->_type) && $this->_type == 'local' &&
  163. PEAR::isError($origErr)) {
  164. if (is_array($origErr->getUserInfo())) {
  165. foreach ($origErr->getUserInfo() as $err) {
  166. if (is_array($err)) {
  167. $err = $err['message'];
  168. }
  169. if (!isset($options['soft'])) {
  170. $this->_downloader->log(0, $err);
  171. }
  172. }
  173. }
  174. if (!isset($options['soft'])) {
  175. $this->_downloader->log(0, $origErr->getMessage());
  176. }
  177. if (is_array($param)) {
  178. $param = $this->_registry->parsedPackageNameToString($param,
  179. true);
  180. }
  181. return PEAR::raiseError(
  182. "Cannot initialize '$param', invalid or missing package file");
  183. }
  184. if (PEAR::isError($err)) {
  185. if (!isset($options['soft'])) {
  186. $this->_downloader->log(0, $err->getMessage());
  187. }
  188. }
  189. if (is_array($param)) {
  190. $param = $this->_registry->parsedPackageNameToString($param, true);
  191. }
  192. return PEAR::raiseError(
  193. "Cannot initialize '$param', invalid or missing package file");
  194. }
  195. }
  196. }
  197. }
  198. /**
  199. * Retrieve any non-local packages
  200. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
  201. */
  202. function &download()
  203. {
  204. if (isset($this->_packagefile)) {
  205. return $this->_packagefile;
  206. }
  207. if (isset($this->_downloadURL['url'])) {
  208. $this->_isvalid = false;
  209. $info = $this->getParsedPackage();
  210. foreach ($info as $i => $p) {
  211. $info[$i] = strtolower($p);
  212. }
  213. $err = $this->_fromUrl($this->_downloadURL['url'],
  214. $this->_registry->parsedPackageNameToString($this->_parsedname, true));
  215. $newinfo = $this->getParsedPackage();
  216. foreach ($newinfo as $i => $p) {
  217. $newinfo[$i] = strtolower($p);
  218. }
  219. if ($info != $newinfo) {
  220. do {
  221. if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') {
  222. $info['package'] = 'pear.php.net';
  223. if ($info == $newinfo) {
  224. // skip the channel check if a pecl package says it's a PEAR package
  225. break;
  226. }
  227. }
  228. return PEAR::raiseError('CRITICAL ERROR: We are ' .
  229. $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
  230. 'downloaded claims to be ' .
  231. $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
  232. } while (false);
  233. }
  234. if (PEAR::isError($err) || !$this->_valid) {
  235. return $err;
  236. }
  237. }
  238. $this->_type = 'local';
  239. return $this->_packagefile;
  240. }
  241. function &getPackageFile()
  242. {
  243. return $this->_packagefile;
  244. }
  245. function &getDownloader()
  246. {
  247. return $this->_downloader;
  248. }
  249. function getType()
  250. {
  251. return $this->_type;
  252. }
  253. /**
  254. * Like {@link initialize()}, but operates on a dependency
  255. */
  256. function fromDepURL($dep)
  257. {
  258. $this->_downloadURL = $dep;
  259. if (isset($dep['uri'])) {
  260. $options = $this->_downloader->getOptions();
  261. if (!extension_loaded("zlib") || isset($options['nocompress'])) {
  262. $ext = '.tar';
  263. } else {
  264. $ext = '.tgz';
  265. }
  266. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  267. $err = $this->_fromUrl($dep['uri'] . $ext);
  268. PEAR::popErrorHandling();
  269. if (PEAR::isError($err)) {
  270. if (!isset($options['soft'])) {
  271. $this->_downloader->log(0, $err->getMessage());
  272. }
  273. return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
  274. 'cannot download');
  275. }
  276. } else {
  277. $this->_parsedname =
  278. array(
  279. 'package' => $dep['info']->getPackage(),
  280. 'channel' => $dep['info']->getChannel(),
  281. 'version' => $dep['version']
  282. );
  283. if (!isset($dep['nodefault'])) {
  284. $this->_parsedname['group'] = 'default'; // download the default dependency group
  285. $this->_explicitGroup = false;
  286. }
  287. $this->_rawpackagefile = $dep['raw'];
  288. }
  289. }
  290. function detectDependencies($params)
  291. {
  292. $options = $this->_downloader->getOptions();
  293. if (isset($options['downloadonly'])) {
  294. return;
  295. }
  296. if (isset($options['offline'])) {
  297. $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
  298. return;
  299. }
  300. $pname = $this->getParsedPackage();
  301. if (!$pname) {
  302. return;
  303. }
  304. $deps = $this->getDeps();
  305. if (!$deps) {
  306. return;
  307. }
  308. if (isset($deps['required'])) { // package.xml 2.0
  309. return $this->_detect2($deps, $pname, $options, $params);
  310. } else {
  311. return $this->_detect1($deps, $pname, $options, $params);
  312. }
  313. }
  314. function setValidated()
  315. {
  316. $this->_validated = true;
  317. }
  318. function alreadyValidated()
  319. {
  320. return $this->_validated;
  321. }
  322. /**
  323. * Remove packages to be downloaded that are already installed
  324. * @param array of PEAR_Downloader_Package objects
  325. * @static
  326. */
  327. function removeInstalled(&$params)
  328. {
  329. if (!isset($params[0])) {
  330. return;
  331. }
  332. $options = $params[0]->_downloader->getOptions();
  333. if (!isset($options['downloadonly'])) {
  334. foreach ($params as $i => $param) {
  335. // remove self if already installed with this version
  336. // this does not need any pecl magic - we only remove exact matches
  337. if ($param->_registry->packageExists($param->getPackage(), $param->getChannel())) {
  338. if (version_compare($param->_registry->packageInfo($param->getPackage(), 'version',
  339. $param->getChannel()), $param->getVersion(), '==')) {
  340. if (!isset($options['force'])) {
  341. $info = $param->getParsedPackage();
  342. unset($info['version']);
  343. unset($info['state']);
  344. if (!isset($options['soft'])) {
  345. $param->_downloader->log(1, 'Skipping package "' .
  346. $param->getShortName() .
  347. '", already installed as version ' . $param->getVersion());
  348. }
  349. $params[$i] = false;
  350. }
  351. } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
  352. !isset($options['soft'])) {
  353. $info = $param->getParsedPackage();
  354. $param->_downloader->log(1, 'Skipping package "' .
  355. $param->getShortName() .
  356. '", already installed as version ' . $param->getVersion());
  357. $params[$i] = false;
  358. }
  359. }
  360. }
  361. }
  362. PEAR_Downloader_Package::removeDuplicates($params);
  363. }
  364. function _detect2($deps, $pname, $options, $params)
  365. {
  366. $this->_downloadDeps = array();
  367. $groupnotfound = false;
  368. foreach (array('package', 'subpackage') as $packagetype) {
  369. // get required dependency group
  370. if (isset($deps['required'][$packagetype])) {
  371. if (isset($deps['required'][$packagetype][0])) {
  372. foreach ($deps['required'][$packagetype] as $dep) {
  373. if (isset($dep['conflicts'])) {
  374. // skip any package that this package conflicts with
  375. continue;
  376. }
  377. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  378. if (is_array($ret)) {
  379. $this->_downloadDeps[] = $ret;
  380. }
  381. }
  382. } else {
  383. $dep = $deps['required'][$packagetype];
  384. if (!isset($dep['conflicts'])) {
  385. // skip any package that this package conflicts with
  386. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  387. if (is_array($ret)) {
  388. $this->_downloadDeps[] = $ret;
  389. }
  390. }
  391. }
  392. }
  393. // get optional dependency group, if any
  394. if (isset($deps['optional'][$packagetype])) {
  395. $skipnames = array();
  396. if (!isset($deps['optional'][$packagetype][0])) {
  397. $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
  398. }
  399. foreach ($deps['optional'][$packagetype] as $dep) {
  400. $skip = false;
  401. if (!isset($options['alldeps'])) {
  402. $dep['package'] = $dep['name'];
  403. if (!isset($options['soft'])) {
  404. $this->_downloader->log(3, 'Notice: package "' .
  405. $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
  406. true) . '" optional dependency "' .
  407. $this->_registry->parsedPackageNameToString(array('package' =>
  408. $dep['name'], 'channel' => 'pear.php.net'), true) .
  409. '" will not be automatically downloaded');
  410. }
  411. $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
  412. $skip = true;
  413. unset($dep['package']);
  414. }
  415. if (!($ret = $this->_detect2Dep($dep, $pname, 'optional', $params))) {
  416. $dep['package'] = $dep['name'];
  417. if (@$skipnames[count($skipnames) - 1] ==
  418. $this->_registry->parsedPackageNameToString($dep, true)) {
  419. array_pop($skipnames);
  420. }
  421. }
  422. if (!$skip && is_array($ret)) {
  423. $this->_downloadDeps[] = $ret;
  424. }
  425. }
  426. if (count($skipnames)) {
  427. if (!isset($options['soft'])) {
  428. $this->_downloader->log(1, 'Did not download optional dependencies: ' .
  429. implode(', ', $skipnames) .
  430. ', use --alldeps to download automatically');
  431. }
  432. }
  433. }
  434. // get requested dependency group, if any
  435. $groupname = $this->getGroup();
  436. $explicit = $this->_explicitGroup;
  437. if (!$groupname) {
  438. if ($this->canDefault()) {
  439. $groupname = 'default'; // try the default dependency group
  440. } else {
  441. continue;
  442. }
  443. }
  444. if ($groupnotfound) {
  445. continue;
  446. }
  447. if (isset($deps['group'])) {
  448. if (isset($deps['group']['attribs'])) {
  449. if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
  450. $group = $deps['group'];
  451. } elseif ($explicit) {
  452. if (!isset($options['soft'])) {
  453. $this->_downloader->log(0, 'Warning: package "' .
  454. $this->_registry->parsedPackageNameToString($pname, true) .
  455. '" has no dependency ' . 'group named "' . $groupname . '"');
  456. }
  457. $groupnotfound = true;
  458. continue;
  459. }
  460. } else {
  461. $found = false;
  462. foreach ($deps['group'] as $group) {
  463. if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
  464. $found = true;
  465. break;
  466. }
  467. }
  468. if (!$found) {
  469. if ($explicit) {
  470. if (!isset($options['soft'])) {
  471. $this->_downloader->log(0, 'Warning: package "' .
  472. $this->_registry->parsedPackageNameToString($pname, true) .
  473. '" has no dependency ' . 'group named "' . $groupname . '"');
  474. }
  475. }
  476. $groupnotfound = true;
  477. continue;
  478. }
  479. }
  480. }
  481. if (isset($group)) {
  482. if (isset($group[$packagetype])) {
  483. if (isset($group[$packagetype][0])) {
  484. foreach ($group[$packagetype] as $dep) {
  485. $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
  486. $group['attribs']['name'] . '"', $params);
  487. if (is_array($ret)) {
  488. $this->_downloadDeps[] = $ret;
  489. }
  490. }
  491. } else {
  492. $ret = $this->_detect2Dep($group[$packagetype], $pname,
  493. 'dependency group "' .
  494. $group['attribs']['name'] . '"', $params);
  495. if (is_array($ret)) {
  496. $this->_downloadDeps[] = $ret;
  497. }
  498. }
  499. }
  500. }
  501. }
  502. }
  503. function _detect2Dep($dep, $pname, $group, $params)
  504. {
  505. if (isset($dep['conflicts'])) {
  506. return true;
  507. }
  508. $options = $this->_downloader->getOptions();
  509. if (isset($dep['uri'])) {
  510. return array('uri' => $dep['uri'], 'dep' => $dep);;
  511. }
  512. $testdep = $dep;
  513. $testdep['package'] = $dep['name'];
  514. if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
  515. $dep['package'] = $dep['name'];
  516. if (!isset($options['soft'])) {
  517. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
  518. ' dependency "' .
  519. $this->_registry->parsedPackageNameToString($dep, true) .
  520. '", will be installed');
  521. }
  522. return false;
  523. }
  524. $options = $this->_downloader->getOptions();
  525. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  526. if ($this->_explicitState) {
  527. $pname['state'] = $this->_explicitState;
  528. }
  529. $url =
  530. $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  531. if (PEAR::isError($url)) {
  532. PEAR::popErrorHandling();
  533. return $url;
  534. }
  535. $dep['package'] = $dep['name'];
  536. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
  537. !isset($options['alldeps']));
  538. PEAR::popErrorHandling();
  539. if (PEAR::isError($ret)) {
  540. if (!isset($options['soft'])) {
  541. $this->_downloader->log(0, $ret->getMessage());
  542. }
  543. return false;
  544. } else {
  545. // check to see if a dep is already installed and is the same or newer
  546. if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
  547. $oper = 'has';
  548. } else {
  549. $oper = 'gt';
  550. }
  551. // do not try to move this before getDepPackageDownloadURL
  552. // we can't determine whether upgrade is necessary until we know what
  553. // version would be downloaded
  554. if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
  555. $version = $this->_registry->packageInfo($dep['name'], 'version',
  556. $dep['channel']);
  557. $dep['package'] = $dep['name'];
  558. if (!isset($options['soft'])) {
  559. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  560. ' dependency "' .
  561. $this->_registry->parsedPackageNameToString($dep, true) .
  562. '" version ' . $url['version'] . ', already installed as version ' .
  563. $version);
  564. }
  565. return false;
  566. }
  567. }
  568. if (isset($dep['nodefault'])) {
  569. $ret['nodefault'] = true;
  570. }
  571. return $ret;
  572. }
  573. function _detect1($deps, $pname, $options, $params)
  574. {
  575. $this->_downloadDeps = array();
  576. $skipnames = array();
  577. foreach ($deps as $dep) {
  578. $nodownload = false;
  579. if ($dep['type'] == 'pkg') {
  580. $dep['channel'] = 'pear.php.net';
  581. $dep['package'] = $dep['name'];
  582. switch ($dep['rel']) {
  583. case 'not' :
  584. continue 2;
  585. case 'ge' :
  586. case 'eq' :
  587. case 'gt' :
  588. case 'has' :
  589. if (PEAR_Downloader_Package::willDownload($dep, $params)) {
  590. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  591. 'required' :
  592. 'optional';
  593. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  594. . ' dependency "' .
  595. $this->_registry->parsedPackageNameToString($dep, true) .
  596. '", will be installed');
  597. continue 2;
  598. }
  599. }
  600. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  601. if ($this->_explicitState) {
  602. $pname['state'] = $this->_explicitState;
  603. }
  604. $url =
  605. $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  606. $chan = 'pear.php.net';
  607. if (PEAR::isError($url)) {
  608. // check to see if this is a pecl package that has jumped
  609. // from pear.php.net to pecl.php.net channel
  610. if (!class_exists('PEAR_Dependency2')) {
  611. require_once 'PEAR/Dependency2.php';
  612. }
  613. $newdep = PEAR_Dependency2::normalizeDep($dep);
  614. $newdep = $newdep[0];
  615. $newdep['channel'] = 'pecl.php.net';
  616. $chan = 'pecl.php.net';
  617. $url =
  618. $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
  619. if (PEAR::isError($url)) {
  620. PEAR::popErrorHandling();
  621. return $url;
  622. }
  623. }
  624. PEAR::popErrorHandling();
  625. if (!isset($options['alldeps'])) {
  626. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  627. if (!isset($options['soft'])) {
  628. $this->_downloader->log(3, 'Notice: package "' .
  629. $this->getShortName() .
  630. '" optional dependency "' .
  631. $this->_registry->parsedPackageNameToString(
  632. array('channel' => $chan, 'package' =>
  633. $dep['name']), true) .
  634. '" will not be automatically downloaded');
  635. }
  636. $skipnames[] = $this->_registry->parsedPackageNameToString(
  637. array('channel' => $chan, 'package' =>
  638. $dep['name']), true);
  639. $nodownload = true;
  640. }
  641. }
  642. if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
  643. if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  644. if (!isset($options['soft'])) {
  645. $this->_downloader->log(3, 'Notice: package "' .
  646. $this->getShortName() .
  647. '" required dependency "' .
  648. $this->_registry->parsedPackageNameToString(
  649. array('channel' => $chan, 'package' =>
  650. $dep['name']), true) .
  651. '" will not be automatically downloaded');
  652. }
  653. $skipnames[] = $this->_registry->parsedPackageNameToString(
  654. array('channel' => $chan, 'package' =>
  655. $dep['name']), true);
  656. $nodownload = true;
  657. }
  658. }
  659. // check to see if a dep is already installed
  660. // do not try to move this before getDepPackageDownloadURL
  661. // we can't determine whether upgrade is necessary until we know what
  662. // version would be downloaded
  663. if (!isset($options['force']) && $this->isInstalled(
  664. $url, $dep['rel'])) {
  665. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  666. 'required' :
  667. 'optional';
  668. $dep['package'] = $dep['name'];
  669. if (isset($newdep)) {
  670. $version = $this->_registry->packageInfo($newdep['name'], 'version',
  671. $newdep['channel']);
  672. } else {
  673. $version = $this->_registry->packageInfo($dep['name'], 'version');
  674. }
  675. $dep['version'] = $url['version'];
  676. if (!isset($options['soft'])) {
  677. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  678. ' dependency "' .
  679. $this->_registry->parsedPackageNameToString($dep, true) .
  680. '", already installed as version ' . $version);
  681. }
  682. if (@$skipnames[count($skipnames) - 1] ==
  683. $this->_registry->parsedPackageNameToString($dep, true)) {
  684. array_pop($skipnames);
  685. }
  686. continue;
  687. }
  688. if ($nodownload) {
  689. continue;
  690. }
  691. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  692. if (isset($newdep)) {
  693. $dep = $newdep;
  694. }
  695. $dep['package'] = $dep['name'];
  696. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
  697. isset($dep['optional']) && $dep['optional'] == 'yes' &&
  698. !isset($options['alldeps']));
  699. PEAR::popErrorHandling();
  700. if (PEAR::isError($ret)) {
  701. if (!isset($options['soft'])) {
  702. $this->_downloader->log(0, $ret->getMessage());
  703. }
  704. continue;
  705. }
  706. $this->_downloadDeps[] = $ret;
  707. }
  708. }
  709. if (count($skipnames)) {
  710. if (!isset($options['soft'])) {
  711. $this->_downloader->log(1, 'Did not download dependencies: ' .
  712. implode(', ', $skipnames) .
  713. ', use --alldeps or --onlyreqdeps to download automatically');
  714. }
  715. }
  716. }
  717. function setDownloadURL($pkg)
  718. {
  719. $this->_downloadURL = $pkg;
  720. }
  721. /**
  722. * Set the package.xml object for this downloaded package
  723. *
  724. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
  725. */
  726. function setPackageFile(&$pkg)
  727. {
  728. $this->_packagefile = &$pkg;
  729. }
  730. function getShortName()
  731. {
  732. return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
  733. 'package' => $this->getPackage()), true);
  734. }
  735. function getParsedPackage()
  736. {
  737. if (isset($this->_packagefile) || isset($this->_parsedname)) {
  738. return array('channel' => $this->getChannel(),
  739. 'package' => $this->getPackage(),
  740. 'version' => $this->getVersion());
  741. }
  742. return false;
  743. }
  744. function getDownloadURL()
  745. {
  746. return $this->_downloadURL;
  747. }
  748. function canDefault()
  749. {
  750. if (isset($this->_downloadURL)) {
  751. if (isset($this->_downloadURL['nodefault'])) {
  752. return false;
  753. }
  754. }
  755. return true;
  756. }
  757. function getPackage()
  758. {
  759. if (isset($this->_packagefile)) {
  760. return $this->_packagefile->getPackage();
  761. } elseif (isset($this->_downloadURL['info'])) {
  762. return $this->_downloadURL['info']->getPackage();
  763. } else {
  764. return false;
  765. }
  766. }
  767. /**
  768. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  769. */
  770. function isSubpackage(&$pf)
  771. {
  772. if (isset($this->_packagefile)) {
  773. return $this->_packagefile->isSubpackage($pf);
  774. } elseif (isset($this->_downloadURL['info'])) {
  775. return $this->_downloadURL['info']->isSubpackage($pf);
  776. } else {
  777. return false;
  778. }
  779. }
  780. function getPackageType()
  781. {
  782. if (isset($this->_packagefile)) {
  783. return $this->_packagefile->getPackageType();
  784. } elseif (isset($this->_downloadURL['info'])) {
  785. return $this->_downloadURL['info']->getPackageType();
  786. } else {
  787. return false;
  788. }
  789. }
  790. function isBundle()
  791. {
  792. if (isset($this->_packagefile)) {
  793. return $this->_packagefile->getPackageType() == 'bundle';
  794. } else {
  795. return false;
  796. }
  797. }
  798. function getPackageXmlVersion()
  799. {
  800. if (isset($this->_packagefile)) {
  801. return $this->_packagefile->getPackagexmlVersion();
  802. } elseif (isset($this->_downloadURL['info'])) {
  803. return $this->_downloadURL['info']->getPackagexmlVersion();
  804. } else {
  805. return '1.0';
  806. }
  807. }
  808. function getChannel()
  809. {
  810. if (isset($this->_packagefile)) {
  811. return $this->_packagefile->getChannel();
  812. } elseif (isset($this->_downloadURL['info'])) {
  813. return $this->_downloadURL['info']->getChannel();
  814. } else {
  815. return false;
  816. }
  817. }
  818. function getURI()
  819. {
  820. if (isset($this->_packagefile)) {
  821. return $this->_packagefile->getURI();
  822. } elseif (isset($this->_downloadURL['info'])) {
  823. return $this->_downloadURL['info']->getURI();
  824. } else {
  825. return false;
  826. }
  827. }
  828. function getVersion()
  829. {
  830. if (isset($this->_packagefile)) {
  831. return $this->_packagefile->getVersion();
  832. } elseif (isset($this->_downloadURL['version'])) {
  833. return $this->_downloadURL['version'];
  834. } else {
  835. return false;
  836. }
  837. }
  838. function isCompatible($pf)
  839. {
  840. if (isset($this->_packagefile)) {
  841. return $this->_packagefile->isCompatible($pf);
  842. } elseif (isset($this->_downloadURL['info'])) {
  843. return $this->_downloadURL['info']->isCompatible($pf);
  844. } else {
  845. return true;
  846. }
  847. }
  848. function setGroup($group)
  849. {
  850. $this->_parsedname['group'] = $group;
  851. }
  852. function getGroup()
  853. {
  854. if (isset($this->_parsedname['group'])) {
  855. return $this->_parsedname['group'];
  856. } else {
  857. return '';
  858. }
  859. }
  860. function isExtension($name)
  861. {
  862. if (isset($this->_packagefile)) {
  863. return $this->_packagefile->isExtension($name);
  864. } elseif (isset($this->_downloadURL['info'])) {
  865. return $this->_downloadURL['info']->getProvidesExtension() == $name;
  866. } else {
  867. return false;
  868. }
  869. }
  870. function getDeps()
  871. {
  872. if (isset($this->_packagefile)) {
  873. if ($this->_packagefile->getPackagexmlVersion() == '2.0') {
  874. return $this->_packagefile->getDeps(true);
  875. } else {
  876. return $this->_packagefile->getDeps();
  877. }
  878. } elseif (isset($this->_downloadURL['info'])) {
  879. if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
  880. return $this->_downloadURL['info']->getDeps(true);
  881. } else {
  882. return $this->_downloadURL['info']->getDeps();
  883. }
  884. } else {
  885. return array();
  886. }
  887. }
  888. /**
  889. * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
  890. * returned from getDepDownloadURL()
  891. */
  892. function isEqual($param)
  893. {
  894. if (is_object($param)) {
  895. $channel = $param->getChannel();
  896. $package = $param->getPackage();
  897. if ($param->getURI()) {
  898. $param = array(
  899. 'channel' => $param->getChannel(),
  900. 'package' => $param->getPackage(),
  901. 'version' => $param->getVersion(),
  902. 'uri' => $param->getURI(),
  903. );
  904. } else {
  905. $param = array(
  906. 'channel' => $param->getChannel(),
  907. 'package' => $param->getPackage(),
  908. 'version' => $param->getVersion(),
  909. );
  910. }
  911. } else {
  912. if (isset($param['uri'])) {
  913. $param['channel'] = '__uri';
  914. $param['package'] = $param['dep']['name'];
  915. }
  916. $package = isset($param['package']) ? $param['package'] :
  917. $param['info']->getPackage();
  918. $channel = isset($param['channel']) ? $param['channel'] :
  919. $param['info']->getChannel();
  920. if (isset($param['rel'])) {
  921. if (!class_exists('PEAR_Dependency2')) {
  922. require_once 'PEAR/Dependency2.php';
  923. }
  924. $newdep = PEAR_Dependency2::normalizeDep($param);
  925. $newdep = $newdep[0];
  926. } elseif (isset($param['min'])) {
  927. $newdep = $param;
  928. }
  929. }
  930. if (isset($newdep)) {
  931. if (!isset($newdep['min'])) {
  932. $newdep['min'] = '0';
  933. }
  934. if (!isset($newdep['max'])) {
  935. $newdep['max'] = '100000000000000000000';
  936. }
  937. // use magic to support pecl packages suddenly jumping to the pecl channel
  938. // we need to support both dependency possibilities
  939. if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
  940. if ($package == $this->getPackage()) {
  941. $channel = 'pecl.php.net';
  942. }
  943. }
  944. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  945. if ($package == $this->getPackage()) {
  946. $channel = 'pear.php.net';
  947. }
  948. }
  949. return (strtolower($package) == strtolower($this->getPackage()) &&
  950. $channel == $this->getChannel() &&
  951. version_compare($newdep['min'], $this->getVersion(), '<=') &&
  952. version_compare($newdep['max'], $this->getVersion(), '>='));
  953. }
  954. // use magic to support pecl packages suddenly jumping to the pecl channel
  955. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  956. if (strtolower($package) == strtolower($this->getPackage())) {
  957. $channel = 'pear.php.net';
  958. }
  959. }
  960. if (isset($param['version'])) {
  961. return (strtolower($package) == strtolower($this->getPackage()) &&
  962. $channel == $this->getChannel() &&
  963. $param['version'] == $this->getVersion());
  964. } else {
  965. return strtolower($package) == strtolower($this->getPackage()) &&
  966. $channel == $this->getChannel();
  967. }
  968. }
  969. function isInstalled($dep, $oper = '==')
  970. {
  971. if (!$dep) {
  972. return false;
  973. }
  974. if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
  975. return false;
  976. }
  977. if (is_object($dep)) {
  978. $package = $dep->getPackage();
  979. $channel = $dep->getChannel();
  980. if ($dep->getURI()) {
  981. $dep = array(
  982. 'uri' => $dep->getURI(),
  983. 'version' => $dep->getVersion(),
  984. );
  985. } else {
  986. $dep = array(
  987. 'version' => $dep->getVersion(),
  988. );
  989. }
  990. } else {
  991. if (isset($dep['uri'])) {
  992. $channel = '__uri';
  993. $package = $dep['dep']['name'];
  994. } else {
  995. $channel = $dep['info']->getChannel();
  996. $package = $dep['info']->getPackage();
  997. }
  998. }
  999. $options = $this->_downloader->getOptions();
  1000. $test = $this->_registry->packageExists($package, $channel);
  1001. if (!$test && $channel == 'pecl.php.net') {
  1002. // do magic to allow upgrading from old pecl packages to new ones
  1003. $test = $this->_registry->packageExists($package, 'pear.php.net');
  1004. $channel = 'pear.php.net';
  1005. }
  1006. if ($test) {
  1007. if (isset($dep['uri'])) {
  1008. if ($this->_registry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
  1009. return true;
  1010. }
  1011. }
  1012. if (isset($options['upgrade'])) {
  1013. if ($oper == 'has') {
  1014. if (version_compare($this->_registry->packageInfo(
  1015. $package, 'version', $channel),
  1016. $dep['version'], '>=')) {
  1017. return true;
  1018. } else {
  1019. return false;
  1020. }
  1021. } else {
  1022. if (version_compare($this->_registry->packageInfo(
  1023. $package, 'version', $channel),
  1024. $dep['version'], '>=')) {
  1025. return true;
  1026. }
  1027. return false;
  1028. }
  1029. }
  1030. return true;
  1031. }
  1032. return false;
  1033. }
  1034. /**
  1035. * @param array
  1036. * @static
  1037. */
  1038. function removeDuplicates(&$params)
  1039. {
  1040. $pnames = array();
  1041. foreach ($params as $i => $param) {
  1042. if (!$param) {
  1043. continue;
  1044. }
  1045. if ($param->getPackage()) {
  1046. $pnames[$i] = $param->getChannel() . '/' .
  1047. $param->getPackage() . '-' . $param->getVersion() . '#' . $param->getGroup();
  1048. }
  1049. }
  1050. $pnames = array_unique($pnames);
  1051. $unset = array_diff(array_keys($params), array_keys($pnames));
  1052. $testp = array_flip($pnames);
  1053. foreach ($params as $i => $param) {
  1054. if (!$param) {
  1055. $unset[] = $i;
  1056. continue;
  1057. }
  1058. if (!is_a($param, 'PEAR_Downloader_Package')) {
  1059. $unset[] = $i;
  1060. continue;
  1061. }
  1062. if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
  1063. $param->getVersion() . '#' . $param->getGroup()])) {
  1064. $unset[] = $i;
  1065. }
  1066. }
  1067. foreach ($unset as $i) {
  1068. unset($params[$i]);
  1069. }
  1070. $ret = array();
  1071. foreach ($params as $i => $param) {
  1072. $ret[] = &$params[$i];
  1073. }
  1074. $params = array();
  1075. foreach ($ret as $i => $param) {
  1076. $params[] = &$ret[$i];
  1077. }
  1078. }
  1079. function explicitState()
  1080. {
  1081. return $this->_explicitState;
  1082. }
  1083. function setExplicitState($s)
  1084. {
  1085. $this->_explicitState = $s;
  1086. }
  1087. /**
  1088. * @static
  1089. */
  1090. function mergeDependencies(&$params)
  1091. {
  1092. $newparams = array();
  1093. $bundles = array();
  1094. foreach ($params as $i => $param) {
  1095. if (!$param->isBundle()) {
  1096. continue;
  1097. }
  1098. $bundles[] = $i;
  1099. $pf = &$param->getPackageFile();
  1100. $newdeps = array();
  1101. $contents = $pf->getBundledPackages();
  1102. if (!is_array($contents)) {
  1103. $contents = array($contents);
  1104. }
  1105. foreach ($contents as $file) {
  1106. $filecontents = $pf->getFileContents($file);
  1107. $dl = &$param->getDownloader();
  1108. $options = $dl->getOptions();
  1109. $fp = @fopen($dl->getDownloadDir() . DIRECTORY_SEPARATOR . $file, 'wb');
  1110. if (!$fp) {
  1111. continue;
  1112. }
  1113. fwrite($fp, $filecontents, strlen($filecontents));
  1114. fclose($fp);
  1115. if ($s = $params[$i]->explicitState()) {
  1116. $obj->setExplicitState($s);
  1117. }
  1118. $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
  1119. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1120. $e = $obj->_fromFile($dl->getDownloadDir() . DIRECTORY_SEPARATOR . $file);
  1121. PEAR::popErrorHandling();
  1122. if (PEAR::isError($e)) {
  1123. if (!isset($options['soft'])) {
  1124. $dl->log(0, $e->getMessage());
  1125. }
  1126. continue;
  1127. }
  1128. $j = &$obj;
  1129. if (!PEAR_Downloader_Package::willDownload($j,
  1130. array_merge($params, $newparams)) && !$param->isInstalled($j)) {
  1131. $newparams[] = &$j;
  1132. }
  1133. }
  1134. }
  1135. foreach ($bundles as $i) {
  1136. unset($params[$i]); // remove bundles - only their contents matter for installation
  1137. }
  1138. PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
  1139. if (count($newparams)) { // add in bundled packages for install
  1140. foreach ($newparams as $i => $unused) {
  1141. $params[] = &$newparams[$i];
  1142. }
  1143. $newparams = array();
  1144. }
  1145. foreach ($params as $i => $param) {
  1146. $newdeps = array();
  1147. foreach ($param->_downloadDeps as $dep) {
  1148. if (!PEAR_Downloader_Package::willDownload($dep,
  1149. array_merge($params, $newparams)) && !$param->isInstalled($dep)) {
  1150. $newdeps[] = $dep;
  1151. } else {
  1152. // detect versioning conflicts here
  1153. }
  1154. }
  1155. // convert the dependencies into PEAR_Downloader_Package objects for the next time
  1156. // around
  1157. $params[$i]->_downloadDeps = array();
  1158. foreach ($newdeps as $dep) {
  1159. $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
  1160. if ($s = $params[$i]->explicitState()) {
  1161. $obj->setExplicitState($s);
  1162. }
  1163. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1164. $e = $obj->fromDepURL($dep);
  1165. PEAR::popErrorHandling();
  1166. if (PEAR::isError($e)) {
  1167. if (!isset($options['soft'])) {
  1168. $obj->_downloader->log(0, $e->getMessage());
  1169. }
  1170. continue;
  1171. }
  1172. $e = $obj->detectDependencies($params);
  1173. if (PEAR::isError($e)) {
  1174. if (!isset($options['soft'])) {
  1175. $obj->_downloader->log(0, $e->getMessage());
  1176. }
  1177. }
  1178. $j = &$obj;
  1179. $newparams[] = &$j;
  1180. }
  1181. }
  1182. if (count($newparams)) {
  1183. foreach ($newparams as $i => $unused) {
  1184. $params[] = &$newparams[$i];
  1185. }
  1186. return true;
  1187. } else {
  1188. return false;
  1189. }
  1190. }
  1191. /**
  1192. * @static
  1193. */
  1194. function willDownload($param, $params)
  1195. {
  1196. if (!is_array($params)) {
  1197. return false;
  1198. }
  1199. foreach ($params as $obj) {
  1200. if ($obj->isEqual($param)) {
  1201. return true;
  1202. }
  1203. }
  1204. return false;
  1205. }
  1206. /**
  1207. * For simpler unit-testing
  1208. * @param PEAR_Config
  1209. * @param int
  1210. * @param string
  1211. */
  1212. function &getPackagefileObject(&$c, $d, $t = false)
  1213. {
  1214. $a = &new PEAR_PackageFile($c, $d, $t);
  1215. return $a;
  1216. }
  1217. function _fromFile($param)
  1218. {
  1219. if (@is_file($param)) {
  1220. $this->_type = 'local';
  1221. $options = $this->_downloader->getOptions();
  1222. if (isset($options['downloadonly'])) {
  1223. $pkg = &$this->getPackagefileObject($this->_config,
  1224. $this->_downloader->_debug);
  1225. } else {
  1226. $pkg = &$this->getPackagefileObject($this->_config,
  1227. $this->_downloader->_debug, $this->_downloader->getDownloadDir());
  1228. }
  1229. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1230. $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
  1231. PEAR::popErrorHandling();
  1232. if (PEAR::isError($pf)) {
  1233. $this->_valid = false;
  1234. return $pf;
  1235. }
  1236. $this->_packagefile = &$pf;
  1237. $this->setGroup('default'); // install the default dependency group
  1238. return $this->_valid = true;
  1239. }
  1240. return $this->_valid = false;
  1241. }
  1242. function _fromUrl($param, $saveparam = '')
  1243. {
  1244. if (!is_array($param) &&
  1245. (preg_match('#^(http|ftp)://#', $param))) {
  1246. $options = $this->_downloader->getOptions();
  1247. $this->_type = 'url';
  1248. $callback = $this->_downloader->ui ?
  1249. array(&$this->_downloader, '_downloadCallback') : null;
  1250. $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
  1251. $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
  1252. $this->_downloader->getDownloadDir(), $callback);
  1253. $this->_downloader->popErrorHandling();
  1254. if (PEAR::isError($file)) {
  1255. if (!empty($saveparam)) {
  1256. $saveparam = ", cannot download \"$saveparam\"";
  1257. }
  1258. $err = PEAR::raiseError('Could not download from "' . $param .
  1259. '"' . $saveparam);
  1260. return $err;
  1261. }
  1262. if ($this->_rawpackagefile) {
  1263. require_once 'Archive/Tar.php';
  1264. $tar = &new Archive_Tar($file);
  1265. $packagexml = $tar->extractInString('package2.xml');
  1266. if (!$packagexml) {
  1267. $packagexml = $tar->extractInString('package.xml');
  1268. }
  1269. if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
  1270. str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
  1271. if ($this->getChannel() == 'pear.php.net') {
  1272. // be more lax for the existing PEAR packages that have not-ok
  1273. // characters in their package.xml
  1274. $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
  1275. $this->getPackage() . '" package has invalid characters in its ' .
  1276. 'package.xml. The next version of PEAR may not be able to install ' .
  1277. 'this package for security reasons. Please open a bug report at ' .
  1278. 'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
  1279. } else {
  1280. return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
  1281. 'not match value returned from xml-rpc');
  1282. }
  1283. }
  1284. }
  1285. // whew, download worked!
  1286. if (isset($options['downloadonly'])) {
  1287. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
  1288. } else {
  1289. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug,
  1290. $this->_downloader->getDownloadDir());
  1291. }
  1292. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1293. $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
  1294. PEAR::popErrorHandling();
  1295. if (PEAR::isError($pf)) {
  1296. if (is_array($pf->getUserInfo())) {
  1297. foreach ($pf->getUserInfo() as $err) {
  1298. if (is_array($err)) {
  1299. $err = $err['message'];
  1300. }
  1301. if (!isset($options['soft'])) {
  1302. $this->_downloader->log(0, "Validation Error: $err");
  1303. }
  1304. }
  1305. }
  1306. if (!isset($options['soft'])) {
  1307. $this->_downloader->log(0, $pf->getMessage());
  1308. }
  1309. $err = PEAR::raiseError('Download of "' . ($saveparam ? $saveparam :
  1310. $param) . '" succeeded, but it is not a valid package archive');
  1311. $this->_valid = false;
  1312. return $err;
  1313. }
  1314. $this->_packagefile = &$pf;
  1315. $this->setGroup('default'); // install the default dependency group
  1316. return $this->_valid = true;
  1317. }
  1318. return $this->_valid = false;
  1319. }
  1320. /**
  1321. *
  1322. * @param string|array pass in an array of format
  1323. * array(
  1324. * 'package' => 'pname',
  1325. * ['channel' => 'channame',]
  1326. * ['version' => 'version',]
  1327. * ['state' => 'state',])
  1328. * or a string of format [channame/]pname[-version|-state]
  1329. */
  1330. function _fromString($param)
  1331. {
  1332. $options = $this->_downloader->getOptions();
  1333. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1334. $pname = $this->_registry->parsePackageName($param,
  1335. $this->_config->get('default_channel'));
  1336. PEAR::popErrorHandling();
  1337. if (PEAR::isError($pname)) {
  1338. if ($pname->getCode() == 'invalid') {
  1339. $this->_valid = false;
  1340. return false;
  1341. }
  1342. if ($pname->getCode() == 'channel') {
  1343. $parsed = $pname->getUserInfo();
  1344. if ($this->_downloader->discover($parsed['channel'])) {
  1345. if ($this->_config->get('auto_discover')) {
  1346. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1347. $pname = $this->_registry->parsePackageName($param,
  1348. $this->_config->get('default_channel'));
  1349. PEAR::popErrorHandling();
  1350. } else {
  1351. if (!isset($options['soft'])) {
  1352. $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
  1353. '" is not initialized, use ' .
  1354. '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
  1355. 'or pear config-set auto_discover 1');
  1356. }
  1357. }
  1358. }
  1359. if (PEAR::isError($pname)) {
  1360. if (!isset($options['soft'])) {
  1361. $this->_downloader->log(0, $pname->getMessage());
  1362. }
  1363. if (is_array($param)) {
  1364. $param = $this->_registry->parsedPackageNameToString($param);
  1365. }
  1366. $err = PEAR::raiseError('invalid package name/package file "' .
  1367. $param . '"');
  1368. $this->_valid = false;
  1369. return $err;
  1370. }
  1371. } else {
  1372. if (!isset($options['soft'])) {
  1373. $this->_downloader->log(0, $pname->getMessage());
  1374. }
  1375. $err = PEAR::raiseError('invalid package name/package file "' .
  1376. $param . '"');
  1377. $this->_valid = false;
  1378. return $err;
  1379. }
  1380. }
  1381. if (!isset($this->_type)) {
  1382. $this->_type = 'xmlrpc';
  1383. }
  1384. $this->_parsedname = $pname;
  1385. if (isset($pname['state'])) {
  1386. $this->_explicitState = $pname['state'];
  1387. } else {
  1388. $this->_explicitState = false;
  1389. }
  1390. if (isset($pname['group'])) {
  1391. $this->_explicitGroup = true;
  1392. } else {
  1393. $this->_explicitGroup = false;
  1394. }
  1395. $info = $this->_downloader->_getPackageDownloadUrl($pname);
  1396. if (PEAR::isError($info)) {
  1397. return $info;
  1398. }
  1399. $this->_rawpackagefile = $info['raw'];
  1400. $ret = $this->_analyzeDownloadURL($info, $param, $pname);
  1401. if (PEAR::isError($ret)) {
  1402. return $ret;
  1403. }
  1404. if ($ret) {
  1405. $this->_downloadURL = $ret;
  1406. return $this->_valid = (bool) $ret;
  1407. }
  1408. }
  1409. /**
  1410. * @param array output of package.getDownloadURL
  1411. * @param string|array|object information for detecting packages to be downloaded, and
  1412. * for errors
  1413. * @param array name information of the package
  1414. * @param array|null packages to be downloaded
  1415. * @param bool is this an optional dependency?
  1416. * @access private
  1417. */
  1418. function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false)
  1419. {
  1420. if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
  1421. return false;
  1422. }
  1423. if (!$info) {
  1424. if (!is_string($param)) {
  1425. $saveparam = ", cannot download \"$param\"";
  1426. } else {
  1427. $saveparam = '';
  1428. }
  1429. // no releases exist
  1430. return PEAR::raiseError('No releases for package "' .
  1431. $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
  1432. }
  1433. if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
  1434. $err = false;
  1435. if ($pname['channel'] == 'pecl.php.net') {
  1436. if ($info['info']->getChannel() != 'pear.php.net') {
  1437. $err = true;
  1438. }
  1439. } elseif ($info['info']->getChannel() == 'pecl.php.net') {
  1440. if ($pname['channel'] != 'pear.php.net') {
  1441. $err = true;
  1442. }
  1443. } else {
  1444. $err = true;
  1445. }
  1446. if ($err) {
  1447. return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
  1448. '" retrieved another channel\'s name for download! ("' .
  1449. $info['info']->getChannel() . '")');
  1450. }
  1451. }
  1452. if (!isset($info['url'])) {
  1453. $instead = ', will instead download version ' . $info['version'] .
  1454. ', stability "' . $info['info']->getState() . '"';
  1455. // releases exist, but we failed to get any
  1456. if (isset($this->_downloader->_options['force'])) {
  1457. if (isset($pname['version'])) {
  1458. $vs = ', version "' . $pname['version'] . '"';
  1459. } elseif (isset($pname['state'])) {
  1460. $vs = ', stability "' . $pname['state'] . '"';
  1461. } elseif ($param == 'dependency') {
  1462. if (!class_exists('PEAR_Common')) {
  1463. require_once 'PEAR/Common.php';
  1464. }
  1465. if (!in_array($info['info']->getState(),
  1466. PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
  1467. if ($optional) {
  1468. // don't spit out confusing error message
  1469. return $this->_downloader->_getPackageDownloadUrl(
  1470. array('package' => $pname['package'],
  1471. 'channel' => $pname['channel'],
  1472. 'version' => $info['version']));
  1473. }
  1474. $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
  1475. '"';
  1476. } else {
  1477. if (!class_exists('PEAR_Dependency2')) {
  1478. require_once 'PEAR/Dependency2.php';
  1479. }
  1480. if ($optional) {
  1481. // don't spit out confusing error message
  1482. return $this->_downloader->_getPackageDownloadUrl(
  1483. array('package' => $pname['package'],
  1484. 'channel' => $pname['channel'],
  1485. 'version' => $info['version']));
  1486. }
  1487. $vs = PEAR_Dependency2::_getExtraString($pname);
  1488. $instead = '';
  1489. }
  1490. } else {
  1491. $vs = ' within preferred state "' . $this->_config->get(
  1492. 'preferred_state') . '"';
  1493. }
  1494. if (!isset($options['soft'])) {
  1495. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  1496. '/' . $pname['package'] . $vs . $instead);
  1497. }
  1498. // download the latest release
  1499. return $this->_downloader->_getPackageDownloadUrl(
  1500. array('package' => $pname['package'],
  1501. 'channel' => $pname['channel'],
  1502. 'version' => $info['version']));
  1503. } else {
  1504. // construct helpful error message
  1505. if (isset($pname['version'])) {
  1506. $vs = ', version "' . $pname['version'] . '"';
  1507. } elseif (isset($pname['state'])) {
  1508. $vs = ', stability "' . $pname['state'] . '"';
  1509. } elseif ($param == 'dependency') {
  1510. if (!class_exists('PEAR_Common')) {
  1511. require_once 'PEAR/Common.php';
  1512. }
  1513. if (!in_array($info['info']->getState(),
  1514. PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
  1515. if ($optional) {
  1516. // don't spit out confusing error message, and don't die on
  1517. // optional dep failure!
  1518. return $this->_downloader->_getPackageDownloadUrl(
  1519. array('package' => $pname['package'],
  1520. 'channel' => $pname['channel'],
  1521. 'version' => $info['version']));
  1522. }
  1523. $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
  1524. '"';
  1525. } else {
  1526. if (!class_exists('PEAR_Dependency2')) {
  1527. require_once 'PEAR/Dependency2.php';
  1528. }
  1529. if ($optional) {
  1530. // don't spit out confusing error message, and don't die on
  1531. // optional dep failure!
  1532. return $this->_downloader->_getPackageDownloadUrl(
  1533. array('package' => $pname['package'],
  1534. 'channel' => $pname['channel'],
  1535. 'version' => $info['version']));
  1536. }
  1537. $vs = PEAR_Dependency2::_getExtraString($pname);
  1538. }
  1539. } else {
  1540. $vs = ' within preferred state "' . $this->_downloader->config->get(
  1541. 'preferred_state') . '"';
  1542. }
  1543. $err = PEAR::raiseError(
  1544. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  1545. array('channel' => $pname['channel'], 'package' => $pname['package']),
  1546. true)
  1547. . $vs .
  1548. ', latest release is version ' . $info['version'] .
  1549. ', stability "' . $info['info']->getState() . '", use "' .
  1550. $this->_registry->parsedPackageNameToString(
  1551. array('channel' => $pname['channel'], 'package' => $pname['package'],
  1552. 'version' => $info['version'])) . '" to install');
  1553. return $err;
  1554. }
  1555. }
  1556. return $info;
  1557. }
  1558. }
  1559. ?>