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
 * PEAR_Common, the base class for the PEAR Installer
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-2006 The PHP Group
19
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
20
 * @version    CVS: $Id: Common.php,v 1.157 2006/05/12 02:38:58 cellog Exp $
21
 * @link       http://pear.php.net/package/PEAR
22
 * @since      File available since Release 0.1.0
23
 * @deprecated File deprecated since Release 1.4.0a1
24
 */
25
 
26
/**
27
 * Include error handling
28
 */
29
require_once 'PEAR.php';
30
 
31
// {{{ constants and globals
32
 
33
/**
34
 * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
35
 */
36
define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
37
define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
38
define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/');
39
 
40
// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
41
define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
42
define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '$/i');
43
 
44
// XXX far from perfect :-)
45
define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
46
    ')(-([.0-9a-zA-Z]+))?');
47
define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
48
    '$/');
49
 
50
define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
51
define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '$/');
52
 
53
// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
54
define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
55
define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '$/i');
56
 
57
define('_PEAR_CHANNELS_PACKAGE_PREG',  '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
58
         . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
59
define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '$/i');
60
 
61
define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
62
    . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
63
define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '$/');
64
 
65
/**
66
 * List of temporary files and directories registered by
67
 * PEAR_Common::addTempFile().
68
 * @var array
69
 */
70
$GLOBALS['_PEAR_Common_tempfiles'] = array();
71
 
72
/**
73
 * Valid maintainer roles
74
 * @var array
75
 */
76
$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
77
 
78
/**
79
 * Valid release states
80
 * @var array
81
 */
82
$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
83
 
84
/**
85
 * Valid dependency types
86
 * @var array
87
 */
88
$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
89
 
90
/**
91
 * Valid dependency relations
92
 * @var array
93
 */
94
$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
95
 
96
/**
97
 * Valid file roles
98
 * @var array
99
 */
100
$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
101
 
102
/**
103
 * Valid replacement types
104
 * @var array
105
 */
106
$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
107
 
108
/**
109
 * Valid "provide" types
110
 * @var array
111
 */
112
$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
113
 
114
/**
115
 * Valid "provide" types
116
 * @var array
117
 */
118
$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
119
 
120
// }}}
121
 
122
/**
123
 * Class providing common functionality for PEAR administration classes.
124
 * @category   pear
125
 * @package    PEAR
126
 * @author     Stig Bakken <ssb@php.net>
127
 * @author     Tomas V. V. Cox <cox@idecnet.com>
128
 * @author     Greg Beaver <cellog@php.net>
129
 * @copyright  1997-2006 The PHP Group
130
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
131
 * @version    Release: 1.5.1
132
 * @link       http://pear.php.net/package/PEAR
133
 * @since      Class available since Release 1.4.0a1
134
 * @deprecated This class will disappear, and its components will be spread
135
 *             into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
136
 */
137
class PEAR_Common extends PEAR
138
{
139
    // {{{ properties
140
 
141
    /** stack of elements, gives some sort of XML context */
142
    var $element_stack = array();
143
 
144
    /** name of currently parsed XML element */
145
    var $current_element;
146
 
147
    /** array of attributes of the currently parsed XML element */
148
    var $current_attributes = array();
149
 
150
    /** assoc with information about a package */
151
    var $pkginfo = array();
152
 
153
    /**
154
     * User Interface object (PEAR_Frontend_* class).  If null,
155
     * the log() method uses print.
156
     * @var object
157
     */
158
    var $ui = null;
159
 
160
    /**
161
     * Configuration object (PEAR_Config).
162
     * @var object
163
     */
164
    var $config = null;
165
 
166
    var $current_path = null;
167
 
168
    /**
169
     * PEAR_SourceAnalyzer instance
170
     * @var object
171
     */
172
    var $source_analyzer = null;
173
    /**
174
     * Flag variable used to mark a valid package file
175
     * @var boolean
176
     * @access private
177
     */
178
    var $_validPackageFile;
179
 
180
    // }}}
181
 
182
    // {{{ constructor
183
 
184
    /**
185
     * PEAR_Common constructor
186
     *
187
     * @access public
188
     */
189
    function PEAR_Common()
190
    {
191
        parent::PEAR();
192
        $this->config = &PEAR_Config::singleton();
193
        $this->debug = $this->config->get('verbose');
194
    }
195
 
196
    // }}}
197
    // {{{ destructor
198
 
199
    /**
200
     * PEAR_Common destructor
201
     *
202
     * @access private
203
     */
204
    function _PEAR_Common()
205
    {
206
        // doesn't work due to bug #14744
207
        //$tempfiles = $this->_tempfiles;
208
        $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
209
        while ($file = array_shift($tempfiles)) {
210
            if (@is_dir($file)) {
211
                if (!class_exists('System')) {
212
                    require_once 'System.php';
213
                }
214
                System::rm(array('-rf', $file));
215
            } elseif (file_exists($file)) {
216
                unlink($file);
217
            }
218
        }
219
    }
220
 
221
    // }}}
222
    // {{{ addTempFile()
223
 
224
    /**
225
     * Register a temporary file or directory.  When the destructor is
226
     * executed, all registered temporary files and directories are
227
     * removed.
228
     *
229
     * @param string  $file  name of file or directory
230
     *
231
     * @return void
232
     *
233
     * @access public
234
     */
235
    function addTempFile($file)
236
    {
237
        if (!class_exists('PEAR_Frontend')) {
238
            require_once 'PEAR/Frontend.php';
239
        }
240
        PEAR_Frontend::addTempFile($file);
241
    }
242
 
243
    // }}}
244
    // {{{ mkDirHier()
245
 
246
    /**
247
     * Wrapper to System::mkDir(), creates a directory as well as
248
     * any necessary parent directories.
249
     *
250
     * @param string  $dir  directory name
251
     *
252
     * @return bool TRUE on success, or a PEAR error
253
     *
254
     * @access public
255
     */
256
    function mkDirHier($dir)
257
    {
258
        $this->log(2, "+ create dir $dir");
259
        if (!class_exists('System')) {
260
            require_once 'System.php';
261
        }
262
        return System::mkDir(array('-p', $dir));
263
    }
264
 
265
    // }}}
266
    // {{{ log()
267
 
268
    /**
269
     * Logging method.
270
     *
271
     * @param int    $level  log level (0 is quiet, higher is noisier)
272
     * @param string $msg    message to write to the log
273
     *
274
     * @return void
275
     *
276
     * @access public
277
     * @static
278
     */
279
    function log($level, $msg, $append_crlf = true)
280
    {
281
        if ($this->debug >= $level) {
282
            if (!class_exists('PEAR_Frontend')) {
283
                require_once 'PEAR/Frontend.php';
284
            }
285
            $ui = &PEAR_Frontend::singleton();
286
            if (is_a($ui, 'PEAR_Frontend')) {
287
                $ui->log($msg, $append_crlf);
288
            } else {
289
                print "$msg\n";
290
            }
291
        }
292
    }
293
 
294
    // }}}
295
    // {{{ mkTempDir()
296
 
297
    /**
298
     * Create and register a temporary directory.
299
     *
300
     * @param string $tmpdir (optional) Directory to use as tmpdir.
301
     *                       Will use system defaults (for example
302
     *                       /tmp or c:\windows\temp) if not specified
303
     *
304
     * @return string name of created directory
305
     *
306
     * @access public
307
     */
308
    function mkTempDir($tmpdir = '')
309
    {
310
        if ($tmpdir) {
311
            $topt = array('-t', $tmpdir);
312
        } else {
313
            $topt = array();
314
        }
315
        $topt = array_merge($topt, array('-d', 'pear'));
316
        if (!class_exists('System')) {
317
            require_once 'System.php';
318
        }
319
        if (!$tmpdir = System::mktemp($topt)) {
320
            return false;
321
        }
322
        $this->addTempFile($tmpdir);
323
        return $tmpdir;
324
    }
325
 
326
    // }}}
327
    // {{{ setFrontendObject()
328
 
329
    /**
330
     * Set object that represents the frontend to be used.
331
     *
332
     * @param  object Reference of the frontend object
333
     * @return void
334
     * @access public
335
     */
336
    function setFrontendObject(&$ui)
337
    {
338
        $this->ui = &$ui;
339
    }
340
 
341
    // }}}
342
 
343
    // {{{ infoFromTgzFile()
344
 
345
    /**
346
     * Returns information about a package file.  Expects the name of
347
     * a gzipped tar file as input.
348
     *
349
     * @param string  $file  name of .tgz file
350
     *
351
     * @return array  array with package information
352
     *
353
     * @access public
354
     * @deprecated use PEAR_PackageFile->fromTgzFile() instead
355
     *
356
     */
357
    function infoFromTgzFile($file)
358
    {
359
        $packagefile = &new PEAR_PackageFile($this->config);
360
        $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
361
        if (PEAR::isError($pf)) {
362
            $errs = $pf->getUserinfo();
363
            if (is_array($errs)) {
364
                foreach ($errs as $error) {
365
                    $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
366
                }
367
            }
368
            return $pf;
369
        }
370
        return $this->_postProcessValidPackagexml($pf);
371
    }
372
 
373
    // }}}
374
    // {{{ infoFromDescriptionFile()
375
 
376
    /**
377
     * Returns information about a package file.  Expects the name of
378
     * a package xml file as input.
379
     *
380
     * @param string  $descfile  name of package xml file
381
     *
382
     * @return array  array with package information
383
     *
384
     * @access public
385
     * @deprecated use PEAR_PackageFile->fromPackageFile() instead
386
     *
387
     */
388
    function infoFromDescriptionFile($descfile)
389
    {
390
        $packagefile = &new PEAR_PackageFile($this->config);
391
        $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
392
        if (PEAR::isError($pf)) {
393
            $errs = $pf->getUserinfo();
394
            if (is_array($errs)) {
395
                foreach ($errs as $error) {
396
                    $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
397
                }
398
            }
399
            return $pf;
400
        }
401
        return $this->_postProcessValidPackagexml($pf);
402
    }
403
 
404
    // }}}
405
    // {{{ infoFromString()
406
 
407
    /**
408
     * Returns information about a package file.  Expects the contents
409
     * of a package xml file as input.
410
     *
411
     * @param string  $data  contents of package.xml file
412
     *
413
     * @return array   array with package information
414
     *
415
     * @access public
416
     * @deprecated use PEAR_PackageFile->fromXmlstring() instead
417
     *
418
     */
419
    function infoFromString($data)
420
    {
421
        $packagefile = &new PEAR_PackageFile($this->config);
422
        $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
423
        if (PEAR::isError($pf)) {
424
            $errs = $pf->getUserinfo();
425
            if (is_array($errs)) {
426
                foreach ($errs as $error) {
427
                    $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
428
                }
429
            }
430
            return $pf;
431
        }
432
        return $this->_postProcessValidPackagexml($pf);
433
    }
434
    // }}}
435
 
436
    /**
437
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
438
     * @return array
439
     */
440
    function _postProcessValidPackagexml(&$pf)
441
    {
442
        if (is_a($pf, 'PEAR_PackageFile_v2')) {
443
            // sort of make this into a package.xml 1.0-style array
444
            // changelog is not converted to old format.
445
            $arr = $pf->toArray(true);
446
            $arr = array_merge($arr, $arr['old']);
447
            unset($arr['old']);
448
            unset($arr['xsdversion']);
449
            unset($arr['contents']);
450
            unset($arr['compatible']);
451
            unset($arr['channel']);
452
            unset($arr['uri']);
453
            unset($arr['dependencies']);
454
            unset($arr['phprelease']);
455
            unset($arr['extsrcrelease']);
456
            unset($arr['zendextsrcrelease']);
457
            unset($arr['extbinrelease']);
458
            unset($arr['zendextbinrelease']);
459
            unset($arr['bundle']);
460
            unset($arr['lead']);
461
            unset($arr['developer']);
462
            unset($arr['helper']);
463
            unset($arr['contributor']);
464
            $arr['filelist'] = $pf->getFilelist();
465
            $this->pkginfo = $arr;
466
            return $arr;
467
        } else {
468
            $this->pkginfo = $pf->toArray();
469
            return $this->pkginfo;
470
        }
471
    }
472
    // {{{ infoFromAny()
473
 
474
    /**
475
     * Returns package information from different sources
476
     *
477
     * This method is able to extract information about a package
478
     * from a .tgz archive or from a XML package definition file.
479
     *
480
     * @access public
481
     * @param  string Filename of the source ('package.xml', '<package>.tgz')
482
     * @return string
483
     * @deprecated use PEAR_PackageFile->fromAnyFile() instead
484
     */
485
    function infoFromAny($info)
486
    {
487
        if (is_string($info) && file_exists($info)) {
488
            $packagefile = &new PEAR_PackageFile($this->config);
489
            $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
490
            if (PEAR::isError($pf)) {
491
                $errs = $pf->getUserinfo();
492
                if (is_array($errs)) {
493
                    foreach ($errs as $error) {
494
                        $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
495
                    }
496
                }
497
                return $pf;
498
            }
499
            return $this->_postProcessValidPackagexml($pf);
500
        }
501
        return $info;
502
    }
503
 
504
    // }}}
505
    // {{{ xmlFromInfo()
506
 
507
    /**
508
     * Return an XML document based on the package info (as returned
509
     * by the PEAR_Common::infoFrom* methods).
510
     *
511
     * @param array  $pkginfo  package info
512
     *
513
     * @return string XML data
514
     *
515
     * @access public
516
     * @deprecated use a PEAR_PackageFile_v* object's generator instead
517
     */
518
    function xmlFromInfo($pkginfo)
519
    {
520
        $config = &PEAR_Config::singleton();
521
        $packagefile = &new PEAR_PackageFile($config);
522
        $pf = &$packagefile->fromArray($pkginfo);
523
        $gen = &$pf->getDefaultGenerator();
524
        return $gen->toXml(PEAR_VALIDATE_PACKAGING);
525
    }
526
 
527
    // }}}
528
    // {{{ validatePackageInfo()
529
 
530
    /**
531
     * Validate XML package definition file.
532
     *
533
     * @param  string $info Filename of the package archive or of the
534
     *                package definition file
535
     * @param  array $errors Array that will contain the errors
536
     * @param  array $warnings Array that will contain the warnings
537
     * @param  string $dir_prefix (optional) directory where source files
538
     *                may be found, or empty if they are not available
539
     * @access public
540
     * @return boolean
541
     * @deprecated use the validation of PEAR_PackageFile objects
542
     */
543
    function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
544
    {
545
        $config = &PEAR_Config::singleton();
546
        $packagefile = &new PEAR_PackageFile($config);
547
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
548
        if (strpos($info, '<?xml') !== false) {
549
            $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
550
        } else {
551
            $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
552
        }
553
        PEAR::staticPopErrorHandling();
554
        if (PEAR::isError($pf)) {
555
            $errs = $pf->getUserinfo();
556
            if (is_array($errs)) {
557
                foreach ($errs as $error) {
558
                    if ($error['level'] == 'error') {
559
                        $errors[] = $error['message'];
560
                    } else {
561
                        $warnings[] = $error['message'];
562
                    }
563
                }
564
            }
565
            return false;
566
        }
567
        return true;
568
    }
569
 
570
    // }}}
571
    // {{{ buildProvidesArray()
572
 
573
    /**
574
     * Build a "provides" array from data returned by
575
     * analyzeSourceCode().  The format of the built array is like
576
     * this:
577
     *
578
     *  array(
579
     *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
580
     *    ...
581
     *  )
582
     *
583
     *
584
     * @param array $srcinfo array with information about a source file
585
     * as returned by the analyzeSourceCode() method.
586
     *
587
     * @return void
588
     *
589
     * @access public
590
     *
591
     */
592
    function buildProvidesArray($srcinfo)
593
    {
594
        $file = basename($srcinfo['source_file']);
595
        $pn = '';
596
        if (isset($this->_packageName)) {
597
            $pn = $this->_packageName;
598
        }
599
        $pnl = strlen($pn);
600
        foreach ($srcinfo['declared_classes'] as $class) {
601
            $key = "class;$class";
602
            if (isset($this->pkginfo['provides'][$key])) {
603
                continue;
604
            }
605
            $this->pkginfo['provides'][$key] =
606
                array('file'=> $file, 'type' => 'class', 'name' => $class);
607
            if (isset($srcinfo['inheritance'][$class])) {
608
                $this->pkginfo['provides'][$key]['extends'] =
609
                    $srcinfo['inheritance'][$class];
610
            }
611
        }
612
        foreach ($srcinfo['declared_methods'] as $class => $methods) {
613
            foreach ($methods as $method) {
614
                $function = "$class::$method";
615
                $key = "function;$function";
616
                if ($method{0} == '_' || !strcasecmp($method, $class) ||
617
                    isset($this->pkginfo['provides'][$key])) {
618
                    continue;
619
                }
620
                $this->pkginfo['provides'][$key] =
621
                    array('file'=> $file, 'type' => 'function', 'name' => $function);
622
            }
623
        }
624
 
625
        foreach ($srcinfo['declared_functions'] as $function) {
626
            $key = "function;$function";
627
            if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
628
                continue;
629
            }
630
            if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
631
                $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
632
            }
633
            $this->pkginfo['provides'][$key] =
634
                array('file'=> $file, 'type' => 'function', 'name' => $function);
635
        }
636
    }
637
 
638
    // }}}
639
    // {{{ analyzeSourceCode()
640
 
641
    /**
642
     * Analyze the source code of the given PHP file
643
     *
644
     * @param  string Filename of the PHP file
645
     * @return mixed
646
     * @access public
647
     */
648
    function analyzeSourceCode($file)
649
    {
650
        if (!function_exists("token_get_all")) {
651
            return false;
652
        }
653
        if (!defined('T_DOC_COMMENT')) {
654
            define('T_DOC_COMMENT', T_COMMENT);
655
        }
656
        if (!defined('T_INTERFACE')) {
657
            define('T_INTERFACE', -1);
658
        }
659
        if (!defined('T_IMPLEMENTS')) {
660
            define('T_IMPLEMENTS', -1);
661
        }
662
        if (!$fp = @fopen($file, "r")) {
663
            return false;
664
        }
665
        fclose($fp);
666
        $contents = file_get_contents($file);
667
        $tokens = token_get_all($contents);
668
/*
669
        for ($i = 0; $i < sizeof($tokens); $i++) {
670
            @list($token, $data) = $tokens[$i];
671
            if (is_string($token)) {
672
                var_dump($token);
673
            } else {
674
                print token_name($token) . ' ';
675
                var_dump(rtrim($data));
676
            }
677
        }
678
*/
679
        $look_for = 0;
680
        $paren_level = 0;
681
        $bracket_level = 0;
682
        $brace_level = 0;
683
        $lastphpdoc = '';
684
        $current_class = '';
685
        $current_interface = '';
686
        $current_class_level = -1;
687
        $current_function = '';
688
        $current_function_level = -1;
689
        $declared_classes = array();
690
        $declared_interfaces = array();
691
        $declared_functions = array();
692
        $declared_methods = array();
693
        $used_classes = array();
694
        $used_functions = array();
695
        $extends = array();
696
        $implements = array();
697
        $nodeps = array();
698
        $inquote = false;
699
        $interface = false;
700
        for ($i = 0; $i < sizeof($tokens); $i++) {
701
            if (is_array($tokens[$i])) {
702
                list($token, $data) = $tokens[$i];
703
            } else {
704
                $token = $tokens[$i];
705
                $data = '';
706
            }
707
            if ($inquote) {
708
                if ($token != '"') {
709
                    continue;
710
                } else {
711
                    $inquote = false;
712
                    continue;
713
                }
714
            }
715
            switch ($token) {
716
                case T_WHITESPACE:
717
                    continue;
718
                case ';':
719
                    if ($interface) {
720
                        $current_function = '';
721
                        $current_function_level = -1;
722
                    }
723
                    break;
724
                case '"':
725
                    $inquote = true;
726
                    break;
727
                case T_CURLY_OPEN:
728
                case T_DOLLAR_OPEN_CURLY_BRACES:
729
                case '{': $brace_level++; continue 2;
730
                case '}':
731
                    $brace_level--;
732
                    if ($current_class_level == $brace_level) {
733
                        $current_class = '';
734
                        $current_class_level = -1;
735
                    }
736
                    if ($current_function_level == $brace_level) {
737
                        $current_function = '';
738
                        $current_function_level = -1;
739
                    }
740
                    continue 2;
741
                case '[': $bracket_level++; continue 2;
742
                case ']': $bracket_level--; continue 2;
743
                case '(': $paren_level++;   continue 2;
744
                case ')': $paren_level--;   continue 2;
745
                case T_INTERFACE:
746
                    $interface = true;
747
                case T_CLASS:
748
                    if (($current_class_level != -1) || ($current_function_level != -1)) {
749
                        PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
750
                            PEAR_COMMON_ERROR_INVALIDPHP);
751
                        return false;
752
                    }
753
                case T_FUNCTION:
754
                case T_NEW:
755
                case T_EXTENDS:
756
                case T_IMPLEMENTS:
757
                    $look_for = $token;
758
                    continue 2;
759
                case T_STRING:
760
                    if (version_compare(zend_version(), '2.0', '<')) {
761
                        if (in_array(strtolower($data),
762
                            array('public', 'private', 'protected', 'abstract',
763
                                  'interface', 'implements', 'throw')
764
                                 )) {
765
                            PEAR::raiseError('Error: PHP5 token encountered in ' . $file .
766
                            'packaging should be done in PHP 5');
767
                            return false;
768
                        }
769
                    }
770
                    if ($look_for == T_CLASS) {
771
                        $current_class = $data;
772
                        $current_class_level = $brace_level;
773
                        $declared_classes[] = $current_class;
774
                    } elseif ($look_for == T_INTERFACE) {
775
                        $current_interface = $data;
776
                        $current_class_level = $brace_level;
777
                        $declared_interfaces[] = $current_interface;
778
                    } elseif ($look_for == T_IMPLEMENTS) {
779
                        $implements[$current_class] = $data;
780
                    } elseif ($look_for == T_EXTENDS) {
781
                        $extends[$current_class] = $data;
782
                    } elseif ($look_for == T_FUNCTION) {
783
                        if ($current_class) {
784
                            $current_function = "$current_class::$data";
785
                            $declared_methods[$current_class][] = $data;
786
                        } elseif ($current_interface) {
787
                            $current_function = "$current_interface::$data";
788
                            $declared_methods[$current_interface][] = $data;
789
                        } else {
790
                            $current_function = $data;
791
                            $declared_functions[] = $current_function;
792
                        }
793
                        $current_function_level = $brace_level;
794
                        $m = array();
795
                    } elseif ($look_for == T_NEW) {
796
                        $used_classes[$data] = true;
797
                    }
798
                    $look_for = 0;
799
                    continue 2;
800
                case T_VARIABLE:
801
                    $look_for = 0;
802
                    continue 2;
803
                case T_DOC_COMMENT:
804
                case T_COMMENT:
805
                    if (preg_match('!^/\*\*\s!', $data)) {
806
                        $lastphpdoc = $data;
807
                        if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
808
                            $nodeps = array_merge($nodeps, $m[1]);
809
                        }
810
                    }
811
                    continue 2;
812
                case T_DOUBLE_COLON:
813
                    if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
814
                        PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
815
                            PEAR_COMMON_ERROR_INVALIDPHP);
816
                        return false;
817
                    }
818
                    $class = $tokens[$i - 1][1];
819
                    if (strtolower($class) != 'parent') {
820
                        $used_classes[$class] = true;
821
                    }
822
                    continue 2;
823
            }
824
        }
825
        return array(
826
            "source_file" => $file,
827
            "declared_classes" => $declared_classes,
828
            "declared_interfaces" => $declared_interfaces,
829
            "declared_methods" => $declared_methods,
830
            "declared_functions" => $declared_functions,
831
            "used_classes" => array_diff(array_keys($used_classes), $nodeps),
832
            "inheritance" => $extends,
833
            "implements" => $implements,
834
            );
835
    }
836
 
837
    // }}}
838
    // {{{  betterStates()
839
 
840
    /**
841
     * Return an array containing all of the states that are more stable than
842
     * or equal to the passed in state
843
     *
844
     * @param string Release state
845
     * @param boolean Determines whether to include $state in the list
846
     * @return false|array False if $state is not a valid release state
847
     */
848
    function betterStates($state, $include = false)
849
    {
850
        static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
851
        $i = array_search($state, $states);
852
        if ($i === false) {
853
            return false;
854
        }
855
        if ($include) {
856
            $i--;
857
        }
858
        return array_slice($states, $i + 1);
859
    }
860
 
861
    // }}}
862
    // {{{ detectDependencies()
863
 
864
    function detectDependencies($any, $status_callback = null)
865
    {
866
        if (!function_exists("token_get_all")) {
867
            return false;
868
        }
869
        if (PEAR::isError($info = $this->infoFromAny($any))) {
870
            return $this->raiseError($info);
871
        }
872
        if (!is_array($info)) {
873
            return false;
874
        }
875
        $deps = array();
876
        $used_c = $decl_c = $decl_f = $decl_m = array();
877
        foreach ($info['filelist'] as $file => $fa) {
878
            $tmp = $this->analyzeSourceCode($file);
879
            $used_c = @array_merge($used_c, $tmp['used_classes']);
880
            $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
881
            $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
882
            $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
883
            $inheri = @array_merge($inheri, $tmp['inheritance']);
884
        }
885
        $used_c = array_unique($used_c);
886
        $decl_c = array_unique($decl_c);
887
        $undecl_c = array_diff($used_c, $decl_c);
888
        return array('used_classes' => $used_c,
889
                     'declared_classes' => $decl_c,
890
                     'declared_methods' => $decl_m,
891
                     'declared_functions' => $decl_f,
892
                     'undeclared_classes' => $undecl_c,
893
                     'inheritance' => $inheri,
894
                     );
895
    }
896
 
897
    // }}}
898
    // {{{ getUserRoles()
899
 
900
    /**
901
     * Get the valid roles for a PEAR package maintainer
902
     *
903
     * @return array
904
     * @static
905
     */
906
    function getUserRoles()
907
    {
908
        return $GLOBALS['_PEAR_Common_maintainer_roles'];
909
    }
910
 
911
    // }}}
912
    // {{{ getReleaseStates()
913
 
914
    /**
915
     * Get the valid package release states of packages
916
     *
917
     * @return array
918
     * @static
919
     */
920
    function getReleaseStates()
921
    {
922
        return $GLOBALS['_PEAR_Common_release_states'];
923
    }
924
 
925
    // }}}
926
    // {{{ getDependencyTypes()
927
 
928
    /**
929
     * Get the implemented dependency types (php, ext, pkg etc.)
930
     *
931
     * @return array
932
     * @static
933
     */
934
    function getDependencyTypes()
935
    {
936
        return $GLOBALS['_PEAR_Common_dependency_types'];
937
    }
938
 
939
    // }}}
940
    // {{{ getDependencyRelations()
941
 
942
    /**
943
     * Get the implemented dependency relations (has, lt, ge etc.)
944
     *
945
     * @return array
946
     * @static
947
     */
948
    function getDependencyRelations()
949
    {
950
        return $GLOBALS['_PEAR_Common_dependency_relations'];
951
    }
952
 
953
    // }}}
954
    // {{{ getFileRoles()
955
 
956
    /**
957
     * Get the implemented file roles
958
     *
959
     * @return array
960
     * @static
961
     */
962
    function getFileRoles()
963
    {
964
        return $GLOBALS['_PEAR_Common_file_roles'];
965
    }
966
 
967
    // }}}
968
    // {{{ getReplacementTypes()
969
 
970
    /**
971
     * Get the implemented file replacement types in
972
     *
973
     * @return array
974
     * @static
975
     */
976
    function getReplacementTypes()
977
    {
978
        return $GLOBALS['_PEAR_Common_replacement_types'];
979
    }
980
 
981
    // }}}
982
    // {{{ getProvideTypes()
983
 
984
    /**
985
     * Get the implemented file replacement types in
986
     *
987
     * @return array
988
     * @static
989
     */
990
    function getProvideTypes()
991
    {
992
        return $GLOBALS['_PEAR_Common_provide_types'];
993
    }
994
 
995
    // }}}
996
    // {{{ getScriptPhases()
997
 
998
    /**
999
     * Get the implemented file replacement types in
1000
     *
1001
     * @return array
1002
     * @static
1003
     */
1004
    function getScriptPhases()
1005
    {
1006
        return $GLOBALS['_PEAR_Common_script_phases'];
1007
    }
1008
 
1009
    // }}}
1010
    // {{{ validPackageName()
1011
 
1012
    /**
1013
     * Test whether a string contains a valid package name.
1014
     *
1015
     * @param string $name the package name to test
1016
     *
1017
     * @return bool
1018
     *
1019
     * @access public
1020
     */
1021
    function validPackageName($name)
1022
    {
1023
        return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
1024
    }
1025
 
1026
 
1027
    // }}}
1028
    // {{{ validPackageVersion()
1029
 
1030
    /**
1031
     * Test whether a string contains a valid package version.
1032
     *
1033
     * @param string $ver the package version to test
1034
     *
1035
     * @return bool
1036
     *
1037
     * @access public
1038
     */
1039
    function validPackageVersion($ver)
1040
    {
1041
        return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
1042
    }
1043
 
1044
 
1045
    // }}}
1046
 
1047
    // {{{ downloadHttp()
1048
 
1049
    /**
1050
     * Download a file through HTTP.  Considers suggested file name in
1051
     * Content-disposition: header and can run a callback function for
1052
     * different events.  The callback will be called with two
1053
     * parameters: the callback type, and parameters.  The implemented
1054
     * callback types are:
1055
     *
1056
     *  'setup'       called at the very beginning, parameter is a UI object
1057
     *                that should be used for all output
1058
     *  'message'     the parameter is a string with an informational message
1059
     *  'saveas'      may be used to save with a different file name, the
1060
     *                parameter is the filename that is about to be used.
1061
     *                If a 'saveas' callback returns a non-empty string,
1062
     *                that file name will be used as the filename instead.
1063
     *                Note that $save_dir will not be affected by this, only
1064
     *                the basename of the file.
1065
     *  'start'       download is starting, parameter is number of bytes
1066
     *                that are expected, or -1 if unknown
1067
     *  'bytesread'   parameter is the number of bytes read so far
1068
     *  'done'        download is complete, parameter is the total number
1069
     *                of bytes read
1070
     *  'connfailed'  if the TCP connection fails, this callback is called
1071
     *                with array(host,port,errno,errmsg)
1072
     *  'writefailed' if writing to disk fails, this callback is called
1073
     *                with array(destfile,errmsg)
1074
     *
1075
     * If an HTTP proxy has been configured (http_proxy PEAR_Config
1076
     * setting), the proxy will be used.
1077
     *
1078
     * @param string  $url       the URL to download
1079
     * @param object  $ui        PEAR_Frontend_* instance
1080
     * @param object  $config    PEAR_Config instance
1081
     * @param string  $save_dir  (optional) directory to save file in
1082
     * @param mixed   $callback  (optional) function/method to call for status
1083
     *                           updates
1084
     *
1085
     * @return string  Returns the full path of the downloaded file or a PEAR
1086
     *                 error on failure.  If the error is caused by
1087
     *                 socket-related errors, the error object will
1088
     *                 have the fsockopen error code available through
1089
     *                 getCode().
1090
     *
1091
     * @access public
1092
     * @deprecated in favor of PEAR_Downloader::downloadHttp()
1093
     */
1094
    function downloadHttp($url, &$ui, $save_dir = '.', $callback = null)
1095
    {
1096
        if (!class_exists('PEAR_Downloader')) {
1097
            require_once 'PEAR/Downloader.php';
1098
        }
1099
        return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback);
1100
    }
1101
 
1102
    // }}}
1103
 
1104
    /**
1105
     * @param string $path relative or absolute include path
1106
     * @return boolean
1107
     * @static
1108
     */
1109
    function isIncludeable($path)
1110
    {
1111
        if (file_exists($path) && is_readable($path)) {
1112
            return true;
1113
        }
1114
        $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
1115
        foreach ($ipath as $include) {
1116
            $test = realpath($include . DIRECTORY_SEPARATOR . $path);
1117
            if (file_exists($test) && is_readable($test)) {
1118
                return true;
1119
            }
1120
        }
1121
        return false;
1122
    }
1123
}
1124
require_once 'PEAR/Config.php';
1125
require_once 'PEAR/PackageFile.php';
1126
?>