PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/php/PEAR/Registry.php

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