Bearsampp 2026.9.23
Loading...
Searching...
No Matches
Registry.php
Go to the documentation of this file.
1<?php
17
21require_once 'PEAR.php';
22require_once 'PEAR/DependencyDB.php';
23
24define('PEAR_REGISTRY_ERROR_LOCK', -2);
25define('PEAR_REGISTRY_ERROR_FORMAT', -3);
26define('PEAR_REGISTRY_ERROR_FILE', -4);
27define('PEAR_REGISTRY_ERROR_CONFLICT', -5);
28define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6);
29
43class PEAR_Registry extends PEAR
44{
49 var $channels = '';
50
54 var $statedir = '';
55
59 var $filemap = '';
60
64 var $channelsdir = '';
65
69 var $lockfile = '';
70
74 var $lock_fp = null;
75
79 var $lock_mode = 0; // XXX UNUSED
80
87 var $pkginfo_cache = array();
88
93 var $filemap_cache = array();
94
99
104
109
114
119
133 function __construct($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,
134 $pecl_channel = false, $pear_metadata_dir = '')
135 {
136 parent::__construct();
137 $this->setInstallDir($pear_install_dir, $pear_metadata_dir);
138 $this->_pearChannel = $pear_channel;
139 $this->_peclChannel = $pecl_channel;
140 $this->_config = false;
141 }
142
143 function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR, $pear_metadata_dir = '')
144 {
145 $ds = DIRECTORY_SEPARATOR;
146 $this->install_dir = $pear_install_dir;
147 if (!$pear_metadata_dir) {
148 $pear_metadata_dir = $pear_install_dir;
149 }
150 $this->channelsdir = $pear_metadata_dir.$ds.'.channels';
151 $this->statedir = $pear_metadata_dir.$ds.'.registry';
152 $this->filemap = $pear_metadata_dir.$ds.'.filemap';
153 $this->lockfile = $pear_metadata_dir.$ds.'.lock';
154 }
155
156 function hasWriteAccess()
157 {
158 if (!file_exists($this->install_dir)) {
159 $dir = $this->install_dir;
160 while ($dir && $dir != '.') {
161 $olddir = $dir;
162 $dir = dirname($dir);
163 if ($dir != '.' && file_exists($dir)) {
164 if (is_writeable($dir)) {
165 return true;
166 }
167
168 return false;
169 }
170
171 if ($dir == $olddir) { // this can happen in safe mode
172 return @is_writable($dir);
173 }
174 }
175
176 return false;
177 }
178
179 return is_writeable($this->install_dir);
180 }
181
182 function setConfig(&$config, $resetInstallDir = true)
183 {
184 $this->_config = &$config;
185 if ($resetInstallDir) {
186 $this->setInstallDir($config->get('php_dir'), $config->get('metadata_dir'));
187 }
188 }
189
191 {
192 static $running = false;
193 if (!$running) {
194 $running = true;
195 $ds = DIRECTORY_SEPARATOR;
196 if (!is_dir($this->channelsdir) ||
197 !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
198 !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
199 !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
200 !file_exists($this->channelsdir . $ds . '__uri.reg')) {
201 if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
202 $pear_channel = $this->_pearChannel;
203 if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) {
204 if (!class_exists('PEAR_ChannelFile')) {
205 require_once 'PEAR/ChannelFile.php';
206 }
207
208 $pear_channel = new PEAR_ChannelFile;
209 $pear_channel->setAlias('pear');
210 $pear_channel->setServer('pear.php.net');
211 $pear_channel->setSummary('PHP Extension and Application Repository');
212 $pear_channel->setDefaultPEARProtocols();
213 $pear_channel->setBaseURL('REST1.0', 'https://pear.php.net/rest/');
214 $pear_channel->setBaseURL('REST1.1', 'https://pear.php.net/rest/');
215 $pear_channel->setBaseURL('REST1.3', 'https://pear.php.net/rest/');
216 //$pear_channel->setBaseURL('REST1.4', 'https://pear.php.net/rest/');
217 } else {
218 $pear_channel->setServer('pear.php.net');
219 $pear_channel->setAlias('pear');
220 }
221
222 $pear_channel->validate();
223 $this->_addChannel($pear_channel);
224 }
225
226 if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) {
227 $pecl_channel = $this->_peclChannel;
228 if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) {
229 if (!class_exists('PEAR_ChannelFile')) {
230 require_once 'PEAR/ChannelFile.php';
231 }
232
233 $pecl_channel = new PEAR_ChannelFile;
234 $pecl_channel->setAlias('pecl');
235 $pecl_channel->setServer('pecl.php.net');
236 $pecl_channel->setSummary('PHP Extension Community Library');
237 $pecl_channel->setDefaultPEARProtocols();
238 $pecl_channel->setBaseURL('REST1.0', 'https://pecl.php.net/rest/');
239 $pecl_channel->setBaseURL('REST1.1', 'https://pecl.php.net/rest/');
240 $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
241 } else {
242 $pecl_channel->setServer('pecl.php.net');
243 $pecl_channel->setAlias('pecl');
244 }
245
246 $pecl_channel->validate();
247 $this->_addChannel($pecl_channel);
248 }
249
250 if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) {
251 $doc_channel = $this->_docChannel;
252 if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) {
253 if (!class_exists('PEAR_ChannelFile')) {
254 require_once 'PEAR/ChannelFile.php';
255 }
256
257 $doc_channel = new PEAR_ChannelFile;
258 $doc_channel->setAlias('phpdocs');
259 $doc_channel->setServer('doc.php.net');
260 $doc_channel->setSummary('PHP Documentation Team');
261 $doc_channel->setDefaultPEARProtocols();
262 $doc_channel->setBaseURL('REST1.0', 'https://doc.php.net/rest/');
263 $doc_channel->setBaseURL('REST1.1', 'https://doc.php.net/rest/');
264 $doc_channel->setBaseURL('REST1.3', 'https://doc.php.net/rest/');
265 } else {
266 $doc_channel->setServer('doc.php.net');
267 $doc_channel->setAlias('doc');
268 }
269
270 $doc_channel->validate();
271 $this->_addChannel($doc_channel);
272 }
273
274 if (!file_exists($this->channelsdir . $ds . '__uri.reg')) {
275 if (!class_exists('PEAR_ChannelFile')) {
276 require_once 'PEAR/ChannelFile.php';
277 }
278
279 $private = new PEAR_ChannelFile;
280 $private->setName('__uri');
281 $private->setDefaultPEARProtocols();
282 $private->setBaseURL('REST1.0', '****');
283 $private->setSummary('Pseudo-channel for static packages');
284 $this->_addChannel($private);
285 }
286 $this->_rebuildFileMap();
287 }
288
289 $running = false;
290 }
291 }
292
294 {
295 $ds = DIRECTORY_SEPARATOR;
296 // XXX Compatibility code should be removed in the future
297 // rename all registry files if any to lowercase
298 if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) &&
299 $handle = opendir($this->statedir)) {
300 $dest = $this->statedir . $ds;
301 while (false !== ($file = readdir($handle))) {
302 if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) {
303 rename($dest . $file, $dest . strtolower($file));
304 }
305 }
306 closedir($handle);
307 }
308
309 $this->_initializeChannelDirs();
310 if (!file_exists($this->filemap)) {
311 $this->_rebuildFileMap();
312 }
313 $this->_initializeDepDB();
314 }
315
317 {
318 if (!isset($this->_dependencyDB)) {
319 static $initializing = false;
320 if (!$initializing) {
321 $initializing = true;
322 if (!$this->_config) { // never used?
323 $file = OS_WINDOWS ? 'pear.ini' : '.pearrc';
324 $this->_config = new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .
325 $file);
326 $this->_config->setRegistry($this);
327 $this->_config->set('php_dir', $this->install_dir);
328 }
329
330 $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
331 if (PEAR::isError($this->_dependencyDB)) {
332 // attempt to recover by removing the dep db
333 if (file_exists($this->_config->get('metadata_dir', null, 'pear.php.net') .
334 DIRECTORY_SEPARATOR . '.depdb')) {
335 @unlink($this->_config->get('metadata_dir', null, 'pear.php.net') .
336 DIRECTORY_SEPARATOR . '.depdb');
337 }
338
339 $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
340 if (PEAR::isError($this->_dependencyDB)) {
341 echo $this->_dependencyDB->getMessage();
342 echo 'Unrecoverable error';
343 exit(1);
344 }
345 }
346
347 $initializing = false;
348 }
349 }
350 }
351
357 function _PEAR_Registry()
358 {
359 parent::_PEAR();
360 if (is_resource($this->lock_fp)) {
361 $this->_unlock();
362 }
363 }
364
373 function _assertStateDir($channel = false)
374 {
375 if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
376 return $this->_assertChannelStateDir($channel);
377 }
378
379 static $init = false;
380 if (!file_exists($this->statedir)) {
381 if (!$this->hasWriteAccess()) {
382 return false;
383 }
384
385 require_once 'System.php';
386 if (!System::mkdir(array('-p', $this->statedir))) {
387 return $this->raiseError("could not create directory '{$this->statedir}'");
388 }
389 $init = true;
390 } elseif (!is_dir($this->statedir)) {
391 return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' .
392 'it already exists and is not a directory');
393 }
394
395 $ds = DIRECTORY_SEPARATOR;
396 if (!file_exists($this->channelsdir)) {
397 if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
398 !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
399 !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
400 !file_exists($this->channelsdir . $ds . '__uri.reg')) {
401 $init = true;
402 }
403 } elseif (!is_dir($this->channelsdir)) {
404 return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' .
405 'it already exists and is not a directory');
406 }
407
408 if ($init) {
409 static $running = false;
410 if (!$running) {
411 $running = true;
412 $this->_initializeDirs();
413 $running = false;
414 $init = false;
415 }
416 } else {
417 $this->_initializeDepDB();
418 }
419
420 return true;
421 }
422
432 function _assertChannelStateDir($channel)
433 {
434 $ds = DIRECTORY_SEPARATOR;
435 if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
436 if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
437 $this->_initializeChannelDirs();
438 }
439 return $this->_assertStateDir($channel);
440 }
441
442 $channelDir = $this->_channelDirectoryName($channel);
443 if (!is_dir($this->channelsdir) ||
444 !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
445 $this->_initializeChannelDirs();
446 }
447
448 if (!file_exists($channelDir)) {
449 if (!$this->hasWriteAccess()) {
450 return false;
451 }
452
453 require_once 'System.php';
454 if (!System::mkdir(array('-p', $channelDir))) {
455 return $this->raiseError("could not create directory '" . $channelDir .
456 "'");
457 }
458 } elseif (!is_dir($channelDir)) {
459 return $this->raiseError("could not create directory '" . $channelDir .
460 "', already exists and is not a directory");
461 }
462
463 return true;
464 }
465
475 {
476 if (!file_exists($this->channelsdir)) {
477 if (!$this->hasWriteAccess()) {
478 return false;
479 }
480
481 require_once 'System.php';
482 if (!System::mkdir(array('-p', $this->channelsdir))) {
483 return $this->raiseError("could not create directory '{$this->channelsdir}'");
484 }
485 } elseif (!is_dir($this->channelsdir)) {
486 return $this->raiseError("could not create directory '{$this->channelsdir}" .
487 "', it already exists and is not a directory");
488 }
489
490 if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
491 if (!$this->hasWriteAccess()) {
492 return false;
493 }
494
495 require_once 'System.php';
496 if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {
497 return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
498 }
499 } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
500 return $this->raiseError("could not create directory '{$this->channelsdir}" .
501 "/.alias', it already exists and is not a directory");
502 }
503
504 return true;
505 }
506
517 function _packageFileName($package, $channel = false)
518 {
519 if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
520 return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR .
521 strtolower($package) . '.reg';
522 }
523
524 return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
525 }
526
532 function _channelFileName($channel, $noaliases = false)
533 {
534 if (!$noaliases) {
535 if (file_exists($this->_getChannelAliasFileName($channel))) {
536 $channel = implode('', file($this->_getChannelAliasFileName($channel)));
537 }
538 }
539 return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_',
540 strtolower($channel)) . '.reg';
541 }
542
548 {
549 return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .
550 DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';
551 }
552
556 function _getChannelFromAlias($channel)
557 {
558 if (!$this->_channelExists($channel)) {
559 if ($channel == 'pear.php.net') {
560 return 'pear.php.net';
561 }
562
563 if ($channel == 'pecl.php.net') {
564 return 'pecl.php.net';
565 }
566
567 if ($channel == 'doc.php.net') {
568 return 'doc.php.net';
569 }
570
571 if ($channel == '__uri') {
572 return '__uri';
573 }
574
575 return false;
576 }
577
578 $channel = strtolower($channel);
579 if (file_exists($this->_getChannelAliasFileName($channel))) {
580 // translate an alias to an actual channel
581 return implode('', file($this->_getChannelAliasFileName($channel)));
582 }
583
584 return $channel;
585 }
586
590 function _getAlias($channel)
591 {
592 if (!$this->_channelExists($channel)) {
593 if ($channel == 'pear.php.net') {
594 return 'pear';
595 }
596
597 if ($channel == 'pecl.php.net') {
598 return 'pecl';
599 }
600
601 if ($channel == 'doc.php.net') {
602 return 'phpdocs';
603 }
604
605 return false;
606 }
607
608 $channel = $this->_getChannel($channel);
609 if (PEAR::isError($channel)) {
610 return $channel;
611 }
612
613 return $channel->getAlias();
614 }
615
626 function _channelDirectoryName($channel)
627 {
628 if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
629 return $this->statedir;
630 }
631
632 $ch = $this->_getChannelFromAlias($channel);
633 if (!$ch) {
634 $ch = $channel;
635 }
636
637 return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .
638 str_replace('/', '_', $ch));
639 }
640
641 function _openPackageFile($package, $mode, $channel = false)
642 {
643 if (!$this->_assertStateDir($channel)) {
644 return null;
645 }
646
647 if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
648 return null;
649 }
650
651 $file = $this->_packageFileName($package, $channel);
652 if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
653 return null;
654 }
655
656 $fp = @fopen($file, $mode);
657 if (!$fp) {
658 return null;
659 }
660
661 return $fp;
662 }
663
664 function _closePackageFile($fp)
665 {
666 fclose($fp);
667 }
668
669 function _openChannelFile($channel, $mode)
670 {
671 if (!$this->_assertChannelDir()) {
672 return null;
673 }
674
675 if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
676 return null;
677 }
678
679 $file = $this->_channelFileName($channel);
680 if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
681 return null;
682 }
683
684 $fp = @fopen($file, $mode);
685 if (!$fp) {
686 return null;
687 }
688
689 return $fp;
690 }
691
692 function _closeChannelFile($fp)
693 {
694 fclose($fp);
695 }
696
698 {
699 if (!class_exists('PEAR_Installer_Role')) {
700 require_once 'PEAR/Installer/Role.php';
701 }
702
703 $channels = $this->_listAllPackages();
704 $files = array();
705 foreach ($channels as $channel => $packages) {
706 foreach ($packages as $package) {
707 $version = $this->_packageInfo($package, 'version', $channel);
708 $filelist = $this->_packageInfo($package, 'filelist', $channel);
709 if (!is_array($filelist)) {
710 continue;
711 }
712
713 foreach ($filelist as $name => $attrs) {
714 if (isset($attrs['attribs'])) {
715 $attrs = $attrs['attribs'];
716 }
717
718 // it is possible for conflicting packages in different channels to
719 // conflict with data files/doc files
720 if ($name == 'dirtree') {
721 continue;
722 }
723
724 if (isset($attrs['role']) && !in_array($attrs['role'],
726 // these are not installed
727 continue;
728 }
729
730 if (isset($attrs['role']) && !in_array($attrs['role'],
732 $attrs['baseinstalldir'] = $package;
733 }
734
735 if (isset($attrs['baseinstalldir'])) {
736 $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
737 } else {
738 $file = $name;
739 }
740
741 $file = preg_replace(',^/+,', '', $file);
742 if ($channel != 'pear.php.net') {
743 if (!isset($files[$attrs['role']])) {
744 $files[$attrs['role']] = array();
745 }
746 $files[$attrs['role']][$file] = array(strtolower($channel),
747 strtolower($package));
748 } else {
749 if (!isset($files[$attrs['role']])) {
750 $files[$attrs['role']] = array();
751 }
752 $files[$attrs['role']][$file] = strtolower($package);
753 }
754 }
755 }
756 }
757
758
759 $this->_assertStateDir();
760 if (!$this->hasWriteAccess()) {
761 return false;
762 }
763
764 $fp = @fopen($this->filemap, 'wb');
765 if (!$fp) {
766 return false;
767 }
768
769 $this->filemap_cache = $files;
770 fwrite($fp, serialize($files));
771 fclose($fp);
772 return true;
773 }
774
775 function _readFileMap()
776 {
777 if (!file_exists($this->filemap)) {
778 return array();
779 }
780
781 $fp = @fopen($this->filemap, 'r');
782 if (!$fp) {
783 $last_errormsg = '';
784 $last_error = error_get_last();
785 if (!empty($last_error['message'])) {
786 $last_errormsg = $last_error['message'];
787 }
788 return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $last_errormsg);
789 }
790
791 clearstatcache();
792 $fsize = filesize($this->filemap);
793 fclose($fp);
794 $data = file_get_contents($this->filemap);
795 $tmp = unserialize($data);
796 if (!$tmp && $fsize > 7) {
797 return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
798 }
799
800 $this->filemap_cache = $tmp;
801 return true;
802 }
803
816 function _lock($mode = LOCK_EX)
817 {
818 if (stristr(php_uname(), 'Windows 9')) {
819 return true;
820 }
821
822 if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
823 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
824 return true;
825 }
826
827 if (!$this->_assertStateDir()) {
828 if ($mode == LOCK_EX) {
829 return $this->raiseError('Registry directory is not writeable by the current user');
830 }
831
832 return true;
833 }
834
835 $open_mode = 'w';
836 // XXX People reported problems with LOCK_SH and 'w'
837 if ($mode === LOCK_SH || $mode === LOCK_UN) {
838 if (!file_exists($this->lockfile)) {
839 touch($this->lockfile);
840 }
841 $open_mode = 'r';
842 }
843
844 if (!is_resource($this->lock_fp)) {
845 $this->lock_fp = @fopen($this->lockfile, $open_mode);
846 }
847
848 if (!is_resource($this->lock_fp)) {
849 $this->lock_fp = null;
850 return $this->raiseError("could not create lock file" .
851 (isset($php_errormsg) ? ": " . $php_errormsg : ""));
852 }
853
854 if (!(int)flock($this->lock_fp, $mode)) {
855 switch ($mode) {
856 case LOCK_SH: $str = 'shared'; break;
857 case LOCK_EX: $str = 'exclusive'; break;
858 case LOCK_UN: $str = 'unlock'; break;
859 default: $str = 'unknown'; break;
860 }
861
862 //is resource at this point, close it on error.
863 fclose($this->lock_fp);
864 $this->lock_fp = null;
865 return $this->raiseError("could not acquire $str lock ($this->lockfile)",
867 }
868
869 return true;
870 }
871
872 function _unlock()
873 {
874 $ret = $this->_lock(LOCK_UN);
875 if (is_resource($this->lock_fp)) {
876 fclose($this->lock_fp);
877 }
878
879 $this->lock_fp = null;
880 return $ret;
881 }
882
883 function _packageExists($package, $channel = false)
884 {
885 return file_exists($this->_packageFileName($package, $channel));
886 }
887
895 function _channelExists($channel, $noaliases = false)
896 {
897 $a = file_exists($this->_channelFileName($channel, $noaliases));
898 if (!$a && $channel == 'pear.php.net') {
899 return true;
900 }
901
902 if (!$a && $channel == 'pecl.php.net') {
903 return true;
904 }
905
906 if (!$a && $channel == 'doc.php.net') {
907 return true;
908 }
909
910 return $a;
911 }
912
921 function _mirrorExists($channel, $mirror)
922 {
923 $data = $this->_channelInfo($channel);
924 if (!isset($data['servers']['mirror'])) {
925 return false;
926 }
927
928 foreach ($data['servers']['mirror'] as $m) {
929 if ($m['attribs']['host'] == $mirror) {
930 return true;
931 }
932 }
933
934 return false;
935 }
936
943 function _addChannel($channel, $update = false, $lastmodified = false)
944 {
945 if (!is_a($channel, 'PEAR_ChannelFile')) {
946 return false;
947 }
948
949 if (!$channel->validate()) {
950 return false;
951 }
952
953 if (file_exists($this->_channelFileName($channel->getName()))) {
954 if (!$update) {
955 return false;
956 }
957
958 $checker = $this->_getChannel($channel->getName());
959 if (PEAR::isError($checker)) {
960 return $checker;
961 }
962
963 if ($channel->getAlias() != $checker->getAlias()) {
964 if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) {
965 @unlink($this->_getChannelAliasFileName($checker->getAlias()));
966 }
967 }
968 } else {
969 if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) {
970 return false;
971 }
972 }
973
974 $ret = $this->_assertChannelDir();
975 if (PEAR::isError($ret)) {
976 return $ret;
977 }
978
979 $ret = $this->_assertChannelStateDir($channel->getName());
980 if (PEAR::isError($ret)) {
981 return $ret;
982 }
983
984 if ($channel->getAlias() != $channel->getName()) {
985 if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&
986 $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {
987 $channel->setAlias($channel->getName());
988 }
989
990 if (!$this->hasWriteAccess()) {
991 return false;
992 }
993
994 $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');
995 if (!$fp) {
996 return false;
997 }
998
999 fwrite($fp, $channel->getName());
1000 fclose($fp);
1001 }
1002
1003 if (!$this->hasWriteAccess()) {
1004 return false;
1005 }
1006
1007 $fp = @fopen($this->_channelFileName($channel->getName()), 'wb');
1008 if (!$fp) {
1009 return false;
1010 }
1011
1012 $info = $channel->toArray();
1013 if ($lastmodified) {
1014 $info['_lastmodified'] = $lastmodified;
1015 } else {
1016 $info['_lastmodified'] = self::getSourceDateEpoch();
1017 }
1018
1019 fwrite($fp, serialize($info));
1020 fclose($fp);
1021 return true;
1022 }
1023
1029 function _deleteChannel($channel)
1030 {
1031 if (!is_string($channel)) {
1032 if (!is_a($channel, 'PEAR_ChannelFile')) {
1033 return false;
1034 }
1035
1036 if (!$channel->validate()) {
1037 return false;
1038 }
1039 $channel = $channel->getName();
1040 }
1041
1042 if ($this->_getChannelFromAlias($channel) == '__uri') {
1043 return false;
1044 }
1045
1046 if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
1047 return false;
1048 }
1049
1050 if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
1051 return false;
1052 }
1053
1054 if (!$this->_channelExists($channel)) {
1055 return false;
1056 }
1057
1058 if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
1059 return false;
1060 }
1061
1062 $channel = $this->_getChannelFromAlias($channel);
1063 if ($channel == 'pear.php.net') {
1064 return false;
1065 }
1066
1067 $test = $this->_listChannelPackages($channel);
1068 if (count($test)) {
1069 return false;
1070 }
1071
1072 $test = @rmdir($this->_channelDirectoryName($channel));
1073 if (!$test) {
1074 return false;
1075 }
1076
1077 $file = $this->_getChannelAliasFileName($this->_getAlias($channel));
1078 if (file_exists($file)) {
1079 $test = @unlink($file);
1080 if (!$test) {
1081 return false;
1082 }
1083 }
1084
1085 $file = $this->_channelFileName($channel);
1086 $ret = true;
1087 if (file_exists($file)) {
1088 $ret = @unlink($file);
1089 }
1090
1091 return $ret;
1092 }
1093
1099 function _isChannelAlias($alias)
1100 {
1101 return file_exists($this->_getChannelAliasFileName($alias));
1102 }
1103
1111 function _packageInfo($package = null, $key = null, $channel = 'pear.php.net')
1112 {
1113 if ($package === null) {
1114 if ($channel === null) {
1115 $channels = $this->_listChannels();
1116 $ret = array();
1117 foreach ($channels as $channel) {
1118 $channel = strtolower($channel);
1119 $ret[$channel] = array();
1120 $packages = $this->_listPackages($channel);
1121 foreach ($packages as $package) {
1122 $ret[$channel][] = $this->_packageInfo($package, null, $channel);
1123 }
1124 }
1125
1126 return $ret;
1127 }
1128
1129 $ps = $this->_listPackages($channel);
1130 if (!count($ps)) {
1131 return array();
1132 }
1133 return array_map(array(&$this, '_packageInfo'),
1134 $ps, array_fill(0, count($ps), null),
1135 array_fill(0, count($ps), $channel));
1136 }
1137
1138 $fp = $this->_openPackageFile($package, 'r', $channel);
1139 if ($fp === null) {
1140 return null;
1141 }
1142
1143 clearstatcache();
1144 $this->_closePackageFile($fp);
1145 $data = file_get_contents($this->_packageFileName($package, $channel));
1146 $data = @unserialize($data);
1147 if ($key === null) {
1148 return $data;
1149 }
1150
1151 // compatibility for package.xml version 2.0
1152 if (isset($data['old'][$key])) {
1153 return $data['old'][$key];
1154 }
1155
1156 if (isset($data[$key])) {
1157 return $data[$key];
1158 }
1159
1160 return null;
1161 }
1162
1168 function _channelInfo($channel, $noaliases = false)
1169 {
1170 if (!$this->_channelExists($channel, $noaliases)) {
1171 return null;
1172 }
1173
1174 $fp = $this->_openChannelFile($channel, 'r');
1175 if ($fp === null) {
1176 return null;
1177 }
1178
1179 clearstatcache();
1180 $this->_closeChannelFile($fp);
1181 $data = file_get_contents($this->_channelFileName($channel));
1182 $data = unserialize($data);
1183 return $data;
1184 }
1185
1186 function _listChannels()
1187 {
1188 $channellist = array();
1189 if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) {
1190 return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri');
1191 }
1192
1193 $dp = opendir($this->channelsdir);
1194 while ($ent = readdir($dp)) {
1195 if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
1196 continue;
1197 }
1198
1199 if ($ent == '__uri.reg') {
1200 $channellist[] = '__uri';
1201 continue;
1202 }
1203
1204 $channellist[] = str_replace('_', '/', substr($ent, 0, -4));
1205 }
1206
1207 closedir($dp);
1208 if (!in_array('pear.php.net', $channellist)) {
1209 $channellist[] = 'pear.php.net';
1210 }
1211
1212 if (!in_array('pecl.php.net', $channellist)) {
1213 $channellist[] = 'pecl.php.net';
1214 }
1215
1216 if (!in_array('doc.php.net', $channellist)) {
1217 $channellist[] = 'doc.php.net';
1218 }
1219
1220
1221 if (!in_array('__uri', $channellist)) {
1222 $channellist[] = '__uri';
1223 }
1224
1225 natsort($channellist);
1226 return $channellist;
1227 }
1228
1229 function _listPackages($channel = false)
1230 {
1231 if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
1232 return $this->_listChannelPackages($channel);
1233 }
1234
1235 if (!file_exists($this->statedir) || !is_dir($this->statedir)) {
1236 return array();
1237 }
1238
1239 $pkglist = array();
1240 $dp = opendir($this->statedir);
1241 if (!$dp) {
1242 return $pkglist;
1243 }
1244
1245 while ($ent = readdir($dp)) {
1246 if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
1247 continue;
1248 }
1249
1250 $pkglist[] = substr($ent, 0, -4);
1251 }
1252 closedir($dp);
1253 sort($pkglist);
1254 return $pkglist;
1255 }
1256
1257 function _listChannelPackages($channel)
1258 {
1259 $pkglist = array();
1260 if (!file_exists($this->_channelDirectoryName($channel)) ||
1261 !is_dir($this->_channelDirectoryName($channel))) {
1262 return array();
1263 }
1264
1265 $dp = opendir($this->_channelDirectoryName($channel));
1266 if (!$dp) {
1267 return $pkglist;
1268 }
1269
1270 while ($ent = readdir($dp)) {
1271 if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
1272 continue;
1273 }
1274 $pkglist[] = substr($ent, 0, -4);
1275 }
1276
1277 closedir($dp);
1278 return $pkglist;
1279 }
1280
1282 {
1283 $ret = array();
1284 foreach ($this->_listChannels() as $channel) {
1285 $ret[$channel] = $this->_listPackages($channel);
1286 }
1287
1288 return $ret;
1289 }
1290
1298 function _addPackage($package, $info)
1299 {
1300 if ($this->_packageExists($package)) {
1301 return false;
1302 }
1303
1304 $fp = $this->_openPackageFile($package, 'wb');
1305 if ($fp === null) {
1306 return false;
1307 }
1308
1309 $info['_lastmodified'] = self::getSourceDateEpoch();
1310 fwrite($fp, serialize($info));
1311 $this->_closePackageFile($fp);
1312 if (isset($info['filelist'])) {
1313 $this->_rebuildFileMap();
1314 }
1315
1316 return true;
1317 }
1318
1324 function _addPackage2($info)
1325 {
1326 if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) {
1327 return false;
1328 }
1329
1330 if (!$info->validate()) {
1331 if (class_exists('PEAR_Common')) {
1333 if ($ui) {
1334 foreach ($info->getValidationWarnings() as $err) {
1335 $ui->log($err['message'], true);
1336 }
1337 }
1338 }
1339 return false;
1340 }
1341
1342 $channel = $info->getChannel();
1343 $package = $info->getPackage();
1344 $save = $info;
1345 if ($this->_packageExists($package, $channel)) {
1346 return false;
1347 }
1348
1349 if (!$this->_channelExists($channel, true)) {
1350 return false;
1351 }
1352
1353 $info = $info->toArray(true);
1354 if (!$info) {
1355 return false;
1356 }
1357
1358 $fp = $this->_openPackageFile($package, 'wb', $channel);
1359 if ($fp === null) {
1360 return false;
1361 }
1362
1363 $info['_lastmodified'] = self::getSourceDateEpoch();
1364 fwrite($fp, serialize($info));
1365 $this->_closePackageFile($fp);
1366 $this->_rebuildFileMap();
1367 return true;
1368 }
1369
1376 function _updatePackage($package, $info, $merge = true)
1377 {
1378 $oldinfo = $this->_packageInfo($package);
1379 if (empty($oldinfo)) {
1380 return false;
1381 }
1382
1383 $fp = $this->_openPackageFile($package, 'w');
1384 if ($fp === null) {
1385 return false;
1386 }
1387
1388 if (is_object($info)) {
1389 $info = $info->toArray();
1390 }
1391 $info['_lastmodified'] = self::getSourceDateEpoch();
1392
1393 $newinfo = $info;
1394 if ($merge) {
1395 $info = array_merge($oldinfo, $info);
1396 } else {
1397 $diff = $info;
1398 }
1399
1400 fwrite($fp, serialize($info));
1401 $this->_closePackageFile($fp);
1402 if (isset($newinfo['filelist'])) {
1403 $this->_rebuildFileMap();
1404 }
1405
1406 return true;
1407 }
1408
1414 function _updatePackage2($info)
1415 {
1416 if (!$this->_packageExists($info->getPackage(), $info->getChannel())) {
1417 return false;
1418 }
1419
1420 $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());
1421 if ($fp === null) {
1422 return false;
1423 }
1424
1425 $save = $info;
1426 $info = $save->getArray(true);
1427 $info['_lastmodified'] = self::getSourceDateEpoch();
1428 fwrite($fp, serialize($info));
1429 $this->_closePackageFile($fp);
1430 $this->_rebuildFileMap();
1431 return true;
1432 }
1433
1440 function &_getPackage($package, $channel = 'pear.php.net')
1441 {
1442 $info = $this->_packageInfo($package, null, $channel);
1443 if ($info === null) {
1444 return $info;
1445 }
1446
1447 $a = $this->_config;
1448 if (!$a) {
1449 $this->_config = new PEAR_Config;
1450 $this->_config->set('php_dir', $this->statedir);
1451 }
1452
1453 if (!class_exists('PEAR_PackageFile')) {
1454 require_once 'PEAR/PackageFile.php';
1455 }
1456
1457 $pkg = new PEAR_PackageFile($this->_config);
1458 $pf = &$pkg->fromArray($info);
1459 return $pf;
1460 }
1461
1468 function &_getChannel($channel, $noaliases = false)
1469 {
1470 $ch = false;
1471 if ($this->_channelExists($channel, $noaliases)) {
1472 $chinfo = $this->_channelInfo($channel, $noaliases);
1473 if ($chinfo) {
1474 if (!class_exists('PEAR_ChannelFile')) {
1475 require_once 'PEAR/ChannelFile.php';
1476 }
1477
1479 }
1480 }
1481
1482 if ($ch) {
1483 if ($ch->validate()) {
1484 return $ch;
1485 }
1486
1487 foreach ($ch->getErrors(true) as $err) {
1488 $message = $err['message'] . "\n";
1489 }
1490
1491 $ch = PEAR::raiseError($message);
1492 return $ch;
1493 }
1494
1495 if ($this->_getChannelFromAlias($channel) == 'pear.php.net') {
1496 // the registry is not properly set up, so use defaults
1497 if (!class_exists('PEAR_ChannelFile')) {
1498 require_once 'PEAR/ChannelFile.php';
1499 }
1500
1501 $pear_channel = new PEAR_ChannelFile;
1502 $pear_channel->setServer('pear.php.net');
1503 $pear_channel->setAlias('pear');
1504 $pear_channel->setSummary('PHP Extension and Application Repository');
1505 $pear_channel->setDefaultPEARProtocols();
1506 $pear_channel->setBaseURL('REST1.0', 'https://pear.php.net/rest/');
1507 $pear_channel->setBaseURL('REST1.1', 'https://pear.php.net/rest/');
1508 $pear_channel->setBaseURL('REST1.3', 'https://pear.php.net/rest/');
1509 return $pear_channel;
1510 }
1511
1512 if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
1513 // the registry is not properly set up, so use defaults
1514 if (!class_exists('PEAR_ChannelFile')) {
1515 require_once 'PEAR/ChannelFile.php';
1516 }
1517 $pear_channel = new PEAR_ChannelFile;
1518 $pear_channel->setServer('pecl.php.net');
1519 $pear_channel->setAlias('pecl');
1520 $pear_channel->setSummary('PHP Extension Community Library');
1521 $pear_channel->setDefaultPEARProtocols();
1522 $pear_channel->setBaseURL('REST1.0', 'https://pecl.php.net/rest/');
1523 $pear_channel->setBaseURL('REST1.1', 'https://pecl.php.net/rest/');
1524 $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
1525 return $pear_channel;
1526 }
1527
1528 if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
1529 // the registry is not properly set up, so use defaults
1530 if (!class_exists('PEAR_ChannelFile')) {
1531 require_once 'PEAR/ChannelFile.php';
1532 }
1533
1534 $doc_channel = new PEAR_ChannelFile;
1535 $doc_channel->setServer('doc.php.net');
1536 $doc_channel->setAlias('phpdocs');
1537 $doc_channel->setSummary('PHP Documentation Team');
1538 $doc_channel->setDefaultPEARProtocols();
1539 $doc_channel->setBaseURL('REST1.0', 'https://doc.php.net/rest/');
1540 $doc_channel->setBaseURL('REST1.1', 'https://doc.php.net/rest/');
1541 $doc_channel->setBaseURL('REST1.3', 'https://doc.php.net/rest/');
1542 return $doc_channel;
1543 }
1544
1545
1546 if ($this->_getChannelFromAlias($channel) == '__uri') {
1547 // the registry is not properly set up, so use defaults
1548 if (!class_exists('PEAR_ChannelFile')) {
1549 require_once 'PEAR/ChannelFile.php';
1550 }
1551
1552 $private = new PEAR_ChannelFile;
1553 $private->setName('__uri');
1554 $private->setDefaultPEARProtocols();
1555 $private->setBaseURL('REST1.0', '****');
1556 $private->setSummary('Pseudo-channel for static packages');
1557 return $private;
1558 }
1559
1560 return $ch;
1561 }
1562
1568 function packageExists($package, $channel = 'pear.php.net')
1569 {
1570 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1571 return $e;
1572 }
1573 $ret = $this->_packageExists($package, $channel);
1574 $this->_unlock();
1575 return $ret;
1576 }
1577
1578 // }}}
1579
1580 // {{{ channelExists()
1581
1587 function channelExists($channel, $noaliases = false)
1588 {
1589 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1590 return $e;
1591 }
1592 $ret = $this->_channelExists($channel, $noaliases);
1593 $this->_unlock();
1594 return $ret;
1595 }
1596
1597 // }}}
1598
1605 function mirrorExists($channel, $mirror)
1606 {
1607 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1608 return $e;
1609 }
1610
1611 $ret = $this->_mirrorExists($channel, $mirror);
1612 $this->_unlock();
1613 return $ret;
1614 }
1615
1616 // {{{ isAlias()
1617
1623 function isAlias($alias)
1624 {
1625 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1626 return $e;
1627 }
1628 $ret = $this->_isChannelAlias($alias);
1629 $this->_unlock();
1630 return $ret;
1631 }
1632
1633 // }}}
1634 // {{{ packageInfo()
1635
1642 function packageInfo($package = null, $key = null, $channel = 'pear.php.net')
1643 {
1644 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1645 return $e;
1646 }
1647 $ret = $this->_packageInfo($package, $key, $channel);
1648 $this->_unlock();
1649 return $ret;
1650 }
1651
1652 // }}}
1653 // {{{ channelInfo()
1654
1664 function channelInfo($channel = null, $noaliases = false)
1665 {
1666 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1667 return $e;
1668 }
1669 $ret = $this->_channelInfo($channel, $noaliases);
1670 $this->_unlock();
1671 return $ret;
1672 }
1673
1674 // }}}
1675
1679 function channelName($channel)
1680 {
1681 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1682 return $e;
1683 }
1684 $ret = $this->_getChannelFromAlias($channel);
1685 $this->_unlock();
1686 return $ret;
1687 }
1688
1692 function channelAlias($channel)
1693 {
1694 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1695 return $e;
1696 }
1697 $ret = $this->_getAlias($channel);
1698 $this->_unlock();
1699 return $ret;
1700 }
1701 // {{{ listPackages()
1702
1703 function listPackages($channel = false)
1704 {
1705 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1706 return $e;
1707 }
1708 $ret = $this->_listPackages($channel);
1709 $this->_unlock();
1710 return $ret;
1711 }
1712
1713 // }}}
1714 // {{{ listAllPackages()
1715
1717 {
1718 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1719 return $e;
1720 }
1721 $ret = $this->_listAllPackages();
1722 $this->_unlock();
1723 return $ret;
1724 }
1725
1726 // }}}
1727 // {{{ listChannel()
1728
1729 function listChannels()
1730 {
1731 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1732 return $e;
1733 }
1734 $ret = $this->_listChannels();
1735 $this->_unlock();
1736 return $ret;
1737 }
1738
1739 // }}}
1740 // {{{ addPackage()
1741
1749 function addPackage($package, $info)
1750 {
1751 if (is_object($info)) {
1752 return $this->addPackage2($info);
1753 }
1754 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1755 return $e;
1756 }
1757 $ret = $this->_addPackage($package, $info);
1758 $this->_unlock();
1759 if ($ret) {
1760 if (!class_exists('PEAR_PackageFile_v1')) {
1761 require_once 'PEAR/PackageFile/v1.php';
1762 }
1763 $pf = new PEAR_PackageFile_v1;
1764 $pf->setConfig($this->_config);
1765 $pf->fromArray($info);
1766 $this->_dependencyDB->uninstallPackage($pf);
1767 $this->_dependencyDB->installPackage($pf);
1768 }
1769 return $ret;
1770 }
1771
1772 // }}}
1773 // {{{ addPackage2()
1774
1775 function addPackage2($info)
1776 {
1777 if (!is_object($info)) {
1778 return $this->addPackage($info['package'], $info);
1779 }
1780 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1781 return $e;
1782 }
1783 $ret = $this->_addPackage2($info);
1784 $this->_unlock();
1785 if ($ret) {
1786 $this->_dependencyDB->uninstallPackage($info);
1787 $this->_dependencyDB->installPackage($info);
1788 }
1789 return $ret;
1790 }
1791
1792 // }}}
1793 // {{{ updateChannel()
1794
1799 function updateChannel($channel, $lastmodified = null)
1800 {
1801 if ($channel->getName() == '__uri') {
1802 return false;
1803 }
1804 return $this->addChannel($channel, $lastmodified, true);
1805 }
1806
1807 // }}}
1808 // {{{ deleteChannel()
1809
1815 function deleteChannel($channel)
1816 {
1817 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1818 return $e;
1819 }
1820
1821 $ret = $this->_deleteChannel($channel);
1822 $this->_unlock();
1823 if ($ret && is_a($this->_config, 'PEAR_Config')) {
1824 $this->_config->setChannels($this->listChannels());
1825 }
1826
1827 return $ret;
1828 }
1829
1830 // }}}
1831 // {{{ addChannel()
1832
1838 function addChannel($channel, $lastmodified = false, $update = false)
1839 {
1840 if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) {
1841 return false;
1842 }
1843
1844 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1845 return $e;
1846 }
1847
1848 $ret = $this->_addChannel($channel, $update, $lastmodified);
1849 $this->_unlock();
1850 if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) {
1851 $this->_config->setChannels($this->listChannels());
1852 }
1853
1854 return $ret;
1855 }
1856
1857 // }}}
1858 // {{{ deletePackage()
1859
1860 function deletePackage($package, $channel = 'pear.php.net')
1861 {
1862 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1863 return $e;
1864 }
1865
1866 $file = $this->_packageFileName($package, $channel);
1867 $ret = file_exists($file) ? @unlink($file) : false;
1868 $this->_rebuildFileMap();
1869 $this->_unlock();
1870 $p = array('channel' => $channel, 'package' => $package);
1871 $this->_dependencyDB->uninstallPackage($p);
1872 return $ret;
1873 }
1874
1875 // }}}
1876 // {{{ updatePackage()
1877
1878 function updatePackage($package, $info, $merge = true)
1879 {
1880 if (is_object($info)) {
1881 return $this->updatePackage2($info, $merge);
1882 }
1883 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1884 return $e;
1885 }
1886 $ret = $this->_updatePackage($package, $info, $merge);
1887 $this->_unlock();
1888 if ($ret) {
1889 if (!class_exists('PEAR_PackageFile_v1')) {
1890 require_once 'PEAR/PackageFile/v1.php';
1891 }
1892 $pf = new PEAR_PackageFile_v1;
1893 $pf->setConfig($this->_config);
1894 $pf->fromArray($this->packageInfo($package));
1895 $this->_dependencyDB->uninstallPackage($pf);
1896 $this->_dependencyDB->installPackage($pf);
1897 }
1898 return $ret;
1899 }
1900
1901 // }}}
1902 // {{{ updatePackage2()
1903
1904 function updatePackage2($info)
1905 {
1906
1907 if (!is_object($info)) {
1908 return $this->updatePackage($info['package'], $info, $merge);
1909 }
1910
1911 if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {
1912 return false;
1913 }
1914
1915 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
1916 return $e;
1917 }
1918
1919 $ret = $this->_updatePackage2($info);
1920 $this->_unlock();
1921 if ($ret) {
1922 $this->_dependencyDB->uninstallPackage($info);
1923 $this->_dependencyDB->installPackage($info);
1924 }
1925
1926 return $ret;
1927 }
1928
1929 // }}}
1930 // {{{ getChannel()
1936 function getChannel($channel, $noaliases = false)
1937 {
1938 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1939 return $e;
1940 }
1941 $ret = $this->_getChannel($channel, $noaliases);
1942 $this->_unlock();
1943 if (!$ret) {
1944 return PEAR::raiseError('Unknown channel: ' . $channel);
1945 }
1946 return $ret;
1947 }
1948
1949 // }}}
1950 // {{{ getPackage()
1956 function &getPackage($package, $channel = 'pear.php.net')
1957 {
1958 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
1959 return $e;
1960 }
1961 $pf = &$this->_getPackage($package, $channel);
1962 $this->_unlock();
1963 return $pf;
1964 }
1965
1966 // }}}
1967
1976 function getInstalledGroup($group)
1977 {
1978 $ret = array();
1979 if (isset($group['package'])) {
1980 if (!isset($group['package'][0])) {
1981 $group['package'] = array($group['package']);
1982 }
1983 foreach ($group['package'] as $package) {
1984 $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
1985 $p = &$this->getPackage($package['name'], $depchannel);
1986 if ($p) {
1987 $save = &$p;
1988 $ret[] = &$save;
1989 }
1990 }
1991 }
1992 if (isset($group['subpackage'])) {
1993 if (!isset($group['subpackage'][0])) {
1994 $group['subpackage'] = array($group['subpackage']);
1995 }
1996 foreach ($group['subpackage'] as $package) {
1997 $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
1998 $p = &$this->getPackage($package['name'], $depchannel);
1999 if ($p) {
2000 $save = &$p;
2001 $ret[] = &$save;
2002 }
2003 }
2004 }
2005 if (!count($ret)) {
2006 return false;
2007 }
2008 return $ret;
2009 }
2010
2011 // {{{ getChannelValidator()
2016 function &getChannelValidator($channel)
2017 {
2018 $chan = $this->getChannel($channel);
2019 if (PEAR::isError($chan)) {
2020 return $chan;
2021 }
2022 $val = $chan->getValidationObject();
2023 return $val;
2024 }
2025 // }}}
2026 // {{{ getChannels()
2031 function &getChannels()
2032 {
2033 $ret = array();
2034 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
2035 return $e;
2036 }
2037 foreach ($this->_listChannels() as $channel) {
2038 $e = &$this->_getChannel($channel);
2039 if (!$e || PEAR::isError($e)) {
2040 continue;
2041 }
2042 $ret[] = $e;
2043 }
2044 $this->_unlock();
2045 return $ret;
2046 }
2047
2048 // }}}
2049 // {{{ checkFileMap()
2050
2065 function checkFileMap($path, $package = false, $api = '1.0', $attrs = false)
2066 {
2067 if (is_array($path)) {
2068 static $notempty;
2069 if (empty($notempty)) {
2070 if (!class_exists('PEAR_Installer_Role')) {
2071 require_once 'PEAR/Installer/Role.php';
2072 }
2073 $notempty = function($a) { return !empty($a); };
2074 }
2075 $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1]))
2076 : strtolower($package);
2077 $pkgs = array();
2078 foreach ($path as $name => $attrs) {
2079 if (is_array($attrs)) {
2080 if (isset($attrs['install-as'])) {
2081 $name = $attrs['install-as'];
2082 }
2083 if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) {
2084 // these are not installed
2085 continue;
2086 }
2087 if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) {
2088 $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;
2089 }
2090 if (isset($attrs['baseinstalldir'])) {
2091 $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
2092 }
2093 }
2094 $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);
2095 if (PEAR::isError($pkgs[$name])) {
2096 return $pkgs[$name];
2097 }
2098 }
2099 return array_filter($pkgs, $notempty);
2100 }
2101 if (empty($this->filemap_cache)) {
2102 if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
2103 return $e;
2104 }
2105 $err = $this->_readFileMap();
2106 $this->_unlock();
2107 if (PEAR::isError($err)) {
2108 return $err;
2109 }
2110 }
2111 if (!$attrs) {
2112 $attrs = array('role' => 'php'); // any old call would be for PHP role only
2113 }
2114 if (isset($this->filemap_cache[$attrs['role']][$path])) {
2115 if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
2116 return false;
2117 }
2118 return $this->filemap_cache[$attrs['role']][$path];
2119 }
2120 $l = strlen($this->install_dir);
2121 if (substr($path, 0, $l) == $this->install_dir) {
2122 $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
2123 }
2124 if (isset($this->filemap_cache[$attrs['role']][$path])) {
2125 if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
2126 return false;
2127 }
2128 return $this->filemap_cache[$attrs['role']][$path];
2129 }
2130 return false;
2131 }
2132
2133 // }}}
2134 // {{{ flush()
2139 function flushFileMap()
2140 {
2141 $this->filemap_cache = null;
2142 clearstatcache(); // ensure that the next read gets the full, current filemap
2143 }
2144
2145 // }}}
2146 // {{{ apiVersion()
2152 function apiVersion()
2153 {
2154 return '1.1';
2155 }
2156 // }}}
2157
2158
2172 function parsePackageName($param, $defaultchannel = 'pear.php.net')
2173 {
2174 $saveparam = $param;
2175 if (is_array($param)) {
2176 // convert to string for error messages
2177 $saveparam = $this->parsedPackageNameToString($param);
2178 // process the array
2179 if (!isset($param['package'])) {
2180 return PEAR::raiseError('parsePackageName(): array $param ' .
2181 'must contain a valid package name in index "param"',
2182 'package', null, null, $param);
2183 }
2184 if (!isset($param['uri'])) {
2185 if (!isset($param['channel'])) {
2186 $param['channel'] = $defaultchannel;
2187 }
2188 } else {
2189 $param['channel'] = '__uri';
2190 }
2191 } else {
2192 $components = @parse_url((string) $param);
2193 if (isset($components['scheme'])) {
2194 if ($components['scheme'] == 'http') {
2195 // uri package
2196 $param = array('uri' => $param, 'channel' => '__uri');
2197 } elseif($components['scheme'] != 'channel') {
2198 return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .
2199 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);
2200 }
2201 }
2202 if (!isset($components['path'])) {
2203 return PEAR::raiseError('parsePackageName(): array $param ' .
2204 'must contain a valid package name in "' . $param . '"',
2205 'package', null, null, $param);
2206 }
2207 if (isset($components['host'])) {
2208 // remove the leading "/"
2209 $components['path'] = substr($components['path'], 1);
2210 }
2211 if (!isset($components['scheme'])) {
2212 if (strpos($components['path'], '/') !== false) {
2213 if ($components['path'][0] == '/') {
2214 return PEAR::raiseError('parsePackageName(): this is not ' .
2215 'a package name, it begins with "/" in "' . $param . '"',
2216 'invalid', null, null, $param);
2217 }
2218 $parts = explode('/', $components['path']);
2219 $components['host'] = array_shift($parts);
2220 if (count($parts) > 1) {
2221 $components['path'] = array_pop($parts);
2222 $components['host'] .= '/' . implode('/', $parts);
2223 } else {
2224 $components['path'] = implode('/', $parts);
2225 }
2226 } else {
2227 $components['host'] = $defaultchannel;
2228 }
2229 } else {
2230 if (strpos($components['path'], '/')) {
2231 $parts = explode('/', $components['path']);
2232 $components['path'] = array_pop($parts);
2233 $components['host'] .= '/' . implode('/', $parts);
2234 }
2235 }
2236
2237 if (is_array($param)) {
2238 $param['package'] = $components['path'];
2239 } else {
2240 $param = array(
2241 'package' => $components['path']
2242 );
2243 if (isset($components['host'])) {
2244 $param['channel'] = $components['host'];
2245 }
2246 }
2247 if (isset($components['fragment'])) {
2248 $param['group'] = $components['fragment'];
2249 }
2250 if (isset($components['user'])) {
2251 $param['user'] = $components['user'];
2252 }
2253 if (isset($components['pass'])) {
2254 $param['pass'] = $components['pass'];
2255 }
2256 if (isset($components['query'])) {
2257 parse_str($components['query'], $param['opts']);
2258 }
2259 // check for extension
2260 $pathinfo = pathinfo($param['package']);
2261 if (isset($pathinfo['extension']) &&
2262 in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) {
2263 $param['extension'] = $pathinfo['extension'];
2264 $param['package'] = substr($pathinfo['basename'], 0,
2265 strlen($pathinfo['basename']) - 4);
2266 }
2267 // check for version
2268 if (strpos($param['package'], '-')) {
2269 $test = explode('-', $param['package']);
2270 if (count($test) != 2) {
2271 return PEAR::raiseError('parsePackageName(): only one version/state ' .
2272 'delimiter "-" is allowed in "' . $saveparam . '"',
2273 'version', null, null, $param);
2274 }
2275 list($param['package'], $param['version']) = $test;
2276 }
2277 }
2278 // validation
2279 $info = $this->channelExists($param['channel']);
2280 if (PEAR::isError($info)) {
2281 return $info;
2282 }
2283 if (!$info) {
2284 return PEAR::raiseError('unknown channel "' . $param['channel'] .
2285 '" in "' . $saveparam . '"', 'channel', null, null, $param);
2286 }
2287 $chan = $this->getChannel($param['channel']);
2288 if (PEAR::isError($chan)) {
2289 return $chan;
2290 }
2291 if (!$chan) {
2292 return PEAR::raiseError("Exception: corrupt registry, could not " .
2293 "retrieve channel " . $param['channel'] . " information",
2294 'registry', null, null, $param);
2295 }
2296 $param['channel'] = $chan->getName();
2297 $validate = $chan->getValidationObject();
2298 $vpackage = $chan->getValidationPackage();
2299 // validate package name
2300 if (!$validate->validPackageName($param['package'], $vpackage['_content'])) {
2301 return PEAR::raiseError('parsePackageName(): invalid package name "' .
2302 $param['package'] . '" in "' . $saveparam . '"',
2303 'package', null, null, $param);
2304 }
2305 if (isset($param['group'])) {
2306 if (!PEAR_Validate::validGroupName($param['group'])) {
2307 return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] .
2308 '" is not a valid group name in "' . $saveparam . '"', 'group', null, null,
2309 $param);
2310 }
2311 }
2312 if (isset($param['state'])) {
2313 if (!in_array(strtolower($param['state']), $validate->getValidStates())) {
2314 return PEAR::raiseError('parsePackageName(): state "' . $param['state']
2315 . '" is not a valid state in "' . $saveparam . '"',
2316 'state', null, null, $param);
2317 }
2318 }
2319 if (isset($param['version'])) {
2320 if (isset($param['state'])) {
2321 return PEAR::raiseError('parsePackageName(): cannot contain both ' .
2322 'a version and a stability (state) in "' . $saveparam . '"',
2323 'version/state', null, null, $param);
2324 }
2325 // check whether version is actually a state
2326 if (in_array(strtolower($param['version']), $validate->getValidStates())) {
2327 $param['state'] = strtolower($param['version']);
2328 unset($param['version']);
2329 } else {
2330 if (!$validate->validVersion($param['version'])) {
2331 return PEAR::raiseError('parsePackageName(): "' . $param['version'] .
2332 '" is neither a valid version nor a valid state in "' .
2333 $saveparam . '"', 'version/state', null, null, $param);
2334 }
2335 }
2336 }
2337 return $param;
2338 }
2339
2344 function parsedPackageNameToString($parsed, $brief = false)
2345 {
2346 if (is_string($parsed)) {
2347 return $parsed;
2348 }
2349 if (is_object($parsed)) {
2350 $p = $parsed;
2351 $parsed = array(
2352 'package' => $p->getPackage(),
2353 'channel' => $p->getChannel(),
2354 'version' => $p->getVersion(),
2355 );
2356 }
2357 if (isset($parsed['uri'])) {
2358 return $parsed['uri'];
2359 }
2360 if ($brief) {
2361 if ($channel = $this->channelAlias($parsed['channel'])) {
2362 return $channel . '/' . $parsed['package'];
2363 }
2364 }
2365 $upass = '';
2366 if (isset($parsed['user'])) {
2367 $upass = $parsed['user'];
2368 if (isset($parsed['pass'])) {
2369 $upass .= ':' . $parsed['pass'];
2370 }
2371 $upass = "$upass@";
2372 }
2373 $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];
2374 if (isset($parsed['version']) || isset($parsed['state'])) {
2375 $ver = isset($parsed['version']) ? $parsed['version'] : '';
2376 $ver .= isset($parsed['state']) ? $parsed['state'] : '';
2377 $ret .= '-' . $ver;
2378 }
2379 if (isset($parsed['extension'])) {
2380 $ret .= '.' . $parsed['extension'];
2381 }
2382 if (isset($parsed['opts'])) {
2383 $ret .= '?';
2384 foreach ($parsed['opts'] as $name => $value) {
2385 $parsed['opts'][$name] = "$name=$value";
2386 }
2387 $ret .= implode('&', $parsed['opts']);
2388 }
2389 if (isset($parsed['group'])) {
2390 $ret .= '#' . $parsed['group'];
2391 }
2392 return $ret;
2393 }
2394}
const PEAR_REGISTRY_ERROR_FORMAT
Definition Registry.php:25
const PEAR_REGISTRY_ERROR_FILE
Definition Registry.php:26
const PEAR_REGISTRY_ERROR_LOCK
Definition Registry.php:24
const PEAR_VALIDATE_DOWNLOADING
Definition Validate.php:21
setServer($server, $mirror=false)
setAlias($alias, $local=false)
static & fromArrayWithErrors( $data, $compatibility=false, $stackClass='PEAR_ErrorStack')
static & singleton(&$config, $depdb=false)
static & singleton($type=null)
Definition Frontend.php:51
static getBaseinstallRoles($clear=false)
Definition Role.php:156
static getInstallableRoles($clear=false)
Definition Role.php:122
setConfig(&$config)
Definition v1.php:365
updateChannel($channel, $lastmodified=null)
& _getChannel($channel, $noaliases=false)
channelAlias($channel)
_openPackageFile($package, $mode, $channel=false)
Definition Registry.php:641
_addPackage2($info)
& getChannelValidator($channel)
_initializeChannelDirs()
Definition Registry.php:190
_listChannelPackages($channel)
setConfig(&$config, $resetInstallDir=true)
Definition Registry.php:182
listPackages($channel=false)
deletePackage($package, $channel='pear.php.net')
updatePackage2($info)
_channelExists($channel, $noaliases=false)
Definition Registry.php:895
_packageFileName($package, $channel=false)
Definition Registry.php:517
_mirrorExists($channel, $mirror)
Definition Registry.php:921
_channelDirectoryName($channel)
Definition Registry.php:626
getChannel($channel, $noaliases=false)
& _getPackage($package, $channel='pear.php.net')
_channelFileName($channel, $noaliases=false)
Definition Registry.php:532
getInstalledGroup($group)
_isChannelAlias($alias)
_updatePackage($package, $info, $merge=true)
parsePackageName($param, $defaultchannel='pear.php.net')
_closeChannelFile($fp)
Definition Registry.php:692
checkFileMap($path, $package=false, $api='1.0', $attrs=false)
_packageInfo($package=null, $key=null, $channel='pear.php.net')
packageExists($package, $channel='pear.php.net')
_closePackageFile($fp)
Definition Registry.php:664
_addPackage($package, $info)
addPackage($package, $info)
channelInfo($channel=null, $noaliases=false)
setInstallDir($pear_install_dir=PEAR_INSTALL_DIR, $pear_metadata_dir='')
Definition Registry.php:143
_assertStateDir($channel=false)
Definition Registry.php:373
__construct($pear_install_dir=PEAR_INSTALL_DIR, $pear_channel=false, $pecl_channel=false, $pear_metadata_dir='')
Definition Registry.php:133
addChannel($channel, $lastmodified=false, $update=false)
_openChannelFile($channel, $mode)
Definition Registry.php:669
mirrorExists($channel, $mirror)
& getPackage($package, $channel='pear.php.net')
_assertChannelStateDir($channel)
Definition Registry.php:432
channelExists($channel, $noaliases=false)
_getAlias($channel)
Definition Registry.php:590
_getChannelAliasFileName($alias)
Definition Registry.php:547
parsedPackageNameToString($parsed, $brief=false)
_addChannel($channel, $update=false, $lastmodified=false)
Definition Registry.php:943
packageInfo($package=null, $key=null, $channel='pear.php.net')
_channelInfo($channel, $noaliases=false)
_deleteChannel($channel)
_updatePackage2($info)
_getChannelFromAlias($channel)
Definition Registry.php:556
isAlias($alias)
_packageExists($package, $channel=false)
Definition Registry.php:883
updatePackage($package, $info, $merge=true)
deleteChannel($channel)
addPackage2($info)
_listPackages($channel=false)
channelName($channel)
_lock($mode=LOCK_EX)
Definition Registry.php:816
static validGroupName($name)
Definition Validate.php:88
static getSourceDateEpoch()
Definition PEAR.php:787
static isError($data, $code=null)
Definition PEAR.php:306
$config
Definition pearcmd.php:182
$ui
Definition pearcmd.php:181