Bearsampp 2026.9.23
Loading...
Searching...
No Matches
DependencyDB.php
Go to the documentation of this file.
1<?php
16
20require_once 'PEAR.php';
21require_once 'PEAR/Config.php';
22
23$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
37{
38 // {{{ properties
39
57 var $_depdb = false;
63 var $_lockfile = false;
69 var $_lockFp = false;
75 var $_version = '1.0';
82
83 // }}}
84 // {{{ & singleton()
85
92 public static function &singleton(&$config, $depdb = false)
93 {
94 $phpdir = $config->get('php_dir', null, 'pear.php.net');
95 if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) {
96 $a = new PEAR_DependencyDB;
97 $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a;
98 $a->setConfig($config, $depdb);
99 $e = $a->assertDepsDB();
100 if (PEAR::isError($e)) {
101 return $e;
102 }
103 }
104
105 return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir];
106 }
107
113 function setConfig(&$config, $depdb = false)
114 {
115 if (!$config) {
116 $this->_config = &PEAR_Config::singleton();
117 } else {
118 $this->_config = &$config;
119 }
120
121 $this->_registry = &$this->_config->getRegistry();
122 if (!$depdb) {
123 $dir = $this->_config->get('metadata_dir', null, 'pear.php.net');
124 if (!$dir) {
125 $dir = $this->_config->get('php_dir', null, 'pear.php.net');
126 }
127 $this->_depdb = $dir . DIRECTORY_SEPARATOR . '.depdb';
128 } else {
129 $this->_depdb = $depdb;
130 }
131
132 $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
133 }
134 // }}}
135
136 function hasWriteAccess()
137 {
138 if (!file_exists($this->_depdb)) {
139 $dir = $this->_depdb;
140 while ($dir && $dir != '.') {
141 $dir = dirname($dir); // cd ..
142 if ($dir != '.' && file_exists($dir)) {
143 if (is_writeable($dir)) {
144 return true;
145 }
146
147 return false;
148 }
149 }
150
151 return false;
152 }
153
154 return is_writeable($this->_depdb);
155 }
156
157 // {{{ assertDepsDB()
158
164 function assertDepsDB()
165 {
166 if (!is_file($this->_depdb)) {
167 $this->rebuildDB();
168 return;
169 }
170
171 $depdb = $this->_getDepDB();
172 // Datatype format has been changed, rebuild the Deps DB
173 if ($depdb['_version'] < $this->_version) {
174 $this->rebuildDB();
175 }
176
177 if ($depdb['_version'][0] > $this->_version[0]) {
178 return PEAR::raiseError('Dependency database is version ' .
179 $depdb['_version'] . ', and we are version ' .
180 $this->_version . ', cannot continue');
181 }
182 }
183
189 function getDependentPackages(&$pkg)
190 {
191 $data = $this->_getDepDB();
192 if (is_object($pkg)) {
193 $channel = strtolower($pkg->getChannel());
194 $package = strtolower($pkg->getPackage());
195 } else {
196 $channel = strtolower($pkg['channel']);
197 $package = strtolower($pkg['package']);
198 }
199
200 if (isset($data['packages'][$channel][$package])) {
201 return $data['packages'][$channel][$package];
202 }
203
204 return false;
205 }
206
214 {
215 $data = $this->_getDepDB();
216 if (is_object($pkg)) {
217 $channel = strtolower($pkg->getChannel());
218 $package = strtolower($pkg->getPackage());
219 } else if (is_array($pkg)) {
220 $channel = strtolower($pkg['channel']);
221 $package = strtolower($pkg['package']);
222 } else {
223 return false;
224 }
225
226 $depend = $this->getDependentPackages($pkg);
227 if (!$depend) {
228 return false;
229 }
230
231 $dependencies = array();
232 foreach ($depend as $info) {
233 $temp = $this->getDependencies($info);
234 foreach ($temp as $dep) {
235 if (
236 isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) &&
237 strtolower($dep['dep']['channel']) == $channel &&
238 strtolower($dep['dep']['name']) == $package
239 ) {
240 if (!isset($dependencies[$info['channel']])) {
241 $dependencies[$info['channel']] = array();
242 }
243
244 if (!isset($dependencies[$info['channel']][$info['package']])) {
245 $dependencies[$info['channel']][$info['package']] = array();
246 }
247 $dependencies[$info['channel']][$info['package']][] = $dep;
248 }
249 }
250 }
251
252 return $dependencies;
253 }
254
260 function getDependencies(&$pkg)
261 {
262 if (is_object($pkg)) {
263 $channel = strtolower($pkg->getChannel());
264 $package = strtolower($pkg->getPackage());
265 } else {
266 $channel = strtolower($pkg['channel']);
267 $package = strtolower($pkg['package']);
268 }
269
270 $data = $this->_getDepDB();
271 if (isset($data['dependencies'][$channel][$package])) {
272 return $data['dependencies'][$channel][$package];
273 }
274
275 return false;
276 }
277
283 function dependsOn($parent, $child)
284 {
285 $c = array();
286 $this->_getDepDB();
287 return $this->_dependsOn($parent, $child, $c);
288 }
289
290 function _dependsOn($parent, $child, &$checked)
291 {
292 if (is_object($parent)) {
293 $channel = strtolower($parent->getChannel());
294 $package = strtolower($parent->getPackage());
295 } else {
296 $channel = strtolower($parent['channel']);
297 $package = strtolower($parent['package']);
298 }
299
300 if (is_object($child)) {
301 $depchannel = strtolower($child->getChannel());
302 $deppackage = strtolower($child->getPackage());
303 } else {
304 $depchannel = strtolower($child['channel']);
305 $deppackage = strtolower($child['package']);
306 }
307
308 if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
309 return false; // avoid endless recursion
310 }
311
312 $checked[$channel][$package][$depchannel][$deppackage] = true;
313 if (!isset($this->_cache['dependencies'][$channel][$package])) {
314 return false;
315 }
316
317 foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
318 if (isset($info['dep']['uri'])) {
319 if (is_object($child)) {
320 if ($info['dep']['uri'] == $child->getURI()) {
321 return true;
322 }
323 } elseif (isset($child['uri'])) {
324 if ($info['dep']['uri'] == $child['uri']) {
325 return true;
326 }
327 }
328 return false;
329 }
330
331 if (strtolower($info['dep']['channel']) == $depchannel &&
332 strtolower($info['dep']['name']) == $deppackage) {
333 return true;
334 }
335 }
336
337 foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
338 if (isset($info['dep']['uri'])) {
339 if ($this->_dependsOn(array(
340 'uri' => $info['dep']['uri'],
341 'package' => $info['dep']['name']), $child, $checked)) {
342 return true;
343 }
344 } else {
345 if ($this->_dependsOn(array(
346 'channel' => $info['dep']['channel'],
347 'package' => $info['dep']['name']), $child, $checked)) {
348 return true;
349 }
350 }
351 }
352
353 return false;
354 }
355
360 function installPackage(&$package)
361 {
362 $data = $this->_getDepDB();
363 unset($this->_cache);
364 $this->_setPackageDeps($data, $package);
365 $this->_writeDepDB($data);
366 }
367
375 function uninstallPackage(&$pkg)
376 {
377 $data = $this->_getDepDB();
378 unset($this->_cache);
379 if (is_object($pkg)) {
380 $channel = strtolower($pkg->getChannel());
381 $package = strtolower($pkg->getPackage());
382 } else {
383 $channel = strtolower($pkg['channel']);
384 $package = strtolower($pkg['package']);
385 }
386
387 if (!isset($data['dependencies'][$channel][$package])) {
388 return true;
389 }
390
391 foreach ($data['dependencies'][$channel][$package] as $dep) {
392 $found = false;
393 $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']);
394 $depname = strtolower($dep['dep']['name']);
395 if (isset($data['packages'][$depchannel][$depname])) {
396 foreach ($data['packages'][$depchannel][$depname] as $i => $info) {
397 if ($info['channel'] == $channel && $info['package'] == $package) {
398 $found = true;
399 break;
400 }
401 }
402 }
403
404 if ($found) {
405 unset($data['packages'][$depchannel][$depname][$i]);
406 if (!count($data['packages'][$depchannel][$depname])) {
407 unset($data['packages'][$depchannel][$depname]);
408 if (!count($data['packages'][$depchannel])) {
409 unset($data['packages'][$depchannel]);
410 }
411 } else {
412 $data['packages'][$depchannel][$depname] =
413 array_values($data['packages'][$depchannel][$depname]);
414 }
415 }
416 }
417
418 unset($data['dependencies'][$channel][$package]);
419 if (!count($data['dependencies'][$channel])) {
420 unset($data['dependencies'][$channel]);
421 }
422
423 if (!count($data['dependencies'])) {
424 unset($data['dependencies']);
425 }
426
427 if (!count($data['packages'])) {
428 unset($data['packages']);
429 }
430
431 $this->_writeDepDB($data);
432 }
433
438 function rebuildDB()
439 {
440 $depdb = array('_version' => $this->_version);
441 if (!$this->hasWriteAccess()) {
442 // allow startup for read-only with older Registry
443 return $depdb;
444 }
445
446 $packages = $this->_registry->listAllPackages();
447 if (PEAR::isError($packages)) {
448 return $packages;
449 }
450
451 foreach ($packages as $channel => $ps) {
452 foreach ($ps as $package) {
453 $package = $this->_registry->getPackage($package, $channel);
454 if (PEAR::isError($package)) {
455 return $package;
456 }
457 $this->_setPackageDeps($depdb, $package);
458 }
459 }
460
461 $error = $this->_writeDepDB($depdb);
462 if (PEAR::isError($error)) {
463 return $error;
464 }
465
466 $this->_cache = $depdb;
467 return true;
468 }
469
476 function _lock($mode = LOCK_EX)
477 {
478 if (stristr(php_uname(), 'Windows 9')) {
479 return true;
480 }
481
482 if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
483 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
484 return true;
485 }
486
487 $open_mode = 'w';
488 // XXX People reported problems with LOCK_SH and 'w'
489 if ($mode === LOCK_SH) {
490 if (!file_exists($this->_lockfile)) {
491 touch($this->_lockfile);
492 } elseif (!is_file($this->_lockfile)) {
493 return PEAR::raiseError('could not create Dependency lock file, ' .
494 'it exists and is not a regular file');
495 }
496 $open_mode = 'r';
497 }
498
499 if (!is_resource($this->_lockFp)) {
500 $this->_lockFp = @fopen($this->_lockfile, $open_mode);
501 }
502
503 if (!is_resource($this->_lockFp)) {
504 $last_errormsg = '';
505 $last_error = error_get_last();
506 if (!empty($last_error['message'])) {
507 $last_errormsg = $last_error['message'];
508 }
509 return PEAR::raiseError("could not create Dependency lock file" .
510 (isset($last_errormsg) ? ": " . $last_errormsg : ""));
511 }
512
513 if (!(int)flock($this->_lockFp, $mode)) {
514 switch ($mode) {
515 case LOCK_SH: $str = 'shared'; break;
516 case LOCK_EX: $str = 'exclusive'; break;
517 case LOCK_UN: $str = 'unlock'; break;
518 default: $str = 'unknown'; break;
519 }
520
521 return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
522 }
523
524 return true;
525 }
526
532 function _unlock()
533 {
534 $ret = $this->_lock(LOCK_UN);
535 if (is_resource($this->_lockFp)) {
536 fclose($this->_lockFp);
537 }
538 $this->_lockFp = null;
539 return $ret;
540 }
541
546 function _getDepDB()
547 {
548 if (!$this->hasWriteAccess()) {
549 return array('_version' => $this->_version);
550 }
551
552 if (isset($this->_cache)) {
553 return $this->_cache;
554 }
555
556 if (!$fp = fopen($this->_depdb, 'r')) {
557 $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
558 return $err;
559 }
560
561 clearstatcache();
562 fclose($fp);
563 $data = @unserialize(file_get_contents($this->_depdb));
564 $this->_cache = $data;
565 return $data;
566 }
567
574 function _writeDepDB(&$deps)
575 {
576 if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
577 return $e;
578 }
579
580 if (!$fp = fopen($this->_depdb, 'wb')) {
581 $this->_unlock();
582 return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
583 }
584
585 fwrite($fp, serialize($deps));
586 fclose($fp);
587 $this->_unlock();
588 $this->_cache = $deps;
589 return true;
590 }
591
599 function _setPackageDeps(&$data, &$pkg)
600 {
601 $pkg->setConfig($this->_config);
602 if ($pkg->getPackagexmlVersion() == '1.0') {
603 $gen = &$pkg->getDefaultGenerator();
604 $deps = $gen->dependenciesToV2();
605 } else {
606 $deps = $pkg->getDeps(true);
607 }
608
609 if (!$deps) {
610 return;
611 }
612
613 if (!is_array($data)) {
614 $data = array();
615 }
616
617 if (!isset($data['dependencies'])) {
618 $data['dependencies'] = array();
619 }
620
621 $channel = strtolower($pkg->getChannel());
622 $package = strtolower($pkg->getPackage());
623
624 if (!isset($data['dependencies'][$channel])) {
625 $data['dependencies'][$channel] = array();
626 }
627
628 $data['dependencies'][$channel][$package] = array();
629 if (isset($deps['required']['package'])) {
630 if (!isset($deps['required']['package'][0])) {
631 $deps['required']['package'] = array($deps['required']['package']);
632 }
633
634 foreach ($deps['required']['package'] as $dep) {
635 $this->_registerDep($data, $pkg, $dep, 'required');
636 }
637 }
638
639 if (isset($deps['optional']['package'])) {
640 if (!isset($deps['optional']['package'][0])) {
641 $deps['optional']['package'] = array($deps['optional']['package']);
642 }
643
644 foreach ($deps['optional']['package'] as $dep) {
645 $this->_registerDep($data, $pkg, $dep, 'optional');
646 }
647 }
648
649 if (isset($deps['required']['subpackage'])) {
650 if (!isset($deps['required']['subpackage'][0])) {
651 $deps['required']['subpackage'] = array($deps['required']['subpackage']);
652 }
653
654 foreach ($deps['required']['subpackage'] as $dep) {
655 $this->_registerDep($data, $pkg, $dep, 'required');
656 }
657 }
658
659 if (isset($deps['optional']['subpackage'])) {
660 if (!isset($deps['optional']['subpackage'][0])) {
661 $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
662 }
663
664 foreach ($deps['optional']['subpackage'] as $dep) {
665 $this->_registerDep($data, $pkg, $dep, 'optional');
666 }
667 }
668
669 if (isset($deps['group'])) {
670 if (!isset($deps['group'][0])) {
671 $deps['group'] = array($deps['group']);
672 }
673
674 foreach ($deps['group'] as $group) {
675 if (isset($group['package'])) {
676 if (!isset($group['package'][0])) {
677 $group['package'] = array($group['package']);
678 }
679
680 foreach ($group['package'] as $dep) {
681 $this->_registerDep($data, $pkg, $dep, 'optional',
682 $group['attribs']['name']);
683 }
684 }
685
686 if (isset($group['subpackage'])) {
687 if (!isset($group['subpackage'][0])) {
688 $group['subpackage'] = array($group['subpackage']);
689 }
690
691 foreach ($group['subpackage'] as $dep) {
692 $this->_registerDep($data, $pkg, $dep, 'optional',
693 $group['attribs']['name']);
694 }
695 }
696 }
697 }
698
699 if ($data['dependencies'][$channel][$package] == array()) {
700 unset($data['dependencies'][$channel][$package]);
701 if (!count($data['dependencies'][$channel])) {
702 unset($data['dependencies'][$channel]);
703 }
704 }
705 }
706
714 function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
715 {
716 $info = array(
717 'dep' => $dep,
718 'type' => $type,
719 'group' => $group
720 );
721
722 $dep = array_map('strtolower', $dep);
723 $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
724 if (!isset($data['dependencies'])) {
725 $data['dependencies'] = array();
726 }
727
728 $channel = strtolower($pkg->getChannel());
729 $package = strtolower($pkg->getPackage());
730
731 if (!isset($data['dependencies'][$channel])) {
732 $data['dependencies'][$channel] = array();
733 }
734
735 if (!isset($data['dependencies'][$channel][$package])) {
736 $data['dependencies'][$channel][$package] = array();
737 }
738
739 $data['dependencies'][$channel][$package][] = $info;
740 if (isset($data['packages'][$depchannel][$dep['name']])) {
741 $found = false;
742 foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) {
743 if ($p['channel'] == $channel && $p['package'] == $package) {
744 $found = true;
745 break;
746 }
747 }
748 } else {
749 if (!isset($data['packages'])) {
750 $data['packages'] = array();
751 }
752
753 if (!isset($data['packages'][$depchannel])) {
754 $data['packages'][$depchannel] = array();
755 }
756
757 if (!isset($data['packages'][$depchannel][$dep['name']])) {
758 $data['packages'][$depchannel][$dep['name']] = array();
759 }
760
761 $found = false;
762 }
763
764 if (!$found) {
765 $data['packages'][$depchannel][$dep['name']][] = array(
766 'channel' => $channel,
767 'package' => $package
768 );
769 }
770 }
771}
$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
$GLOBALS['_PEAR_default_error_mode']
Definition PEAR.php:46
setConfig(&$config, $depdb=false)
dependsOn($parent, $child)
_dependsOn($parent, $child, &$checked)
getDependentPackageDependencies(&$pkg)
_setPackageDeps(&$data, &$pkg)
_registerDep(&$data, &$pkg, $dep, $type, $group=false)
installPackage(&$package)
static & singleton(&$config, $depdb=false)
_lock($mode=LOCK_EX)
$config
Definition pearcmd.php:182