Редакция 69 | Содержимое файла | Сравнить с предыдущей | Последнее изменение | Открыть журнал | RSS
Редакция | Автор | № строки | Строка |
---|---|---|---|
69 | alex-w | 1 | <?php |
2 | /** |
||
3 | * PEAR_Dependency |
||
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 | * THIS FILE IS DEPRECATED IN FAVOR OF DEPENDENCY2.PHP, AND IS NOT USED IN THE INSTALLER |
||
14 | * |
||
15 | * @category pear |
||
16 | * @package PEAR |
||
17 | * @author Tomas V.V.Cox <cox@idecnet.com> |
||
18 | * @author Stig Bakken <ssb@php.net> |
||
19 | * @copyright 1997-2008 The PHP Group |
||
20 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||
21 | * @version CVS: $Id: Dependency.php,v 1.43 2008/01/03 20:26:34 cellog Exp $ |
||
22 | * @link http://pear.php.net/package/PEAR |
||
23 | * @since File available since Release 1.4.0a1 |
||
24 | */ |
||
25 | |||
26 | require_once "PEAR.php"; |
||
27 | require_once "OS/Guess.php"; |
||
28 | |||
29 | define('PEAR_DEPENDENCY_MISSING', -1); |
||
30 | define('PEAR_DEPENDENCY_CONFLICT', -2); |
||
31 | define('PEAR_DEPENDENCY_UPGRADE_MINOR', -3); |
||
32 | define('PEAR_DEPENDENCY_UPGRADE_MAJOR', -4); |
||
33 | define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5); |
||
34 | define('PEAR_DEPENDENCY_MISSING_OPTIONAL', -6); |
||
35 | define('PEAR_DEPENDENCY_CONFLICT_OPTIONAL', -7); |
||
36 | define('PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL', -8); |
||
37 | define('PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL', -9); |
||
38 | |||
39 | /** |
||
40 | * Dependency check for PEAR packages |
||
41 | * |
||
42 | * The class is based on the dependency RFC that can be found at |
||
43 | * http://cvs.php.net/cvs.php/pearweb/rfc. It requires PHP >= 4.1 |
||
44 | * |
||
45 | * @author Tomas V.V.Vox <cox@idecnet.com> |
||
46 | * @author Stig Bakken <ssb@php.net> |
||
47 | */ |
||
48 | class PEAR_Dependency |
||
49 | { |
||
50 | // {{{ constructor |
||
51 | /** |
||
52 | * Constructor |
||
53 | * |
||
54 | * @access public |
||
55 | * @param object Registry object |
||
56 | * @return void |
||
57 | */ |
||
58 | function PEAR_Dependency(&$registry) |
||
59 | { |
||
60 | $this->registry = &$registry; |
||
61 | } |
||
62 | |||
63 | // }}} |
||
64 | // {{{ callCheckMethod() |
||
65 | |||
66 | /** |
||
67 | * This method maps the XML dependency definition to the |
||
68 | * corresponding one from PEAR_Dependency |
||
69 | * |
||
70 | * <pre> |
||
71 | * $opts => Array |
||
72 | * ( |
||
73 | * [type] => pkg |
||
74 | * [rel] => ge |
||
75 | * [version] => 3.4 |
||
76 | * [name] => HTML_Common |
||
77 | * [optional] => false |
||
78 | * ) |
||
79 | * </pre> |
||
80 | * |
||
81 | * @param string Error message |
||
82 | * @param array Options |
||
83 | * @return boolean |
||
84 | */ |
||
85 | function callCheckMethod(&$errmsg, $opts) |
||
86 | { |
||
87 | $rel = isset($opts['rel']) ? $opts['rel'] : 'has'; |
||
88 | $req = isset($opts['version']) ? $opts['version'] : null; |
||
89 | $name = isset($opts['name']) ? $opts['name'] : null; |
||
90 | $channel = isset($opts['channel']) ? $opts['channel'] : 'pear.php.net'; |
||
91 | $opt = (isset($opts['optional']) && $opts['optional'] == 'yes') ? |
||
92 | $opts['optional'] : null; |
||
93 | $errmsg = ''; |
||
94 | switch ($opts['type']) { |
||
95 | case 'pkg': |
||
96 | return $this->checkPackage($errmsg, $name, $req, $rel, $opt, $channel); |
||
97 | break; |
||
98 | case 'ext': |
||
99 | return $this->checkExtension($errmsg, $name, $req, $rel, $opt); |
||
100 | break; |
||
101 | case 'php': |
||
102 | return $this->checkPHP($errmsg, $req, $rel); |
||
103 | break; |
||
104 | case 'prog': |
||
105 | return $this->checkProgram($errmsg, $name); |
||
106 | break; |
||
107 | case 'os': |
||
108 | return $this->checkOS($errmsg, $name); |
||
109 | break; |
||
110 | case 'sapi': |
||
111 | return $this->checkSAPI($errmsg, $name); |
||
112 | break; |
||
113 | case 'zend': |
||
114 | return $this->checkZend($errmsg, $name); |
||
115 | break; |
||
116 | default: |
||
117 | return "'{$opts['type']}' dependency type not supported"; |
||
118 | } |
||
119 | } |
||
120 | |||
121 | // }}} |
||
122 | // {{{ checkPackage() |
||
123 | |||
124 | /** |
||
125 | * Package dependencies check method |
||
126 | * |
||
127 | * @param string $errmsg Empty string, it will be populated with an error message, if any |
||
128 | * @param string $name Name of the package to test |
||
129 | * @param string $req The package version required |
||
130 | * @param string $relation How to compare versions with each other |
||
131 | * @param bool $opt Whether the relationship is optional |
||
132 | * @param string $channel Channel name |
||
133 | * |
||
134 | * @return mixed bool false if no error or the error string |
||
135 | */ |
||
136 | function checkPackage(&$errmsg, $name, $req = null, $relation = 'has', |
||
137 | $opt = false, $channel = 'pear.php.net') |
||
138 | { |
||
139 | if (is_string($req) && substr($req, 0, 2) == 'v.') { |
||
140 | $req = substr($req, 2); |
||
141 | } |
||
142 | switch ($relation) { |
||
143 | case 'has': |
||
144 | if (!$this->registry->packageExists($name, $channel)) { |
||
145 | if ($opt) { |
||
146 | $errmsg = "package `$channel/$name' is recommended to utilize some features."; |
||
147 | return PEAR_DEPENDENCY_MISSING_OPTIONAL; |
||
148 | } |
||
149 | $errmsg = "requires package `$channel/$name'"; |
||
150 | return PEAR_DEPENDENCY_MISSING; |
||
151 | } |
||
152 | return false; |
||
153 | case 'not': |
||
154 | if ($this->registry->packageExists($name, $channel)) { |
||
155 | $errmsg = "conflicts with package `$channel/$name'"; |
||
156 | return PEAR_DEPENDENCY_CONFLICT; |
||
157 | } |
||
158 | return false; |
||
159 | case 'lt': |
||
160 | case 'le': |
||
161 | case 'eq': |
||
162 | case 'ne': |
||
163 | case 'ge': |
||
164 | case 'gt': |
||
165 | $version = $this->registry->packageInfo($name, 'version', $channel); |
||
166 | if (!$this->registry->packageExists($name, $channel) |
||
167 | || !version_compare("$version", "$req", $relation)) |
||
168 | { |
||
169 | $code = $this->codeFromRelation($relation, $version, $req, $opt); |
||
170 | if ($opt) { |
||
171 | $errmsg = "package `$channel/$name' version " . $this->signOperator($relation) . |
||
172 | " $req is recommended to utilize some features."; |
||
173 | if ($version) { |
||
174 | $errmsg .= " Installed version is $version"; |
||
175 | } |
||
176 | return $code; |
||
177 | } |
||
178 | $errmsg = "requires package `$channel/$name' " . |
||
179 | $this->signOperator($relation) . " $req"; |
||
180 | return $code; |
||
181 | } |
||
182 | return false; |
||
183 | } |
||
184 | $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$channel/$name)"; |
||
185 | return PEAR_DEPENDENCY_BAD_DEPENDENCY; |
||
186 | } |
||
187 | |||
188 | // }}} |
||
189 | // {{{ checkPackageUninstall() |
||
190 | |||
191 | /** |
||
192 | * Check package dependencies on uninstall |
||
193 | * |
||
194 | * @param string $error The resultant error string |
||
195 | * @param string $warning The resultant warning string |
||
196 | * @param string $name Name of the package to test |
||
197 | * @param string $channel Channel name of the package |
||
198 | * |
||
199 | * @return bool true if there were errors |
||
200 | */ |
||
201 | function checkPackageUninstall(&$error, &$warning, $package, $channel = 'pear.php.net') |
||
202 | { |
||
203 | $channel = strtolower($channel); |
||
204 | $error = null; |
||
205 | $channels = $this->registry->listAllPackages(); |
||
206 | foreach ($channels as $channelname => $packages) { |
||
207 | foreach ($packages as $pkg) { |
||
208 | if ($pkg == $package && $channel == $channelname) { |
||
209 | continue; |
||
210 | } |
||
211 | $deps = $this->registry->packageInfo($pkg, 'release_deps', $channel); |
||
212 | if (empty($deps)) { |
||
213 | continue; |
||
214 | } |
||
215 | foreach ($deps as $dep) { |
||
216 | $depchannel = isset($dep['channel']) ? $dep['channel'] : 'pear.php.net'; |
||
217 | if ($dep['type'] == 'pkg' && (strcasecmp($dep['name'], $package) == 0) && |
||
218 | ($depchannel == $channel)) { |
||
219 | if ($dep['rel'] == 'ne') { |
||
220 | continue; |
||
221 | } |
||
222 | if (isset($dep['optional']) && $dep['optional'] == 'yes') { |
||
223 | $warning .= "\nWarning: Package '$depchannel/$pkg' optionally depends on '$channel:/package'"; |
||
224 | } else { |
||
225 | $error .= "Package '$depchannel/$pkg' depends on '$channel/$package'\n"; |
||
226 | } |
||
227 | } |
||
228 | } |
||
229 | } |
||
230 | } |
||
231 | return ($error) ? true : false; |
||
232 | } |
||
233 | |||
234 | // }}} |
||
235 | // {{{ checkExtension() |
||
236 | |||
237 | /** |
||
238 | * Extension dependencies check method |
||
239 | * |
||
240 | * @param string $name Name of the extension to test |
||
241 | * @param string $req_ext_ver Required extension version to compare with |
||
242 | * @param string $relation How to compare versions with eachother |
||
243 | * @param bool $opt Whether the relationship is optional |
||
244 | * |
||
245 | * @return mixed bool false if no error or the error string |
||
246 | */ |
||
247 | function checkExtension(&$errmsg, $name, $req = null, $relation = 'has', |
||
248 | $opt = false) |
||
249 | { |
||
250 | if ($relation == 'not') { |
||
251 | if (extension_loaded($name)) { |
||
252 | $errmsg = "conflicts with PHP extension '$name'"; |
||
253 | return PEAR_DEPENDENCY_CONFLICT; |
||
254 | } else { |
||
255 | return false; |
||
256 | } |
||
257 | } |
||
258 | |||
259 | if (!extension_loaded($name)) { |
||
260 | if ($relation == 'ne') { |
||
261 | return false; |
||
262 | } |
||
263 | if ($opt) { |
||
264 | $errmsg = "'$name' PHP extension is recommended to utilize some features"; |
||
265 | return PEAR_DEPENDENCY_MISSING_OPTIONAL; |
||
266 | } |
||
267 | $errmsg = "'$name' PHP extension is not installed"; |
||
268 | return PEAR_DEPENDENCY_MISSING; |
||
269 | } |
||
270 | if ($relation == 'has') { |
||
271 | return false; |
||
272 | } |
||
273 | $code = false; |
||
274 | if (is_string($req) && substr($req, 0, 2) == 'v.') { |
||
275 | $req = substr($req, 2); |
||
276 | } |
||
277 | $ext_ver = phpversion($name); |
||
278 | $operator = $relation; |
||
279 | // Force params to be strings, otherwise the comparation will fail (ex. 0.9==0.90) |
||
280 | if (!version_compare("$ext_ver", "$req", $operator)) { |
||
281 | $errmsg = "'$name' PHP extension version " . |
||
282 | $this->signOperator($operator) . " $req is required"; |
||
283 | $code = $this->codeFromRelation($relation, $ext_ver, $req, $opt); |
||
284 | if ($opt) { |
||
285 | $errmsg = "'$name' PHP extension version " . $this->signOperator($operator) . |
||
286 | " $req is recommended to utilize some features"; |
||
287 | return $code; |
||
288 | } |
||
289 | } |
||
290 | return $code; |
||
291 | } |
||
292 | |||
293 | // }}} |
||
294 | // {{{ checkOS() |
||
295 | |||
296 | /** |
||
297 | * Operating system dependencies check method |
||
298 | * |
||
299 | * @param string $os Name of the operating system |
||
300 | * |
||
301 | * @return mixed bool false if no error or the error string |
||
302 | */ |
||
303 | function checkOS(&$errmsg, $os) |
||
304 | { |
||
305 | // XXX Fixme: Implement a more flexible way, like |
||
306 | // comma separated values or something similar to PEAR_OS |
||
307 | static $myos; |
||
308 | if (empty($myos)) { |
||
309 | $myos = new OS_Guess(); |
||
310 | } |
||
311 | // only 'has' relation is currently supported |
||
312 | if ($myos->matchSignature($os)) { |
||
313 | return false; |
||
314 | } |
||
315 | $errmsg = "'$os' operating system not supported"; |
||
316 | return PEAR_DEPENDENCY_CONFLICT; |
||
317 | } |
||
318 | |||
319 | // }}} |
||
320 | // {{{ checkPHP() |
||
321 | |||
322 | /** |
||
323 | * PHP version check method |
||
324 | * |
||
325 | * @param string $req which version to compare |
||
326 | * @param string $relation how to compare the version |
||
327 | * |
||
328 | * @return mixed bool false if no error or the error string |
||
329 | */ |
||
330 | function checkPHP(&$errmsg, $req, $relation = 'ge') |
||
331 | { |
||
332 | // this would be a bit stupid, but oh well :) |
||
333 | if ($relation == 'has') { |
||
334 | return false; |
||
335 | } |
||
336 | if ($relation == 'not') { |
||
337 | $errmsg = "Invalid dependency - 'not' is allowed when specifying PHP, you must run PHP in PHP"; |
||
338 | return PEAR_DEPENDENCY_BAD_DEPENDENCY; |
||
339 | } |
||
340 | if (substr($req, 0, 2) == 'v.') { |
||
341 | $req = substr($req,2, strlen($req) - 2); |
||
342 | } |
||
343 | $php_ver = phpversion(); |
||
344 | $operator = $relation; |
||
345 | if (!version_compare("$php_ver", "$req", $operator)) { |
||
346 | $errmsg = "PHP version " . $this->signOperator($operator) . |
||
347 | " $req is required"; |
||
348 | return PEAR_DEPENDENCY_CONFLICT; |
||
349 | } |
||
350 | return false; |
||
351 | } |
||
352 | |||
353 | // }}} |
||
354 | // {{{ checkProgram() |
||
355 | |||
356 | /** |
||
357 | * External program check method. Looks for executable files in |
||
358 | * directories listed in the PATH environment variable. |
||
359 | * |
||
360 | * @param string $program which program to look for |
||
361 | * |
||
362 | * @return mixed bool false if no error or the error string |
||
363 | */ |
||
364 | function checkProgram(&$errmsg, $program) |
||
365 | { |
||
366 | // XXX FIXME honor safe mode |
||
367 | $exe_suffix = OS_WINDOWS ? '.exe' : ''; |
||
368 | $path_elements = explode(PATH_SEPARATOR, getenv('PATH')); |
||
369 | foreach ($path_elements as $dir) { |
||
370 | $file = $dir . DIRECTORY_SEPARATOR . $program . $exe_suffix; |
||
371 | if (file_exists($file) && is_executable($file)) { |
||
372 | return false; |
||
373 | } |
||
374 | } |
||
375 | $errmsg = "'$program' program is not present in the PATH"; |
||
376 | return PEAR_DEPENDENCY_MISSING; |
||
377 | } |
||
378 | |||
379 | // }}} |
||
380 | // {{{ checkSAPI() |
||
381 | |||
382 | /** |
||
383 | * SAPI backend check method. Version comparison is not yet |
||
384 | * available here. |
||
385 | * |
||
386 | * @param string $name name of SAPI backend |
||
387 | * @param string $req which version to compare |
||
388 | * @param string $relation how to compare versions (currently |
||
389 | * hardcoded to 'has') |
||
390 | * @return mixed bool false if no error or the error string |
||
391 | */ |
||
392 | function checkSAPI(&$errmsg, $name, $req = null, $relation = 'has') |
||
393 | { |
||
394 | // XXX Fixme: There is no way to know if the user has or |
||
395 | // not other SAPI backends installed than the installer one |
||
396 | |||
397 | $sapi_backend = php_sapi_name(); |
||
398 | // Version comparisons not supported, sapi backends don't have |
||
399 | // version information yet. |
||
400 | if ($sapi_backend == $name) { |
||
401 | return false; |
||
402 | } |
||
403 | $errmsg = "'$sapi_backend' SAPI backend not supported"; |
||
404 | return PEAR_DEPENDENCY_CONFLICT; |
||
405 | } |
||
406 | |||
407 | // }}} |
||
408 | // {{{ checkZend() |
||
409 | |||
410 | /** |
||
411 | * Zend version check method |
||
412 | * |
||
413 | * @param string $req which version to compare |
||
414 | * @param string $relation how to compare the version |
||
415 | * |
||
416 | * @return mixed bool false if no error or the error string |
||
417 | */ |
||
418 | function checkZend(&$errmsg, $req, $relation = 'ge') |
||
419 | { |
||
420 | if (substr($req, 0, 2) == 'v.') { |
||
421 | $req = substr($req,2, strlen($req) - 2); |
||
422 | } |
||
423 | $zend_ver = zend_version(); |
||
424 | $operator = substr($relation,0,2); |
||
425 | if (!version_compare("$zend_ver", "$req", $operator)) { |
||
426 | $errmsg = "Zend version " . $this->signOperator($operator) . |
||
427 | " $req is required"; |
||
428 | return PEAR_DEPENDENCY_CONFLICT; |
||
429 | } |
||
430 | return false; |
||
431 | } |
||
432 | |||
433 | // }}} |
||
434 | // {{{ signOperator() |
||
435 | |||
436 | /** |
||
437 | * Converts text comparing operators to them sign equivalents |
||
438 | * |
||
439 | * Example: 'ge' to '>=' |
||
440 | * |
||
441 | * @access public |
||
442 | * @param string Operator |
||
443 | * @return string Sign equivalent |
||
444 | */ |
||
445 | function signOperator($operator) |
||
446 | { |
||
447 | switch($operator) { |
||
448 | case 'lt': return '<'; |
||
449 | case 'le': return '<='; |
||
450 | case 'gt': return '>'; |
||
451 | case 'ge': return '>='; |
||
452 | case 'eq': return '=='; |
||
453 | case 'ne': return '!='; |
||
454 | default: |
||
455 | return $operator; |
||
456 | } |
||
457 | } |
||
458 | |||
459 | // }}} |
||
460 | // {{{ codeFromRelation() |
||
461 | |||
462 | /** |
||
463 | * Convert relation into corresponding code |
||
464 | * |
||
465 | * @access public |
||
466 | * @param string Relation |
||
467 | * @param string Version |
||
468 | * @param string Requirement |
||
469 | * @param bool Optional dependency indicator |
||
470 | * @return integer |
||
471 | */ |
||
472 | function codeFromRelation($relation, $version, $req, $opt = false) |
||
473 | { |
||
474 | $code = PEAR_DEPENDENCY_BAD_DEPENDENCY; |
||
475 | switch ($relation) { |
||
476 | case 'gt': case 'ge': case 'eq': |
||
477 | // upgrade |
||
478 | $have_major = preg_replace('/\D.*/', '', $version); |
||
479 | $need_major = preg_replace('/\D.*/', '', $req); |
||
480 | if ($need_major > $have_major) { |
||
481 | $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL : |
||
482 | PEAR_DEPENDENCY_UPGRADE_MAJOR; |
||
483 | } else { |
||
484 | $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL : |
||
485 | PEAR_DEPENDENCY_UPGRADE_MINOR; |
||
486 | } |
||
487 | break; |
||
488 | case 'lt': case 'le': case 'ne': |
||
489 | $code = $opt ? PEAR_DEPENDENCY_CONFLICT_OPTIONAL : |
||
490 | PEAR_DEPENDENCY_CONFLICT; |
||
491 | break; |
||
492 | } |
||
493 | return $code; |
||
494 | } |
||
495 | |||
496 | // }}} |
||
497 | } |
||
498 | ?> |