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