PageRenderTime 40ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/script/lib/PEAR/Registry.php

https://bitbucket.org/ywarnier/chamilo-dev
PHP | 2726 lines | 1970 code | 309 blank | 447 comment | 414 complexity | 99d6a7cdf09af2e15b60209fd2e68288 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT
  1. <?php
  2. /**
  3. * PEAR_Registry
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * @category pear
  8. * @package PEAR
  9. * @author Stig Bakken <ssb@php.net>
  10. * @author Tomas V. V. Cox <cox@idecnet.com>
  11. * @author Greg Beaver <cellog@php.net>
  12. * @copyright 1997-2009 The Authors
  13. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  14. * @version CVS: $Id: Registry.php 287555 2009-08-21 21:27:27Z dufuz $
  15. * @link http://pear.php.net/package/PEAR
  16. * @since File available since Release 0.1
  17. */
  18. /**
  19. * for PEAR_Error
  20. */
  21. require_once 'PEAR.php';
  22. require_once 'PEAR/DependencyDB.php';
  23. define('PEAR_REGISTRY_ERROR_LOCK', - 2);
  24. define('PEAR_REGISTRY_ERROR_FORMAT', - 3);
  25. define('PEAR_REGISTRY_ERROR_FILE', - 4);
  26. define('PEAR_REGISTRY_ERROR_CONFLICT', - 5);
  27. define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', - 6);
  28. /**
  29. * Administration class used to maintain the installed package database.
  30. * @category pear
  31. * @package PEAR
  32. * @author Stig Bakken <ssb@php.net>
  33. * @author Tomas V. V. Cox <cox@idecnet.com>
  34. * @author Greg Beaver <cellog@php.net>
  35. * @copyright 1997-2009 The Authors
  36. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  37. * @version Release: 1.9.1
  38. * @link http://pear.php.net/package/PEAR
  39. * @since Class available since Release 1.4.0a1
  40. */
  41. class PEAR_Registry extends PEAR
  42. {
  43. /**
  44. * File containing all channel information.
  45. * @var string
  46. */
  47. var $channels = '';
  48. /** Directory where registry files are stored.
  49. * @var string
  50. */
  51. var $statedir = '';
  52. /** File where the file map is stored
  53. * @var string
  54. */
  55. var $filemap = '';
  56. /** Directory where registry files for channels are stored.
  57. * @var string
  58. */
  59. var $channelsdir = '';
  60. /** Name of file used for locking the registry
  61. * @var string
  62. */
  63. var $lockfile = '';
  64. /** File descriptor used during locking
  65. * @var resource
  66. */
  67. var $lock_fp = null;
  68. /** Mode used during locking
  69. * @var int
  70. */
  71. var $lock_mode = 0; // XXX UNUSED
  72. /** Cache of package information. Structure:
  73. * array(
  74. * 'package' => array('id' => ... ),
  75. * ... )
  76. * @var array
  77. */
  78. var $pkginfo_cache = array();
  79. /** Cache of file map. Structure:
  80. * array( '/path/to/file' => 'package', ... )
  81. * @var array
  82. */
  83. var $filemap_cache = array();
  84. /**
  85. * @var false|PEAR_ChannelFile
  86. */
  87. var $_pearChannel;
  88. /**
  89. * @var false|PEAR_ChannelFile
  90. */
  91. var $_peclChannel;
  92. /**
  93. * @var false|PEAR_ChannelFile
  94. */
  95. var $_docChannel;
  96. /**
  97. * @var PEAR_DependencyDB
  98. */
  99. var $_dependencyDB;
  100. /**
  101. * @var PEAR_Config
  102. */
  103. var $_config;
  104. /**
  105. * PEAR_Registry constructor.
  106. *
  107. * @param string (optional) PEAR install directory (for .php files)
  108. * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if
  109. * default values are not desired. Only used the very first time a PEAR
  110. * repository is initialized
  111. * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if
  112. * default values are not desired. Only used the very first time a PEAR
  113. * repository is initialized
  114. *
  115. * @access public
  116. */
  117. function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, $pecl_channel = false)
  118. {
  119. parent :: PEAR();
  120. $this->setInstallDir($pear_install_dir);
  121. $this->_pearChannel = $pear_channel;
  122. $this->_peclChannel = $pecl_channel;
  123. $this->_config = false;
  124. }
  125. function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR)
  126. {
  127. $ds = DIRECTORY_SEPARATOR;
  128. $this->install_dir = $pear_install_dir;
  129. $this->channelsdir = $pear_install_dir . $ds . '.channels';
  130. $this->statedir = $pear_install_dir . $ds . '.registry';
  131. $this->filemap = $pear_install_dir . $ds . '.filemap';
  132. $this->lockfile = $pear_install_dir . $ds . '.lock';
  133. }
  134. function hasWriteAccess()
  135. {
  136. if (! file_exists($this->install_dir))
  137. {
  138. $dir = $this->install_dir;
  139. while ($dir && $dir != '.')
  140. {
  141. $olddir = $dir;
  142. $dir = dirname($dir);
  143. if ($dir != '.' && file_exists($dir))
  144. {
  145. if (is_writeable($dir))
  146. {
  147. return true;
  148. }
  149. return false;
  150. }
  151. if ($dir == $olddir)
  152. { // this can happen in safe mode
  153. return @is_writable($dir);
  154. }
  155. }
  156. return false;
  157. }
  158. return is_writeable($this->install_dir);
  159. }
  160. function setConfig(&$config, $resetInstallDir = true)
  161. {
  162. $this->_config = &$config;
  163. if ($resetInstallDir)
  164. {
  165. $this->setInstallDir($config->get('php_dir'));
  166. }
  167. }
  168. function _initializeChannelDirs()
  169. {
  170. static $running = false;
  171. if (! $running)
  172. {
  173. $running = true;
  174. $ds = DIRECTORY_SEPARATOR;
  175. if (! is_dir($this->channelsdir) || ! file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || ! file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || ! file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || ! file_exists($this->channelsdir . $ds . '__uri.reg'))
  176. {
  177. if (! file_exists($this->channelsdir . $ds . 'pear.php.net.reg'))
  178. {
  179. $pear_channel = $this->_pearChannel;
  180. if (! is_a($pear_channel, 'PEAR_ChannelFile') || ! $pear_channel->validate())
  181. {
  182. if (! class_exists('PEAR_ChannelFile'))
  183. {
  184. require_once 'PEAR/ChannelFile.php';
  185. }
  186. $pear_channel = new PEAR_ChannelFile();
  187. $pear_channel->setAlias('pear');
  188. $pear_channel->setServer('pear.php.net');
  189. $pear_channel->setSummary('PHP Extension and Application Repository');
  190. $pear_channel->setDefaultPEARProtocols();
  191. $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
  192. $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
  193. $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
  194. //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/');
  195. }
  196. else
  197. {
  198. $pear_channel->setServer('pear.php.net');
  199. $pear_channel->setAlias('pear');
  200. }
  201. $pear_channel->validate();
  202. $this->_addChannel($pear_channel);
  203. }
  204. if (! file_exists($this->channelsdir . $ds . 'pecl.php.net.reg'))
  205. {
  206. $pecl_channel = $this->_peclChannel;
  207. if (! is_a($pecl_channel, 'PEAR_ChannelFile') || ! $pecl_channel->validate())
  208. {
  209. if (! class_exists('PEAR_ChannelFile'))
  210. {
  211. require_once 'PEAR/ChannelFile.php';
  212. }
  213. $pecl_channel = new PEAR_ChannelFile();
  214. $pecl_channel->setAlias('pecl');
  215. $pecl_channel->setServer('pecl.php.net');
  216. $pecl_channel->setSummary('PHP Extension Community Library');
  217. $pecl_channel->setDefaultPEARProtocols();
  218. $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
  219. $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
  220. $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
  221. }
  222. else
  223. {
  224. $pecl_channel->setServer('pecl.php.net');
  225. $pecl_channel->setAlias('pecl');
  226. }
  227. $pecl_channel->validate();
  228. $this->_addChannel($pecl_channel);
  229. }
  230. if (! file_exists($this->channelsdir . $ds . 'doc.php.net.reg'))
  231. {
  232. $doc_channel = $this->_docChannel;
  233. if (! is_a($doc_channel, 'PEAR_ChannelFile') || ! $doc_channel->validate())
  234. {
  235. if (! class_exists('PEAR_ChannelFile'))
  236. {
  237. require_once 'PEAR/ChannelFile.php';
  238. }
  239. $doc_channel = new PEAR_ChannelFile();
  240. $doc_channel->setAlias('phpdocs');
  241. $doc_channel->setServer('doc.php.net');
  242. $doc_channel->setSummary('PHP Documentation Team');
  243. $doc_channel->setDefaultPEARProtocols();
  244. $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
  245. $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
  246. $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
  247. }
  248. else
  249. {
  250. $doc_channel->setServer('doc.php.net');
  251. $doc_channel->setAlias('doc');
  252. }
  253. $doc_channel->validate();
  254. $this->_addChannel($doc_channel);
  255. }
  256. if (! file_exists($this->channelsdir . $ds . '__uri.reg'))
  257. {
  258. if (! class_exists('PEAR_ChannelFile'))
  259. {
  260. require_once 'PEAR/ChannelFile.php';
  261. }
  262. $private = new PEAR_ChannelFile();
  263. $private->setName('__uri');
  264. $private->setDefaultPEARProtocols();
  265. $private->setBaseURL('REST1.0', '****');
  266. $private->setSummary('Pseudo-channel for static packages');
  267. $this->_addChannel($private);
  268. }
  269. $this->_rebuildFileMap();
  270. }
  271. $running = false;
  272. }
  273. }
  274. function _initializeDirs()
  275. {
  276. $ds = DIRECTORY_SEPARATOR;
  277. // XXX Compatibility code should be removed in the future
  278. // rename all registry files if any to lowercase
  279. if (! OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && $handle = opendir($this->statedir))
  280. {
  281. $dest = $this->statedir . $ds;
  282. while (false !== ($file = readdir($handle)))
  283. {
  284. if (preg_match('/^.*[A-Z].*\.reg\\z/', $file))
  285. {
  286. rename($dest . $file, $dest . strtolower($file));
  287. }
  288. }
  289. closedir($handle);
  290. }
  291. $this->_initializeChannelDirs();
  292. if (! file_exists($this->filemap))
  293. {
  294. $this->_rebuildFileMap();
  295. }
  296. $this->_initializeDepDB();
  297. }
  298. function _initializeDepDB()
  299. {
  300. if (! isset($this->_dependencyDB))
  301. {
  302. static $initializing = false;
  303. if (! $initializing)
  304. {
  305. $initializing = true;
  306. if (! $this->_config)
  307. { // never used?
  308. $file = OS_WINDOWS ? 'pear.ini' : '.pearrc';
  309. $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . $file);
  310. $this->_config->setRegistry($this);
  311. $this->_config->set('php_dir', $this->install_dir);
  312. }
  313. $this->_dependencyDB = &PEAR_DependencyDB :: singleton($this->_config);
  314. if (PEAR :: isError($this->_dependencyDB))
  315. {
  316. // attempt to recover by removing the dep db
  317. if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . DIRECTORY_SEPARATOR . '.depdb'))
  318. {
  319. @unlink($this->_config->get('php_dir', null, 'pear.php.net') . DIRECTORY_SEPARATOR . '.depdb');
  320. }
  321. $this->_dependencyDB = &PEAR_DependencyDB :: singleton($this->_config);
  322. if (PEAR :: isError($this->_dependencyDB))
  323. {
  324. echo $this->_dependencyDB->getMessage();
  325. echo 'Unrecoverable error';
  326. exit(1);
  327. }
  328. }
  329. $initializing = false;
  330. }
  331. }
  332. }
  333. /**
  334. * PEAR_Registry destructor. Makes sure no locks are forgotten.
  335. *
  336. * @access private
  337. */
  338. function _PEAR_Registry()
  339. {
  340. parent :: _PEAR();
  341. if (is_resource($this->lock_fp))
  342. {
  343. $this->_unlock();
  344. }
  345. }
  346. /**
  347. * Make sure the directory where we keep registry files exists.
  348. *
  349. * @return bool TRUE if directory exists, FALSE if it could not be
  350. * created
  351. *
  352. * @access private
  353. */
  354. function _assertStateDir($channel = false)
  355. {
  356. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net')
  357. {
  358. return $this->_assertChannelStateDir($channel);
  359. }
  360. static $init = false;
  361. if (! file_exists($this->statedir))
  362. {
  363. if (! $this->hasWriteAccess())
  364. {
  365. return false;
  366. }
  367. require_once 'System.php';
  368. if (! System :: mkdir(array('-p', $this->statedir)))
  369. {
  370. return $this->raiseError("could not create directory '{$this->statedir}'");
  371. }
  372. $init = true;
  373. }
  374. elseif (! is_dir($this->statedir))
  375. {
  376. return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . 'it already exists and is not a directory');
  377. }
  378. $ds = DIRECTORY_SEPARATOR;
  379. if (! file_exists($this->channelsdir))
  380. {
  381. if (! file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || ! file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || ! file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || ! file_exists($this->channelsdir . $ds . '__uri.reg'))
  382. {
  383. $init = true;
  384. }
  385. }
  386. elseif (! is_dir($this->channelsdir))
  387. {
  388. return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . 'it already exists and is not a directory');
  389. }
  390. if ($init)
  391. {
  392. static $running = false;
  393. if (! $running)
  394. {
  395. $running = true;
  396. $this->_initializeDirs();
  397. $running = false;
  398. $init = false;
  399. }
  400. }
  401. else
  402. {
  403. $this->_initializeDepDB();
  404. }
  405. return true;
  406. }
  407. /**
  408. * Make sure the directory where we keep registry files exists for a non-standard channel.
  409. *
  410. * @param string channel name
  411. * @return bool TRUE if directory exists, FALSE if it could not be
  412. * created
  413. *
  414. * @access private
  415. */
  416. function _assertChannelStateDir($channel)
  417. {
  418. $ds = DIRECTORY_SEPARATOR;
  419. if (! $channel || $this->_getChannelFromAlias($channel) == 'pear.php.net')
  420. {
  421. if (! file_exists($this->channelsdir . $ds . 'pear.php.net.reg'))
  422. {
  423. $this->_initializeChannelDirs();
  424. }
  425. return $this->_assertStateDir($channel);
  426. }
  427. $channelDir = $this->_channelDirectoryName($channel);
  428. if (! is_dir($this->channelsdir) || ! file_exists($this->channelsdir . $ds . 'pear.php.net.reg'))
  429. {
  430. $this->_initializeChannelDirs();
  431. }
  432. if (! file_exists($channelDir))
  433. {
  434. if (! $this->hasWriteAccess())
  435. {
  436. return false;
  437. }
  438. require_once 'System.php';
  439. if (! System :: mkdir(array('-p', $channelDir)))
  440. {
  441. return $this->raiseError("could not create directory '" . $channelDir . "'");
  442. }
  443. }
  444. elseif (! is_dir($channelDir))
  445. {
  446. return $this->raiseError("could not create directory '" . $channelDir . "', already exists and is not a directory");
  447. }
  448. return true;
  449. }
  450. /**
  451. * Make sure the directory where we keep registry files for channels exists
  452. *
  453. * @return bool TRUE if directory exists, FALSE if it could not be
  454. * created
  455. *
  456. * @access private
  457. */
  458. function _assertChannelDir()
  459. {
  460. if (! file_exists($this->channelsdir))
  461. {
  462. if (! $this->hasWriteAccess())
  463. {
  464. return false;
  465. }
  466. require_once 'System.php';
  467. if (! System :: mkdir(array('-p', $this->channelsdir)))
  468. {
  469. return $this->raiseError("could not create directory '{$this->channelsdir}'");
  470. }
  471. }
  472. elseif (! is_dir($this->channelsdir))
  473. {
  474. return $this->raiseError("could not create directory '{$this->channelsdir}" . "', it already exists and is not a directory");
  475. }
  476. if (! file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))
  477. {
  478. if (! $this->hasWriteAccess())
  479. {
  480. return false;
  481. }
  482. require_once 'System.php';
  483. if (! System :: mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias')))
  484. {
  485. return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
  486. }
  487. }
  488. elseif (! is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))
  489. {
  490. return $this->raiseError("could not create directory '{$this->channelsdir}" . "/.alias', it already exists and is not a directory");
  491. }
  492. return true;
  493. }
  494. /**
  495. * Get the name of the file where data for a given package is stored.
  496. *
  497. * @param string channel name, or false if this is a PEAR package
  498. * @param string package name
  499. *
  500. * @return string registry file name
  501. *
  502. * @access public
  503. */
  504. function _packageFileName($package, $channel = false)
  505. {
  506. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net')
  507. {
  508. return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
  509. }
  510. return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
  511. }
  512. /**
  513. * Get the name of the file where data for a given channel is stored.
  514. * @param string channel name
  515. * @return string registry file name
  516. */
  517. function _channelFileName($channel, $noaliases = false)
  518. {
  519. if (! $noaliases)
  520. {
  521. if (file_exists($this->_getChannelAliasFileName($channel)))
  522. {
  523. $channel = implode('', file($this->_getChannelAliasFileName($channel)));
  524. }
  525. }
  526. return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($channel)) . '.reg';
  527. }
  528. /**
  529. * @param string
  530. * @return string
  531. */
  532. function _getChannelAliasFileName($alias)
  533. {
  534. return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';
  535. }
  536. /**
  537. * Get the name of a channel from its alias
  538. */
  539. function _getChannelFromAlias($channel)
  540. {
  541. if (! $this->_channelExists($channel))
  542. {
  543. if ($channel == 'pear.php.net')
  544. {
  545. return 'pear.php.net';
  546. }
  547. if ($channel == 'pecl.php.net')
  548. {
  549. return 'pecl.php.net';
  550. }
  551. if ($channel == 'doc.php.net')
  552. {
  553. return 'doc.php.net';
  554. }
  555. if ($channel == '__uri')
  556. {
  557. return '__uri';
  558. }
  559. return false;
  560. }
  561. $channel = strtolower($channel);
  562. if (file_exists($this->_getChannelAliasFileName($channel)))
  563. {
  564. // translate an alias to an actual channel
  565. return implode('', file($this->_getChannelAliasFileName($channel)));
  566. }
  567. return $channel;
  568. }
  569. /**
  570. * Get the alias of a channel from its alias or its name
  571. */
  572. function _getAlias($channel)
  573. {
  574. if (! $this->_channelExists($channel))
  575. {
  576. if ($channel == 'pear.php.net')
  577. {
  578. return 'pear';
  579. }
  580. if ($channel == 'pecl.php.net')
  581. {
  582. return 'pecl';
  583. }
  584. if ($channel == 'doc.php.net')
  585. {
  586. return 'phpdocs';
  587. }
  588. return false;
  589. }
  590. $channel = $this->_getChannel($channel);
  591. if (PEAR :: isError($channel))
  592. {
  593. return $channel;
  594. }
  595. return $channel->getAlias();
  596. }
  597. /**
  598. * Get the name of the file where data for a given package is stored.
  599. *
  600. * @param string channel name, or false if this is a PEAR package
  601. * @param string package name
  602. *
  603. * @return string registry file name
  604. *
  605. * @access public
  606. */
  607. function _channelDirectoryName($channel)
  608. {
  609. if (! $channel || $this->_getChannelFromAlias($channel) == 'pear.php.net')
  610. {
  611. return $this->statedir;
  612. }
  613. $ch = $this->_getChannelFromAlias($channel);
  614. if (! $ch)
  615. {
  616. $ch = $channel;
  617. }
  618. return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . str_replace('/', '_', $ch));
  619. }
  620. function _openPackageFile($package, $mode, $channel = false)
  621. {
  622. if (! $this->_assertStateDir($channel))
  623. {
  624. return null;
  625. }
  626. if (! in_array($mode, array('r', 'rb')) && ! $this->hasWriteAccess())
  627. {
  628. return null;
  629. }
  630. $file = $this->_packageFileName($package, $channel);
  631. if (! file_exists($file) && $mode == 'r' || $mode == 'rb')
  632. {
  633. return null;
  634. }
  635. $fp = @fopen($file, $mode);
  636. if (! $fp)
  637. {
  638. return null;
  639. }
  640. return $fp;
  641. }
  642. function _closePackageFile($fp)
  643. {
  644. fclose($fp);
  645. }
  646. function _openChannelFile($channel, $mode)
  647. {
  648. if (! $this->_assertChannelDir())
  649. {
  650. return null;
  651. }
  652. if (! in_array($mode, array('r', 'rb')) && ! $this->hasWriteAccess())
  653. {
  654. return null;
  655. }
  656. $file = $this->_channelFileName($channel);
  657. if (! file_exists($file) && $mode == 'r' || $mode == 'rb')
  658. {
  659. return null;
  660. }
  661. $fp = @fopen($file, $mode);
  662. if (! $fp)
  663. {
  664. return null;
  665. }
  666. return $fp;
  667. }
  668. function _closeChannelFile($fp)
  669. {
  670. fclose($fp);
  671. }
  672. function _rebuildFileMap()
  673. {
  674. if (! class_exists('PEAR_Installer_Role'))
  675. {
  676. require_once 'PEAR/Installer/Role.php';
  677. }
  678. $channels = $this->_listAllPackages();
  679. $files = array();
  680. foreach ($channels as $channel => $packages)
  681. {
  682. foreach ($packages as $package)
  683. {
  684. $version = $this->_packageInfo($package, 'version', $channel);
  685. $filelist = $this->_packageInfo($package, 'filelist', $channel);
  686. if (! is_array($filelist))
  687. {
  688. continue;
  689. }
  690. foreach ($filelist as $name => $attrs)
  691. {
  692. if (isset($attrs['attribs']))
  693. {
  694. $attrs = $attrs['attribs'];
  695. }
  696. // it is possible for conflicting packages in different channels to
  697. // conflict with data files/doc files
  698. if ($name == 'dirtree')
  699. {
  700. continue;
  701. }
  702. if (isset($attrs['role']) && ! in_array($attrs['role'], PEAR_Installer_Role :: getInstallableRoles()))
  703. {
  704. // these are not installed
  705. continue;
  706. }
  707. if (isset($attrs['role']) && ! in_array($attrs['role'], PEAR_Installer_Role :: getBaseinstallRoles()))
  708. {
  709. $attrs['baseinstalldir'] = $package;
  710. }
  711. if (isset($attrs['baseinstalldir']))
  712. {
  713. $file = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
  714. }
  715. else
  716. {
  717. $file = $name;
  718. }
  719. $file = preg_replace(',^/+,', '', $file);
  720. if ($channel != 'pear.php.net')
  721. {
  722. if (! isset($files[$attrs['role']]))
  723. {
  724. $files[$attrs['role']] = array();
  725. }
  726. $files[$attrs['role']][$file] = array(strtolower($channel), strtolower($package));
  727. }
  728. else
  729. {
  730. if (! isset($files[$attrs['role']]))
  731. {
  732. $files[$attrs['role']] = array();
  733. }
  734. $files[$attrs['role']][$file] = strtolower($package);
  735. }
  736. }
  737. }
  738. }
  739. $this->_assertStateDir();
  740. if (! $this->hasWriteAccess())
  741. {
  742. return false;
  743. }
  744. $fp = @fopen($this->filemap, 'wb');
  745. if (! $fp)
  746. {
  747. return false;
  748. }
  749. $this->filemap_cache = $files;
  750. fwrite($fp, serialize($files));
  751. fclose($fp);
  752. return true;
  753. }
  754. function _readFileMap()
  755. {
  756. if (! file_exists($this->filemap))
  757. {
  758. return array();
  759. }
  760. $fp = @fopen($this->filemap, 'r');
  761. if (! $fp)
  762. {
  763. return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
  764. }
  765. clearstatcache();
  766. $rt = get_magic_quotes_runtime();
  767. set_magic_quotes_runtime(0);
  768. $fsize = filesize($this->filemap);
  769. fclose($fp);
  770. $data = file_get_contents($this->filemap);
  771. set_magic_quotes_runtime($rt);
  772. $tmp = unserialize($data);
  773. if (! $tmp && $fsize > 7)
  774. {
  775. return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
  776. }
  777. $this->filemap_cache = $tmp;
  778. return true;
  779. }
  780. /**
  781. * Lock the registry.
  782. *
  783. * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
  784. * See flock manual for more information.
  785. *
  786. * @return bool TRUE on success, FALSE if locking failed, or a
  787. * PEAR error if some other error occurs (such as the
  788. * lock file not being writable).
  789. *
  790. * @access private
  791. */
  792. function _lock($mode = LOCK_EX)
  793. {
  794. if (stristr(php_uname(), 'Windows 9'))
  795. {
  796. return true;
  797. }
  798. if ($mode != LOCK_UN && is_resource($this->lock_fp))
  799. {
  800. // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  801. return true;
  802. }
  803. if (! $this->_assertStateDir())
  804. {
  805. if ($mode == LOCK_EX)
  806. {
  807. return $this->raiseError('Registry directory is not writeable by the current user');
  808. }
  809. return true;
  810. }
  811. $open_mode = 'w';
  812. // XXX People reported problems with LOCK_SH and 'w'
  813. if ($mode === LOCK_SH || $mode === LOCK_UN)
  814. {
  815. if (! file_exists($this->lockfile))
  816. {
  817. touch($this->lockfile);
  818. }
  819. $open_mode = 'r';
  820. }
  821. if (! is_resource($this->lock_fp))
  822. {
  823. $this->lock_fp = @fopen($this->lockfile, $open_mode);
  824. }
  825. if (! is_resource($this->lock_fp))
  826. {
  827. $this->lock_fp = null;
  828. return $this->raiseError("could not create lock file" . (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  829. }
  830. if (! (int) flock($this->lock_fp, $mode))
  831. {
  832. switch ($mode)
  833. {
  834. case LOCK_SH :
  835. $str = 'shared';
  836. break;
  837. case LOCK_EX :
  838. $str = 'exclusive';
  839. break;
  840. case LOCK_UN :
  841. $str = 'unlock';
  842. break;
  843. default :
  844. $str = 'unknown';
  845. break;
  846. }
  847. //is resource at this point, close it on error.
  848. fclose($this->lock_fp);
  849. $this->lock_fp = null;
  850. return $this->raiseError("could not acquire $str lock ($this->lockfile)", PEAR_REGISTRY_ERROR_LOCK);
  851. }
  852. return true;
  853. }
  854. function _unlock()
  855. {
  856. $ret = $this->_lock(LOCK_UN);
  857. if (is_resource($this->lock_fp))
  858. {
  859. fclose($this->lock_fp);
  860. }
  861. $this->lock_fp = null;
  862. return $ret;
  863. }
  864. function _packageExists($package, $channel = false)
  865. {
  866. return file_exists($this->_packageFileName($package, $channel));
  867. }
  868. /**
  869. * Determine whether a channel exists in the registry
  870. *
  871. * @param string Channel name
  872. * @param bool if true, then aliases will be ignored
  873. * @return boolean
  874. */
  875. function _channelExists($channel, $noaliases = false)
  876. {
  877. $a = file_exists($this->_channelFileName($channel, $noaliases));
  878. if (! $a && $channel == 'pear.php.net')
  879. {
  880. return true;
  881. }
  882. if (! $a && $channel == 'pecl.php.net')
  883. {
  884. return true;
  885. }
  886. if (! $a && $channel == 'doc.php.net')
  887. {
  888. return true;
  889. }
  890. return $a;
  891. }
  892. /**
  893. * Determine whether a mirror exists within the deafult channel in the registry
  894. *
  895. * @param string Channel name
  896. * @param string Mirror name
  897. *
  898. * @return boolean
  899. */
  900. function _mirrorExists($channel, $mirror)
  901. {
  902. $data = $this->_channelInfo($channel);
  903. if (! isset($data['servers']['mirror']))
  904. {
  905. return false;
  906. }
  907. foreach ($data['servers']['mirror'] as $m)
  908. {
  909. if ($m['attribs']['host'] == $mirror)
  910. {
  911. return true;
  912. }
  913. }
  914. return false;
  915. }
  916. /**
  917. * @param PEAR_ChannelFile Channel object
  918. * @param donotuse
  919. * @param string Last-Modified HTTP tag from remote request
  920. * @return boolean|PEAR_Error True on creation, false if it already exists
  921. */
  922. function _addChannel($channel, $update = false, $lastmodified = false)
  923. {
  924. if (! is_a($channel, 'PEAR_ChannelFile'))
  925. {
  926. return false;
  927. }
  928. if (! $channel->validate())
  929. {
  930. return false;
  931. }
  932. if (file_exists($this->_channelFileName($channel->getName())))
  933. {
  934. if (! $update)
  935. {
  936. return false;
  937. }
  938. $checker = $this->_getChannel($channel->getName());
  939. if (PEAR :: isError($checker))
  940. {
  941. return $checker;
  942. }
  943. if ($channel->getAlias() != $checker->getAlias())
  944. {
  945. if (file_exists($this->_getChannelAliasFileName($checker->getAlias())))
  946. {
  947. @unlink($this->_getChannelAliasFileName($checker->getAlias()));
  948. }
  949. }
  950. }
  951. else
  952. {
  953. if ($update && ! in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net')))
  954. {
  955. return false;
  956. }
  957. }
  958. $ret = $this->_assertChannelDir();
  959. if (PEAR :: isError($ret))
  960. {
  961. return $ret;
  962. }
  963. $ret = $this->_assertChannelStateDir($channel->getName());
  964. if (PEAR :: isError($ret))
  965. {
  966. return $ret;
  967. }
  968. if ($channel->getAlias() != $channel->getName())
  969. {
  970. if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName())
  971. {
  972. $channel->setAlias($channel->getName());
  973. }
  974. if (! $this->hasWriteAccess())
  975. {
  976. return false;
  977. }
  978. $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');
  979. if (! $fp)
  980. {
  981. return false;
  982. }
  983. fwrite($fp, $channel->getName());
  984. fclose($fp);
  985. }
  986. if (! $this->hasWriteAccess())
  987. {
  988. return false;
  989. }
  990. $fp = @fopen($this->_channelFileName($channel->getName()), 'wb');
  991. if (! $fp)
  992. {
  993. return false;
  994. }
  995. $info = $channel->toArray();
  996. if ($lastmodified)
  997. {
  998. $info['_lastmodified'] = $lastmodified;
  999. }
  1000. else
  1001. {
  1002. $info['_lastmodified'] = date('r');
  1003. }
  1004. fwrite($fp, serialize($info));
  1005. fclose($fp);
  1006. return true;
  1007. }
  1008. /**
  1009. * Deletion fails if there are any packages installed from the channel
  1010. * @param string|PEAR_ChannelFile channel name
  1011. * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
  1012. */
  1013. function _deleteChannel($channel)
  1014. {
  1015. if (! is_string($channel))
  1016. {
  1017. if (! is_a($channel, 'PEAR_ChannelFile'))
  1018. {
  1019. return false;
  1020. }
  1021. if (! $channel->validate())
  1022. {
  1023. return false;
  1024. }
  1025. $channel = $channel->getName();
  1026. }
  1027. if ($this->_getChannelFromAlias($channel) == '__uri')
  1028. {
  1029. return false;
  1030. }
  1031. if ($this->_getChannelFromAlias($channel) == 'pecl.php.net')
  1032. {
  1033. return false;
  1034. }
  1035. if ($this->_getChannelFromAlias($channel) == 'doc.php.net')
  1036. {
  1037. return false;
  1038. }
  1039. if (! $this->_channelExists($channel))
  1040. {
  1041. return false;
  1042. }
  1043. if (! $channel || $this->_getChannelFromAlias($channel) == 'pear.php.net')
  1044. {
  1045. return false;
  1046. }
  1047. $channel = $this->_getChannelFromAlias($channel);
  1048. if ($channel == 'pear.php.net')
  1049. {
  1050. return false;
  1051. }
  1052. $test = $this->_listChannelPackages($channel);
  1053. if (count($test))
  1054. {
  1055. return false;
  1056. }
  1057. $test = @rmdir($this->_channelDirectoryName($channel));
  1058. if (! $test)
  1059. {
  1060. return false;
  1061. }
  1062. $file = $this->_getChannelAliasFileName($this->_getAlias($channel));
  1063. if (file_exists($file))
  1064. {
  1065. $test = @unlink($file);
  1066. if (! $test)
  1067. {
  1068. return false;
  1069. }
  1070. }
  1071. $file = $this->_channelFileName($channel);
  1072. $ret = true;
  1073. if (file_exists($file))
  1074. {
  1075. $ret = @unlink($file);
  1076. }
  1077. return $ret;
  1078. }
  1079. /**
  1080. * Determine whether a channel exists in the registry
  1081. * @param string Channel Alias
  1082. * @return boolean
  1083. */
  1084. function _isChannelAlias($alias)
  1085. {
  1086. return file_exists($this->_getChannelAliasFileName($alias));
  1087. }
  1088. /**
  1089. * @param string|null
  1090. * @param string|null
  1091. * @param string|null
  1092. * @return array|null
  1093. * @access private
  1094. */
  1095. function _packageInfo($package = null, $key = null, $channel = 'pear.php.net')
  1096. {
  1097. if ($package === null)
  1098. {
  1099. if ($channel === null)
  1100. {
  1101. $channels = $this->_listChannels();
  1102. $ret = array();
  1103. foreach ($channels as $channel)
  1104. {
  1105. $channel = strtolower($channel);
  1106. $ret[$channel] = array();
  1107. $packages = $this->_listPackages($channel);
  1108. foreach ($packages as $package)
  1109. {
  1110. $ret[$channel][] = $this->_packageInfo($package, null, $channel);
  1111. }
  1112. }
  1113. return $ret;
  1114. }
  1115. $ps = $this->_listPackages($channel);
  1116. if (! count($ps))
  1117. {
  1118. return array();
  1119. }
  1120. return array_map(array(&$this, '_packageInfo'), $ps, array_fill(0, count($ps), null), array_fill(0, count($ps), $channel));
  1121. }
  1122. $fp = $this->_openPackageFile($package, 'r', $channel);
  1123. if ($fp === null)
  1124. {
  1125. return null;
  1126. }
  1127. $rt = get_magic_quotes_runtime();
  1128. set_magic_quotes_runtime(0);
  1129. clearstatcache();
  1130. $this->_closePackageFile($fp);
  1131. $data = file_get_contents($this->_packageFileName($package, $channel));
  1132. set_magic_quotes_runtime($rt);
  1133. $data = unserialize($data);
  1134. if ($key === null)
  1135. {
  1136. return $data;
  1137. }
  1138. // compatibility for package.xml version 2.0
  1139. if (isset($data['old'][$key]))
  1140. {
  1141. return $data['old'][$key];
  1142. }
  1143. if (isset($data[$key]))
  1144. {
  1145. return $data[$key];
  1146. }
  1147. return null;
  1148. }
  1149. /**
  1150. * @param string Channel name
  1151. * @param bool whether to strictly retrieve info of channels, not just aliases
  1152. * @return array|null
  1153. */
  1154. function _channelInfo($channel, $noaliases = false)
  1155. {
  1156. if (! $this->_channelExists($channel, $noaliases))
  1157. {
  1158. return null;
  1159. }
  1160. $fp = $this->_openChannelFile($channel, 'r');
  1161. if ($fp === null)
  1162. {
  1163. return null;
  1164. }
  1165. $rt = get_magic_quotes_runtime();
  1166. set_magic_quotes_runtime(0);
  1167. clearstatcache();
  1168. $this->_closeChannelFile($fp);
  1169. $data = file_get_contents($this->_channelFileName($channel));
  1170. set_magic_quotes_runtime($rt);
  1171. $data = unserialize($data);
  1172. return $data;
  1173. }
  1174. function _listChannels()
  1175. {
  1176. $channellist = array();
  1177. if (! file_exists($this->channelsdir) || ! is_dir($this->channelsdir))
  1178. {
  1179. return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri');
  1180. }
  1181. $dp = opendir($this->channelsdir);
  1182. while ($ent = readdir($dp))
  1183. {
  1184. if ($ent{0} == '.' || substr($ent, - 4) != '.reg')
  1185. {
  1186. continue;
  1187. }
  1188. if ($ent == '__uri.reg')
  1189. {
  1190. $channellist[] = '__uri';
  1191. continue;
  1192. }
  1193. $channellist[] = str_replace('_', '/', substr($ent, 0, - 4));
  1194. }
  1195. closedir($dp);
  1196. if (! in_array('pear.php.net', $channellist))
  1197. {
  1198. $channellist[] = 'pear.php.net';
  1199. }
  1200. if (! in_array('pecl.php.net', $channellist))
  1201. {
  1202. $channellist[] = 'pecl.php.net';
  1203. }
  1204. if (! in_array('doc.php.net', $channellist))
  1205. {
  1206. $channellist[] = 'doc.php.net';
  1207. }
  1208. if (! in_array('__uri', $channellist))
  1209. {
  1210. $channellist[] = '__uri';
  1211. }
  1212. natsort($channellist);
  1213. return $channellist;
  1214. }
  1215. function _listPackages($channel = false)
  1216. {
  1217. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net')
  1218. {
  1219. return $this->_listChannelPackages($channel);
  1220. }
  1221. if (! file_exists($this->statedir) || ! is_dir($this->statedir))
  1222. {
  1223. return array();
  1224. }
  1225. $pkglist = array();
  1226. $dp = opendir($this->statedir);
  1227. if (! $dp)
  1228. {
  1229. return $pkglist;
  1230. }
  1231. while ($ent = readdir($dp))
  1232. {
  1233. if ($ent{0} == '.' || substr($ent, - 4) != '.reg')
  1234. {
  1235. continue;
  1236. }
  1237. $pkglist[] = substr($ent, 0, - 4);
  1238. }
  1239. closedir($dp);
  1240. return $pkglist;
  1241. }
  1242. function _listChannelPackages($channel)
  1243. {
  1244. $pkglist = array();
  1245. if (! file_exists($this->_channelDirectoryName($channel)) || ! is_dir($this->_channelDirectoryName($channel)))
  1246. {
  1247. return array();
  1248. }
  1249. $dp = opendir($this->_channelDirectoryName($channel));
  1250. if (! $dp)
  1251. {
  1252. return $pkglist;
  1253. }
  1254. while ($ent = readdir($dp))
  1255. {
  1256. if ($ent{0} == '.' || substr($ent, - 4) != '.reg')
  1257. {
  1258. continue;
  1259. }
  1260. $pkglist[] = substr($ent, 0, - 4);
  1261. }
  1262. closedir($dp);
  1263. return $pkglist;
  1264. }
  1265. function _listAllPackages()
  1266. {
  1267. $ret = array();
  1268. foreach ($this->_listChannels() as $channel)
  1269. {
  1270. $ret[$channel] = $this->_listPackages($channel);
  1271. }
  1272. return $ret;
  1273. }
  1274. /**
  1275. * Add an installed package to the registry
  1276. * @param string package name
  1277. * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  1278. * @return bool success of saving
  1279. * @access private
  1280. */
  1281. function _addPackage($package, $info)
  1282. {
  1283. if ($this->_packageExists($package))
  1284. {
  1285. return false;
  1286. }
  1287. $fp = $this->_openPackageFile($package, 'wb');
  1288. if ($fp === null)
  1289. {
  1290. return false;
  1291. }
  1292. $info['_lastmodified'] = time();
  1293. fwrite($fp, serialize($info));
  1294. $this->_closePackageFile($fp);
  1295. if (isset($info['filelist']))
  1296. {
  1297. $this->_rebuildFileMap();
  1298. }
  1299. return true;
  1300. }
  1301. /**
  1302. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  1303. * @return bool
  1304. * @access private
  1305. */
  1306. function _addPackage2($info)
  1307. {
  1308. if (! is_a($info, 'PEAR_PackageFile_v1') && ! is_a($info, 'PEAR_PackageFile_v2'))
  1309. {
  1310. return false;
  1311. }
  1312. if (! $info->validate())
  1313. {
  1314. if (class_exists('PEAR_Common'))
  1315. {
  1316. $ui = PEAR_Frontend :: singleton();
  1317. if ($ui)
  1318. {
  1319. foreach ($info->getValidationWarnings() as $err)
  1320. {
  1321. $ui->log($err['message'], true);
  1322. }
  1323. }
  1324. }
  1325. return false;
  1326. }
  1327. $channel = $info->getChannel();
  1328. $package = $info->getPackage();
  1329. $save = $info;
  1330. if ($this->_packageExists($package, $channel))
  1331. {
  1332. return false;
  1333. }
  1334. if (! $this->_channelExists($channel, true))
  1335. {
  1336. return false;
  1337. }
  1338. $info = $info->toArray(true);
  1339. if (! $info)
  1340. {
  1341. return false;
  1342. }
  1343. $fp = $this->_openPackageFile($package, 'wb', $channel);
  1344. if ($fp === null)
  1345. {
  1346. return false;
  1347. }
  1348. $info['_lastmodified'] = time();
  1349. fwrite($fp, serialize($info));
  1350. $this->_closePackageFile($fp);
  1351. $this->_rebuildFileMap();
  1352. return true;
  1353. }
  1354. /**
  1355. * @param string Package name
  1356. * @param array parsed package.xml 1.0
  1357. * @param bool this parameter is only here for BC. Don't use it.
  1358. * @access private
  1359. */
  1360. function _updatePackage($package, $info, $merge = true)
  1361. {
  1362. $oldinfo = $this->_packageInfo($package);
  1363. if (empty($oldinfo))
  1364. {
  1365. return false;
  1366. }
  1367. $fp = $this->_openPackageFile($package, 'w');
  1368. if ($fp === null)
  1369. {
  1370. return false;
  1371. }
  1372. if (is_object($info))
  1373. {
  1374. $info = $info->toArray();
  1375. }
  1376. $info['_lastmodified'] = time();
  1377. $newinfo = $info;
  1378. if ($merge)
  1379. {
  1380. $info = array_merge($oldinfo, $info);
  1381. }
  1382. else
  1383. {
  1384. $diff = $info;
  1385. }
  1386. fwrite($fp, serialize($info));
  1387. $this->_closePackageFile($fp);
  1388. if (isset($newinfo['filelist']))
  1389. {
  1390. $this->_rebuildFileMap();
  1391. }
  1392. return true;
  1393. }
  1394. /**
  1395. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  1396. * @return bool
  1397. * @access private
  1398. */
  1399. function _updatePackage2($info)
  1400. {
  1401. if (! $this->_packageExists($info->getPackage(), $info->getChannel()))
  1402. {
  1403. return false;
  1404. }
  1405. $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());
  1406. if ($fp === null)
  1407. {
  1408. return false;
  1409. }
  1410. $save = $info;
  1411. $info = $save->getArray(true);
  1412. $info['_lastmodified'] = time();
  1413. fwrite($fp, serialize($info));
  1414. $this->_closePackageFile($fp);
  1415. $this->_rebuildFileMap();
  1416. return true;
  1417. }
  1418. /**
  1419. * @param string Package name
  1420. * @param string Channel name
  1421. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  1422. * @access private
  1423. */
  1424. function &_getPackage($package, $channel = 'pear.php.net')
  1425. {
  1426. $info = $this->_packageInfo($package, null, $channel);
  1427. if ($info === null)
  1428. {
  1429. return $info;
  1430. }
  1431. $a = $this->_config;
  1432. if (! $a)
  1433. {
  1434. $this->_config = &new PEAR_Config();
  1435. $this->_config->set('php_dir', $this->statedir);
  1436. }
  1437. if (! class_exists('PEAR_PackageFile'))
  1438. {
  1439. require_once 'PEAR/PackageFile.php';
  1440. }
  1441. $pkg = &new PEAR_PackageFile($this->_config);
  1442. $pf = &$pkg->fromArray($info);
  1443. return $pf;
  1444. }
  1445. /**
  1446. * @param string channel name
  1447. * @param bool whether to strictly retrieve channel names
  1448. * @return PEAR_ChannelFile|PEAR_Error
  1449. * @access private
  1450. */
  1451. function &_getChannel($channel, $noaliases = false)
  1452. {
  1453. $ch = false;
  1454. if ($this->_channelExists($channel, $noaliases))
  1455. {
  1456. $chinfo = $this->_channelInfo($channel, $noaliases);
  1457. if ($chinfo)
  1458. {
  1459. if (! class_exists('PEAR_ChannelFile'))
  1460. {
  1461. require_once 'PEAR/ChannelFile.php';
  1462. }
  1463. $ch = &PEAR_ChannelFile :: fromArrayWithErrors($chinfo);
  1464. }
  1465. }
  1466. if ($ch)
  1467. {
  1468. if ($ch->validate())
  1469. {
  1470. return $ch;
  1471. }
  1472. foreach ($ch->getErrors(true) as $err)
  1473. {
  1474. $message = $err['message'] . "\n";
  1475. }
  1476. $ch = PEAR :: raiseError($message);
  1477. return $ch;
  1478. }
  1479. if ($this->_getChannelFromAlias($channel) == 'pear.php.net')
  1480. {
  1481. // the registry is not properly set up, so use defaults
  1482. if (! class_exists('PEAR_ChannelFile'))
  1483. {
  1484. require_once 'PEAR/ChannelFile.php';
  1485. }
  1486. $pear_channel = new PEAR_ChannelFile();
  1487. $pear_channel->setServer('pear.php.net');
  1488. $pear_channel->setAlias('pear');
  1489. $pear_channel->setSummary('PHP Extension and Application Repository');
  1490. $pear_channel->setDefaultPEARProtocols();
  1491. $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
  1492. $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
  1493. $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
  1494. return $pear_channel;
  1495. }
  1496. if ($this->_getChannelFromAlias($channel) == 'pecl.php.net')
  1497. {
  1498. // the registry is not properly set up, so use defaults
  1499. if (! class_exists('PEAR_ChannelFile'))
  1500. {
  1501. require_once 'PEAR/ChannelFile.php';
  1502. }
  1503. $pear_channel = new PEAR_ChannelFile();
  1504. $pear_channel->setServer('pecl.php.net');
  1505. $pear_channel->setAlias('pecl');
  1506. $pear_channel->setSummary('PHP Extension Community Library');
  1507. $pear_channel->setDefaultPEARProtocols();
  1508. $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
  1509. $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
  1510. $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
  1511. return $pear_channel;
  1512. }
  1513. if ($this->_getChannelFromAlias($channel) == 'doc.php.net')
  1514. {
  1515. // the registry is not properly set up, so use defaults
  1516. if (! class_exists('PEAR_ChannelFile'))
  1517. {
  1518. require_once 'PEAR/ChannelFile.php';
  1519. }
  1520. $doc_channel = new PEAR_ChannelFile();
  1521. $doc_channel->setServer('doc.php.net');
  1522. $doc_channel->setAlias('phpdocs');
  1523. $doc_channel->setSummary('PHP Documentation Team');
  1524. $doc_channel->setDefaultPEARProtocols();
  1525. $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
  1526. $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
  1527. $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
  1528. return $doc_channel;
  1529. }
  1530. if ($this->_getChannelFromAlias($channel) == '__uri')
  1531. {
  1532. // the registry is not properly set up, so use defaults
  1533. if (! class_exists('PEAR_ChannelFile'))
  1534. {
  1535. require_once 'PEAR/ChannelFile.php';
  1536. }
  1537. $private = new PEAR_ChannelFile();
  1538. $private->setName('__uri');
  1539. $private->setDefaultPEARProtocols();
  1540. $private->setBaseURL('REST1.0', '****');
  1541. $private->setSummary('Pseudo-channel for static packages');
  1542. return $private;
  1543. }
  1544. return $ch;
  1545. }
  1546. /**
  1547. * @param string Package name
  1548. * @param string Channel name
  1549. * @return bool
  1550. */
  1551. function packageExists($package, $channel = 'pear.php.net')
  1552. {
  1553. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1554. {
  1555. return $e;
  1556. }
  1557. $ret = $this->_packageExists($package, $channel);
  1558. $this->_unlock();
  1559. return $ret;
  1560. }
  1561. // }}}
  1562. // {{{ channelExists()
  1563. /**
  1564. * @param string channel name
  1565. * @param bool if true, then aliases will be ignored
  1566. * @return bool
  1567. */
  1568. function channelExists($channel, $noaliases = false)
  1569. {
  1570. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1571. {
  1572. return $e;
  1573. }
  1574. $ret = $this->_channelExists($channel, $noaliases);
  1575. $this->_unlock();
  1576. return $ret;
  1577. }
  1578. // }}}
  1579. /**
  1580. * @param string channel name mirror is in
  1581. * @param string mirror name
  1582. *
  1583. * @return bool
  1584. */
  1585. function mirrorExists($channel, $mirror)
  1586. {
  1587. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1588. {
  1589. return $e;
  1590. }
  1591. $ret = $this->_mirrorExists($channel, $mirror);
  1592. $this->_unlock();
  1593. return $ret;
  1594. }
  1595. // {{{ isAlias()
  1596. /**
  1597. * Determines whether the parameter is an alias of a channel
  1598. * @param string
  1599. * @return bool
  1600. */
  1601. function isAlias($alias)
  1602. {
  1603. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1604. {
  1605. return $e;
  1606. }
  1607. $ret = $this->_isChannelAlias($alias);
  1608. $this->_unlock();
  1609. return $ret;
  1610. }
  1611. // }}}
  1612. // {{{ packageInfo()
  1613. /**
  1614. * @param string|null
  1615. * @param string|null
  1616. * @param string
  1617. * @return array|null
  1618. */
  1619. function packageInfo($package = null, $key = null, $channel = 'pear.php.net')
  1620. {
  1621. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1622. {
  1623. return $e;
  1624. }
  1625. $ret = $this->_packageInfo($package, $key, $channel);
  1626. $this->_unlock();
  1627. return $ret;
  1628. }
  1629. // }}}
  1630. // {{{ channelInfo()
  1631. /**
  1632. * Retrieve a raw array of channel data.
  1633. *
  1634. * Do not use this, instead use {@link getChannel()} for normal
  1635. * operations. Array structure is undefined in this method
  1636. * @param string channel name
  1637. * @param bool whether to strictly retrieve information only on non-aliases
  1638. * @return array|null|PEAR_Error
  1639. */
  1640. function channelInfo($channel = null, $noaliases = false)
  1641. {
  1642. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1643. {
  1644. return $e;
  1645. }
  1646. $ret = $this->_channelInfo($channel, $noaliases);
  1647. $this->_unlock();
  1648. return $ret;
  1649. }
  1650. // }}}
  1651. /**
  1652. * @param string
  1653. */
  1654. function channelName($channel)
  1655. {
  1656. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1657. {
  1658. return $e;
  1659. }
  1660. $ret = $this->_getChannelFromAlias($channel);
  1661. $this->_unlock();
  1662. return $ret;
  1663. }
  1664. /**
  1665. * @param string
  1666. */
  1667. function channelAlias($channel)
  1668. {
  1669. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1670. {
  1671. return $e;
  1672. }
  1673. $ret = $this->_getAlias($channel);
  1674. $this->_unlock();
  1675. return $ret;
  1676. }
  1677. // {{{ listPackages()
  1678. function listPackages($channel = false)
  1679. {
  1680. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1681. {
  1682. return $e;
  1683. }
  1684. $ret = $this->_listPackages($channel);
  1685. $this->_unlock();
  1686. return $ret;
  1687. }
  1688. // }}}
  1689. // {{{ listAllPackages()
  1690. function listAllPackages()
  1691. {
  1692. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1693. {
  1694. return $e;
  1695. }
  1696. $ret = $this->_listAllPackages();
  1697. $this->_unlock();
  1698. return $ret;
  1699. }
  1700. // }}}
  1701. // {{{ listChannel()
  1702. function listChannels()
  1703. {
  1704. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1705. {
  1706. return $e;
  1707. }
  1708. $ret = $this->_listChannels();
  1709. $this->_unlock();
  1710. return $ret;
  1711. }
  1712. // }}}
  1713. // {{{ addPackage()
  1714. /**
  1715. * Add an installed package to the registry
  1716. * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object
  1717. * that will be passed to {@link addPackage2()}
  1718. * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  1719. * @return bool success of saving
  1720. */
  1721. function addPackage($package, $info)
  1722. {
  1723. if (is_object($info))
  1724. {
  1725. return $this->addPackage2($info);
  1726. }
  1727. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1728. {
  1729. return $e;
  1730. }
  1731. $ret = $this->_addPackage($package, $info);
  1732. $this->_unlock();
  1733. if ($ret)
  1734. {
  1735. if (! class_exists('PEAR_PackageFile_v1'))
  1736. {
  1737. require_once 'PEAR/PackageFile/v1.php';
  1738. }
  1739. $pf = new PEAR_PackageFile_v1();
  1740. $pf->setConfig($this->_config);
  1741. $pf->fromArray($info);
  1742. $this->_dependencyDB->uninstallPackage($pf);
  1743. $this->_dependencyDB->installPackage($pf);
  1744. }
  1745. return $ret;
  1746. }
  1747. // }}}
  1748. // {{{ addPackage2()
  1749. function addPackage2($info)
  1750. {
  1751. if (! is_object($info))
  1752. {
  1753. return $this->addPackage($info['package'], $info);
  1754. }
  1755. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1756. {
  1757. return $e;
  1758. }
  1759. $ret = $this->_addPackage2($info);
  1760. $this->_unlock();
  1761. if ($ret)
  1762. {
  1763. $this->_dependencyDB->uninstallPackage($info);
  1764. $this->_dependencyDB->installPackage($info);
  1765. }
  1766. return $ret;
  1767. }
  1768. // }}}
  1769. // {{{ updateChannel()
  1770. /**
  1771. * For future expandibility purposes, separate this
  1772. * @param PEAR_ChannelFile
  1773. */
  1774. function updateChannel($channel, $lastmodified = null)
  1775. {
  1776. if ($channel->getName() == '__uri')
  1777. {
  1778. return false;
  1779. }
  1780. return $this->addChannel($channel, $lastmodified, true);
  1781. }
  1782. // }}}
  1783. // {{{ deleteChannel()
  1784. /**
  1785. * Deletion fails if there are any packages installed from the channel
  1786. * @param string|PEAR_ChannelFile channel name
  1787. * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
  1788. */
  1789. function deleteChannel($channel)
  1790. {
  1791. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1792. {
  1793. return $e;
  1794. }
  1795. $ret = $this->_deleteChannel($channel);
  1796. $this->_unlock();
  1797. if ($ret && is_a($this->_config, 'PEAR_Config'))
  1798. {
  1799. $this->_config->setChannels($this->listChannels());
  1800. }
  1801. return $ret;
  1802. }
  1803. // }}}
  1804. // {{{ addChannel()
  1805. /**
  1806. * @param PEAR_ChannelFile Channel object
  1807. * @param string Last-Modified header from HTTP for caching
  1808. * @return boolean|PEAR_Error True on creation, false if it already exists
  1809. */
  1810. function addChannel($channel, $lastmodified = false, $update = false)
  1811. {
  1812. if (! is_a($channel, 'PEAR_ChannelFile') || ! $channel->validate())
  1813. {
  1814. return false;
  1815. }
  1816. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1817. {
  1818. return $e;
  1819. }
  1820. $ret = $this->_addChannel($channel, $update, $lastmodified);
  1821. $this->_unlock();
  1822. if (! $update && $ret && is_a($this->_config, 'PEAR_Config'))
  1823. {
  1824. $this->_config->setChannels($this->listChannels());
  1825. }
  1826. return $ret;
  1827. }
  1828. // }}}
  1829. // {{{ deletePackage()
  1830. function deletePackage($package, $channel = 'pear.php.net')
  1831. {
  1832. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1833. {
  1834. return $e;
  1835. }
  1836. $file = $this->_packageFileName($package, $channel);
  1837. $ret = file_exists($file) ? @unlink($file) : false;
  1838. $this->_rebuildFileMap();
  1839. $this->_unlock();
  1840. $p = array('channel' => $channel, 'package' => $package);
  1841. $this->_dependencyDB->uninstallPackage($p);
  1842. return $ret;
  1843. }
  1844. // }}}
  1845. // {{{ updatePackage()
  1846. function updatePackage($package, $info, $merge = true)
  1847. {
  1848. if (is_object($info))
  1849. {
  1850. return $this->updatePackage2($info, $merge);
  1851. }
  1852. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1853. {
  1854. return $e;
  1855. }
  1856. $ret = $this->_updatePackage($package, $info, $merge);
  1857. $this->_unlock();
  1858. if ($ret)
  1859. {
  1860. if (! class_exists('PEAR_PackageFile_v1'))
  1861. {
  1862. require_once 'PEAR/PackageFile/v1.php';
  1863. }
  1864. $pf = new PEAR_PackageFile_v1();
  1865. $pf->setConfig($this->_config);
  1866. $pf->fromArray($this->packageInfo($package));
  1867. $this->_dependencyDB->uninstallPackage($pf);
  1868. $this->_dependencyDB->installPackage($pf);
  1869. }
  1870. return $ret;
  1871. }
  1872. // }}}
  1873. // {{{ updatePackage2()
  1874. function updatePackage2($info)
  1875. {
  1876. if (! is_object($info))
  1877. {
  1878. return $this->updatePackage($info['package'], $info, $merge);
  1879. }
  1880. if (! $info->validate(PEAR_VALIDATE_DOWNLOADING))
  1881. {
  1882. return false;
  1883. }
  1884. if (PEAR :: isError($e = $this->_lock(LOCK_EX)))
  1885. {
  1886. return $e;
  1887. }
  1888. $ret = $this->_updatePackage2($info);
  1889. $this->_unlock();
  1890. if ($ret)
  1891. {
  1892. $this->_dependencyDB->uninstallPackage($info);
  1893. $this->_dependencyDB->installPackage($info);
  1894. }
  1895. return $ret;
  1896. }
  1897. // }}}
  1898. // {{{ getChannel()
  1899. /**
  1900. * @param string channel name
  1901. * @param bool whether to strictly return raw channels (no aliases)
  1902. * @return PEAR_ChannelFile|PEAR_Error
  1903. */
  1904. function &getChannel($channel, $noaliases = false)
  1905. {
  1906. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1907. {
  1908. return $e;
  1909. }
  1910. $ret = &$this->_getChannel($channel, $noaliases);
  1911. $this->_unlock();
  1912. if (! $ret)
  1913. {
  1914. return PEAR :: raiseError('Unknown channel: ' . $channel);
  1915. }
  1916. return $ret;
  1917. }
  1918. // }}}
  1919. // {{{ getPackage()
  1920. /**
  1921. * @param string package name
  1922. * @param string channel name
  1923. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  1924. */
  1925. function &getPackage($package, $channel = 'pear.php.net')
  1926. {
  1927. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  1928. {
  1929. return $e;
  1930. }
  1931. $pf = &$this->_getPackage($package, $channel);
  1932. $this->_unlock();
  1933. return $pf;
  1934. }
  1935. // }}}
  1936. /**
  1937. * Get PEAR_PackageFile_v[1/2] objects representing the contents of
  1938. * a dependency group that are installed.
  1939. *
  1940. * This is used at uninstall-time
  1941. * @param array
  1942. * @return array|false
  1943. */
  1944. function getInstalledGroup($group)
  1945. {
  1946. $ret = array();
  1947. if (isset($group['package']))
  1948. {
  1949. if (! isset($group['package'][0]))
  1950. {
  1951. $group['package'] = array($group['package']);
  1952. }
  1953. foreach ($group['package'] as $package)
  1954. {
  1955. $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
  1956. $p = &$this->getPackage($package['name'], $depchannel);
  1957. if ($p)
  1958. {
  1959. $save = &$p;
  1960. $ret[] = &$save;
  1961. }
  1962. }
  1963. }
  1964. if (isset($group['subpackage']))
  1965. {
  1966. if (! isset($group['subpackage'][0]))
  1967. {
  1968. $group['subpackage'] = array($group['subpackage']);
  1969. }
  1970. foreach ($group['subpackage'] as $package)
  1971. {
  1972. $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
  1973. $p = &$this->getPackage($package['name'], $depchannel);
  1974. if ($p)
  1975. {
  1976. $save = &$p;
  1977. $ret[] = &$save;
  1978. }
  1979. }
  1980. }
  1981. if (! count($ret))
  1982. {
  1983. return false;
  1984. }
  1985. return $ret;
  1986. }
  1987. // {{{ getChannelValidator()
  1988. /**
  1989. * @param string channel name
  1990. * @return PEAR_Validate|false
  1991. */
  1992. function &getChannelValidator($channel)
  1993. {
  1994. $chan = $this->getChannel($channel);
  1995. if (PEAR :: isError($chan))
  1996. {
  1997. return $chan;
  1998. }
  1999. $val = $chan->getValidationObject();
  2000. return $val;
  2001. }
  2002. // }}}
  2003. // {{{ getChannels()
  2004. /**
  2005. * @param string channel name
  2006. * @return array an array of PEAR_ChannelFile objects representing every installed channel
  2007. */
  2008. function &getChannels()
  2009. {
  2010. $ret = array();
  2011. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  2012. {
  2013. return $e;
  2014. }
  2015. foreach ($this->_listChannels() as $channel)
  2016. {
  2017. $e = &$this->_getChannel($channel);
  2018. if (! $e || PEAR :: isError($e))
  2019. {
  2020. continue;
  2021. }
  2022. $ret[] = $e;
  2023. }
  2024. $this->_unlock();
  2025. return $ret;
  2026. }
  2027. // }}}
  2028. // {{{ checkFileMap()
  2029. /**
  2030. * Test whether a file or set of files belongs to a package.
  2031. *
  2032. * If an array is passed in
  2033. * @param string|array file path, absolute or relative to the pear
  2034. * install dir
  2035. * @param string|array name of PEAR package or array('package' => name, 'channel' =>
  2036. * channel) of a package that will be ignored
  2037. * @param string API version - 1.1 will exclude any files belonging to a package
  2038. * @param array private recursion variable
  2039. * @return array|false which package and channel the file belongs to, or an empty
  2040. * string if the file does not belong to an installed package,
  2041. * or belongs to the second parameter's package
  2042. */
  2043. function checkFileMap($path, $package = false, $api = '1.0', $attrs = false)
  2044. {
  2045. if (is_array($path))
  2046. {
  2047. static $notempty;
  2048. if (empty($notempty))
  2049. {
  2050. if (! class_exists('PEAR_Installer_Role'))
  2051. {
  2052. require_once 'PEAR/Installer/Role.php';
  2053. }
  2054. $notempty = create_function('$a', 'return !empty($a);');
  2055. }
  2056. $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) : strtolower($package);
  2057. $pkgs = array();
  2058. foreach ($path as $name => $attrs)
  2059. {
  2060. if (is_array($attrs))
  2061. {
  2062. if (isset($attrs['install-as']))
  2063. {
  2064. $name = $attrs['install-as'];
  2065. }
  2066. if (! in_array($attrs['role'], PEAR_Installer_Role :: getInstallableRoles()))
  2067. {
  2068. // these are not installed
  2069. continue;
  2070. }
  2071. if (! in_array($attrs['role'], PEAR_Installer_Role :: getBaseinstallRoles()))
  2072. {
  2073. $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;
  2074. }
  2075. if (isset($attrs['baseinstalldir']))
  2076. {
  2077. $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
  2078. }
  2079. }
  2080. $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);
  2081. if (PEAR :: isError($pkgs[$name]))
  2082. {
  2083. return $pkgs[$name];
  2084. }
  2085. }
  2086. return array_filter($pkgs, $notempty);
  2087. }
  2088. if (empty($this->filemap_cache))
  2089. {
  2090. if (PEAR :: isError($e = $this->_lock(LOCK_SH)))
  2091. {
  2092. return $e;
  2093. }
  2094. $err = $this->_readFileMap();
  2095. $this->_unlock();
  2096. if (PEAR :: isError($err))
  2097. {
  2098. return $err;
  2099. }
  2100. }
  2101. if (! $attrs)
  2102. {
  2103. $attrs = array('role' => 'php'); // any old call would be for PHP role only
  2104. }
  2105. if (isset($this->filemap_cache[$attrs['role']][$path]))
  2106. {
  2107. if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package)
  2108. {
  2109. return false;
  2110. }
  2111. return $this->filemap_cache[$attrs['role']][$path];
  2112. }
  2113. $l = strlen($this->install_dir);
  2114. if (substr($path, 0, $l) == $this->install_dir)
  2115. {
  2116. $path = preg_replace('!^' . DIRECTORY_SEPARATOR . '+!', '', substr($path, $l));
  2117. }
  2118. if (isset($this->filemap_cache[$attrs['role']][$path]))
  2119. {
  2120. if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package)
  2121. {
  2122. return false;
  2123. }
  2124. return $this->filemap_cache[$attrs['role']][$path];
  2125. }
  2126. return false;
  2127. }
  2128. // }}}
  2129. // {{{ flush()
  2130. /**
  2131. * Force a reload of the filemap
  2132. * @since 1.5.0RC3
  2133. */
  2134. function flushFileMap()
  2135. {
  2136. $this->filemap_cache = null;
  2137. clearstatcache(); // ensure that the next read gets the full, current filemap
  2138. }
  2139. // }}}
  2140. // {{{ apiVersion()
  2141. /**
  2142. * Get the expected API version. Channels API is version 1.1, as it is backwards
  2143. * compatible with 1.0
  2144. * @return string
  2145. */
  2146. function apiVersion()
  2147. {
  2148. return '1.1';
  2149. }
  2150. // }}}
  2151. /**
  2152. * Parse a package name, or validate a parsed package name array
  2153. * @param string|array pass in an array of format
  2154. * array(
  2155. * 'package' => 'pname',
  2156. * ['channel' => 'channame',]
  2157. * ['version' => 'version',]
  2158. * ['state' => 'state',]
  2159. * ['group' => 'groupname'])
  2160. * or a string of format
  2161. * [channel://][channame/]pname[-version|-state][/group=groupname]
  2162. * @return array|PEAR_Error
  2163. */
  2164. function parsePackageName($param, $defaultchannel = 'pear.php.net')
  2165. {
  2166. $saveparam = $param;
  2167. if (is_array($param))
  2168. {
  2169. // convert to string for error messages
  2170. $saveparam = $this->parsedPackageNameToString($param);
  2171. // process the array
  2172. if (! isset($param['package']))
  2173. {
  2174. return PEAR :: raiseError('parsePackageName(): array $param ' . 'must contain a valid package name in index "param"', 'package', null, null, $param);
  2175. }
  2176. if (! isset($param['uri']))
  2177. {
  2178. if (! isset($param['channel']))
  2179. {
  2180. $param['channel'] = $defaultchannel;
  2181. }
  2182. }
  2183. else
  2184. {
  2185. $param['channel'] = '__uri';
  2186. }
  2187. }
  2188. else
  2189. {
  2190. $components = @parse_url((string) $param);
  2191. if (isset($components['scheme']))
  2192. {
  2193. if ($components['scheme'] == 'http')
  2194. {
  2195. // uri package
  2196. $param = array('uri' => $param, 'channel' => '__uri');
  2197. }
  2198. elseif ($components['scheme'] != 'channel')
  2199. {
  2200. return PEAR :: raiseError('parsePackageName(): only channel:// uris may ' . 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);
  2201. }
  2202. }
  2203. if (! isset($components['path']))
  2204. {
  2205. return PEAR :: raiseError('parsePackageName(): array $param ' . 'must contain a valid package name in "' . $param . '"', 'package', null, null, $param);
  2206. }
  2207. if (isset($components['host']))
  2208. {
  2209. // remove the leading "/"
  2210. $components['path'] = substr($components['path'], 1);
  2211. }
  2212. if (! isset($components['scheme']))
  2213. {
  2214. if (strpos($components['path'], '/') !== false)
  2215. {
  2216. if ($components['path']{0} == '/')
  2217. {
  2218. return PEAR :: raiseError('parsePackageName(): this is not ' . 'a package name, it begins with "/" in "' . $param . '"', 'invalid', null, null, $param);
  2219. }
  2220. $parts = explode('/', $components['path']);
  2221. $components['host'] = array_shift($parts);
  2222. if (count($parts) > 1)
  2223. {
  2224. $components['path'] = array_pop($parts);
  2225. $components['host'] .= '/' . implode('/', $parts);
  2226. }
  2227. else
  2228. {
  2229. $components['path'] = implode('/', $parts);
  2230. }
  2231. }
  2232. else
  2233. {
  2234. $components['host'] = $defaultchannel;
  2235. }
  2236. }
  2237. else
  2238. {
  2239. if (strpos($components['path'], '/'))
  2240. {
  2241. $parts = explode('/', $components['path']);
  2242. $components['path'] = array_pop($parts);
  2243. $components['host'] .= '/' . implode('/', $parts);
  2244. }
  2245. }
  2246. if (is_array($param))
  2247. {
  2248. $param['package'] = $components['path'];
  2249. }
  2250. else
  2251. {
  2252. $param = array('package' => $components['path']);
  2253. if (isset($components['host']))
  2254. {
  2255. $param['channel'] = $components['host'];
  2256. }
  2257. }
  2258. if (isset($components['fragment']))
  2259. {
  2260. $param['group'] = $components['fragment'];
  2261. }
  2262. if (isset($components['user']))
  2263. {
  2264. $param['user'] = $components['user'];
  2265. }
  2266. if (isset($components['pass']))
  2267. {
  2268. $param['pass'] = $components['pass'];
  2269. }
  2270. if (isset($components['query']))
  2271. {
  2272. parse_str($components['query'], $param['opts']);
  2273. }
  2274. // check for extension
  2275. $pathinfo = pathinfo($param['package']);
  2276. if (isset($pathinfo['extension']) && in_array(strtolower($pathinfo['extension']), array('tgz', 'tar')))
  2277. {
  2278. $param['extension'] = $pathinfo['extension'];
  2279. $param['package'] = substr($pathinfo['basename'], 0, strlen($pathinfo['basename']) - 4);
  2280. }
  2281. // check for version
  2282. if (strpos($param['package'], '-'))
  2283. {
  2284. $test = explode('-', $param['package']);
  2285. if (count($test) != 2)
  2286. {
  2287. return PEAR :: raiseError('parsePackageName(): only one version/state ' . 'delimiter "-" is allowed in "' . $saveparam . '"', 'version', null, null, $param);
  2288. }
  2289. list($param['package'], $param['version']) = $test;
  2290. }
  2291. }
  2292. // validation
  2293. $info = $this->channelExists($param['channel']);
  2294. if (PEAR :: isError($info))
  2295. {
  2296. return $info;
  2297. }
  2298. if (! $info)
  2299. {
  2300. return PEAR :: raiseError('unknown channel "' . $param['channel'] . '" in "' . $saveparam . '"', 'channel', null, null, $param);
  2301. }
  2302. $chan = $this->getChannel($param['channel']);
  2303. if (PEAR :: isError($chan))
  2304. {
  2305. return $chan;
  2306. }
  2307. if (! $chan)
  2308. {
  2309. return PEAR :: raiseError("Exception: corrupt registry, could not " . "retrieve channel " . $param['channel'] . " information", 'registry', null, null, $param);
  2310. }
  2311. $param['channel'] = $chan->getName();
  2312. $validate = $chan->getValidationObject();
  2313. $vpackage = $chan->getValidationPackage();
  2314. // validate package name
  2315. if (! $validate->validPackageName($param['package'], $vpackage['_content']))
  2316. {
  2317. return PEAR :: raiseError('parsePackageName(): invalid package name "' . $param['package'] . '" in "' . $saveparam . '"', 'package', null, null, $param);
  2318. }
  2319. if (isset($param['group']))
  2320. {
  2321. if (! PEAR_Validate :: validGroupName($param['group']))
  2322. {
  2323. return PEAR :: raiseError('parsePackageName(): dependency group "' . $param['group'] . '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, $param);
  2324. }
  2325. }
  2326. if (isset($param['state']))
  2327. {
  2328. if (! in_array(strtolower($param['state']), $validate->getValidStates()))
  2329. {
  2330. return PEAR :: raiseError('parsePackageName(): state "' . $param['state'] . '" is not a valid state in "' . $saveparam . '"', 'state', null, null, $param);
  2331. }
  2332. }
  2333. if (isset($param['version']))
  2334. {
  2335. if (isset($param['state']))
  2336. {
  2337. return PEAR :: raiseError('parsePackageName(): cannot contain both ' . 'a version and a stability (state) in "' . $saveparam . '"', 'version/state', null, null, $param);
  2338. }
  2339. // check whether version is actually a state
  2340. if (in_array(strtolower($param['version']), $validate->getValidStates()))
  2341. {
  2342. $param['state'] = strtolower($param['version']);
  2343. unset($param['version']);
  2344. }
  2345. else
  2346. {
  2347. if (! $validate->validVersion($param['version']))
  2348. {
  2349. return PEAR :: raiseError('parsePackageName(): "' . $param['version'] . '" is neither a valid version nor a valid state in "' . $saveparam . '"', 'version/state', null, null, $param);
  2350. }
  2351. }
  2352. }
  2353. return $param;
  2354. }
  2355. /**
  2356. * @param array
  2357. * @return string
  2358. */
  2359. function parsedPackageNameToString($parsed, $brief = false)
  2360. {
  2361. if (is_string($parsed))
  2362. {
  2363. return $parsed;
  2364. }
  2365. if (is_object($parsed))
  2366. {
  2367. $p = $parsed;
  2368. $parsed = array('package' => $p->getPackage(), 'channel' => $p->getChannel(), 'version' => $p->getVersion());
  2369. }
  2370. if (isset($parsed['uri']))
  2371. {
  2372. return $parsed['uri'];
  2373. }
  2374. if ($brief)
  2375. {
  2376. if ($channel = $this->channelAlias($parsed['channel']))
  2377. {
  2378. return $channel . '/' . $parsed['package'];
  2379. }
  2380. }
  2381. $upass = '';
  2382. if (isset($parsed['user']))
  2383. {
  2384. $upass = $parsed['user'];
  2385. if (isset($parsed['pass']))
  2386. {
  2387. $upass .= ':' . $parsed['pass'];
  2388. }
  2389. $upass = "$upass@";
  2390. }
  2391. $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];
  2392. if (isset($parsed['version']) || isset($parsed['state']))
  2393. {
  2394. $ver = isset($parsed['version']) ? $parsed['version'] : '';
  2395. $ver .= isset($parsed['state']) ? $parsed['state'] : '';
  2396. $ret .= '-' . $ver;
  2397. }
  2398. if (isset($parsed['extension']))
  2399. {
  2400. $ret .= '.' . $parsed['extension'];
  2401. }
  2402. if (isset($parsed['opts']))
  2403. {
  2404. $ret .= '?';
  2405. foreach ($parsed['opts'] as $name => $value)
  2406. {
  2407. $parsed['opts'][$name] = "$name=$value";
  2408. }
  2409. $ret .= implode('&', $parsed['opts']);
  2410. }
  2411. if (isset($parsed['group']))
  2412. {
  2413. $ret .= '#' . $parsed['group'];
  2414. }
  2415. return $ret;
  2416. }
  2417. }