PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/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

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

  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

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