Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

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