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_Validate
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     Greg Beaver <cellog@php.net>
16
 * @copyright  1997-2006 The PHP Group
17
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
18
 * @version    CVS: $Id: Validate.php,v 1.50 2006/09/25 05:12:21 cellog Exp $
19
 * @link       http://pear.php.net/package/PEAR
20
 * @since      File available since Release 1.4.0a1
21
 */
22
/**#@+
23
 * Constants for install stage
24
 */
25
define('PEAR_VALIDATE_INSTALLING', 1);
26
define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others
27
define('PEAR_VALIDATE_NORMAL', 3);
28
define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others
29
define('PEAR_VALIDATE_PACKAGING', 7);
30
/**#@-*/
31
require_once 'PEAR/Common.php';
32
require_once 'PEAR/Validator/PECL.php';
33
 
34
/**
35
 * Validation class for package.xml - channel-level advanced validation
36
 * @category   pear
37
 * @package    PEAR
38
 * @author     Greg Beaver <cellog@php.net>
39
 * @copyright  1997-2006 The PHP Group
40
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
41
 * @version    Release: 1.5.1
42
 * @link       http://pear.php.net/package/PEAR
43
 * @since      Class available since Release 1.4.0a1
44
 */
45
class PEAR_Validate
46
{
47
    var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG;
48
    /**
49
     * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2
50
     */
51
    var $_packagexml;
52
    /**
53
     * @var int one of the PEAR_VALIDATE_* constants
54
     */
55
    var $_state = PEAR_VALIDATE_NORMAL;
56
    /**
57
     * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same)
58
     * @var array
59
     * @access private
60
     */
61
    var $_failures = array('error' => array(), 'warning' => array());
62
 
63
    /**
64
     * Override this method to handle validation of normal package names
65
     * @param string
66
     * @return bool
67
     * @access protected
68
     */
69
    function _validPackageName($name)
70
    {
71
        return (bool) preg_match('/^' . $this->packageregex . '$/', $name);
72
    }
73
 
74
    /**
75
     * @param string package name to validate
76
     * @param string name of channel-specific validation package
77
     * @final
78
     */
79
    function validPackageName($name, $validatepackagename = false)
80
    {
81
        if ($validatepackagename) {
82
            if (strtolower($name) == strtolower($validatepackagename)) {
83
                return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*$/', $name);
84
            }
85
        }
86
        return $this->_validPackageName($name);
87
    }
88
 
89
    /**
90
     * This validates a bundle name, and bundle names must conform
91
     * to the PEAR naming convention, so the method is final and static.
92
     * @param string
93
     * @final
94
     * @static
95
     */
96
    function validGroupName($name)
97
    {
98
        return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/', $name);
99
    }
100
 
101
    /**
102
     * Determine whether $state represents a valid stability level
103
     * @param string
104
     * @return bool
105
     * @static
106
     * @final
107
     */
108
    function validState($state)
109
    {
110
        return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable'));
111
    }
112
 
113
    /**
114
     * Get a list of valid stability levels
115
     * @return array
116
     * @static
117
     * @final
118
     */
119
    function getValidStates()
120
    {
121
        return array('snapshot', 'devel', 'alpha', 'beta', 'stable');
122
    }
123
 
124
    /**
125
     * Determine whether a version is a properly formatted version number that can be used
126
     * by version_compare
127
     * @param string
128
     * @return bool
129
     * @static
130
     * @final
131
     */
132
    function validVersion($ver)
133
    {
134
        return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
135
    }
136
 
137
    /**
138
     * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
139
     */
140
    function setPackageFile(&$pf)
141
    {
142
        $this->_packagexml = &$pf;
143
    }
144
 
145
    /**
146
     * @access private
147
     */
148
    function _addFailure($field, $reason)
149
    {
150
        $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason);
151
    }
152
 
153
    /**
154
     * @access private
155
     */
156
    function _addWarning($field, $reason)
157
    {
158
        $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason);
159
    }
160
 
161
    function getFailures()
162
    {
163
        $failures = $this->_failures;
164
        $this->_failures = array('warnings' => array(), 'errors' => array());
165
        return $failures;
166
    }
167
 
168
    /**
169
     * @param int one of the PEAR_VALIDATE_* constants
170
     */
171
    function validate($state = null)
172
    {
173
        if (!isset($this->_packagexml)) {
174
            return false;
175
        }
176
        if ($state !== null) {
177
            $this->_state = $state;
178
        }
179
        $this->_failures = array('warnings' => array(), 'errors' => array());
180
        $this->validatePackageName();
181
        $this->validateVersion();
182
        $this->validateMaintainers();
183
        $this->validateDate();
184
        $this->validateSummary();
185
        $this->validateDescription();
186
        $this->validateLicense();
187
        $this->validateNotes();
188
        if ($this->_packagexml->getPackagexmlVersion() == '1.0') {
189
            $this->validateState();
190
            $this->validateFilelist();
191
        } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' ||
192
                  $this->_packagexml->getPackagexmlVersion() == '2.1') {
193
            $this->validateTime();
194
            $this->validateStability();
195
            $this->validateDeps();
196
            $this->validateMainFilelist();
197
            $this->validateReleaseFilelist();
198
            //$this->validateGlobalTasks();
199
            $this->validateChangelog();
200
        }
201
        return !((bool) count($this->_failures['errors']));
202
    }
203
 
204
    /**
205
     * @access protected
206
     */
207
    function validatePackageName()
208
    {
209
        if ($this->_state == PEAR_VALIDATE_PACKAGING ||
210
              $this->_state == PEAR_VALIDATE_NORMAL) {
211
            if (($this->_packagexml->getPackagexmlVersion() == '2.0' ||
212
                 $this->_packagexml->getPackagexmlVersion() == '2.1') &&
213
                  $this->_packagexml->getExtends()) {
214
                $version = $this->_packagexml->getVersion() . '';
215
                $name = $this->_packagexml->getPackage();
216
                $test = array_shift($a = explode('.', $version));
217
                if ($test == '0') {
218
                    return true;
219
                }
220
                $vlen = strlen($test);
221
                $majver = substr($name, strlen($name) - $vlen);
222
                while ($majver && !is_numeric($majver{0})) {
223
                    $majver = substr($majver, 1);
224
                }
225
                if ($majver != $test) {
226
                    $this->_addWarning('package', "package $name extends package " .
227
                        $this->_packagexml->getExtends() . ' and so the name should ' .
228
                        'have a postfix equal to the major version like "' .
229
                        $this->_packagexml->getExtends() . $test . '"');
230
                    return true;
231
                } elseif (substr($name, 0, strlen($name) - $vlen) !=
232
                            $this->_packagexml->getExtends()) {
233
                    $this->_addWarning('package', "package $name extends package " .
234
                        $this->_packagexml->getExtends() . ' and so the name must ' .
235
                        'be an extension like "' . $this->_packagexml->getExtends() .
236
                        $test . '"');
237
                    return true;
238
                }
239
            }
240
        }
241
        if (!$this->validPackageName($this->_packagexml->getPackage())) {
242
            $this->_addFailure('name', 'package name "' .
243
                $this->_packagexml->getPackage() . '" is invalid');
244
            return false;
245
        }
246
    }
247
 
248
    /**
249
     * @access protected
250
     */
251
    function validateVersion()
252
    {
253
        if ($this->_state != PEAR_VALIDATE_PACKAGING) {
254
            if (!$this->validVersion($this->_packagexml->getVersion())) {
255
                $this->_addFailure('version',
256
                    'Invalid version number "' . $this->_packagexml->getVersion() . '"');
257
            }
258
            return false;
259
        }
260
        $version = $this->_packagexml->getVersion();
261
        $versioncomponents = explode('.', $version);
262
        if (count($versioncomponents) != 3) {
263
            $this->_addWarning('version',
264
                'A version number should have 3 decimals (x.y.z)');
265
            return true;
266
        }
267
        $name = $this->_packagexml->getPackage();
268
        // version must be based upon state
269
        switch ($this->_packagexml->getState()) {
270
            case 'snapshot' :
271
                return true;
272
            case 'devel' :
273
                if ($versioncomponents[0] . 'a' == '0a') {
274
                    return true;
275
                }
276
                if ($versioncomponents[0] == 0) {
277
                    $versioncomponents[0] = '0';
278
                    $this->_addWarning('version',
279
                        'version "' . $version . '" should be "' .
280
                        implode('.' ,$versioncomponents) . '"');
281
                } else {
282
                    $this->_addWarning('version',
283
                        'packages with devel stability must be < version 1.0.0');
284
                }
285
                return true;
286
            break;
287
            case 'alpha' :
288
            case 'beta' :
289
                // check for a package that extends a package,
290
                // like Foo and Foo2
291
                if ($this->_state == PEAR_VALIDATE_PACKAGING) {
292
                    if (substr($versioncomponents[2], 1, 2) == 'rc') {
293
                        $this->_addFailure('version', 'Release Candidate versions ' .
294
                            'must have capital RC, not lower-case rc');
295
                        return false;
296
                    }
297
                }
298
                if (!$this->_packagexml->getExtends()) {
299
                    if ($versioncomponents[0] == '1') {
300
                        if ($versioncomponents[2]{0} == '0') {
301
                            if ($versioncomponents[2] == '0') {
302
                                // version 1.*.0000
303
                                $this->_addWarning('version',
304
                                    'version 1.' . $versioncomponents[1] .
305
                                        '.0 probably should not be alpha or beta');
306
                                return true;
307
                            } elseif (strlen($versioncomponents[2]) > 1) {
308
                                // version 1.*.0RC1 or 1.*.0beta24 etc.
309
                                return true;
310
                            } else {
311
                                // version 1.*.0
312
                                $this->_addWarning('version',
313
                                    'version 1.' . $versioncomponents[1] .
314
                                        '.0 probably should not be alpha or beta');
315
                                return true;
316
                            }
317
                        } else {
318
                            $this->_addWarning('version',
319
                                'bugfix versions (1.3.x where x > 0) probably should ' .
320
                                'not be alpha or beta');
321
                            return true;
322
                        }
323
                    } elseif ($versioncomponents[0] != '0') {
324
                        $this->_addWarning('version',
325
                            'major versions greater than 1 are not allowed for packages ' .
326
                            'without an <extends> tag or an identical postfix (foo2 v2.0.0)');
327
                        return true;
328
                    }
329
                    if ($versioncomponents[0] . 'a' == '0a') {
330
                        return true;
331
                    }
332
                    if ($versioncomponents[0] == 0) {
333
                        $versioncomponents[0] = '0';
334
                        $this->_addWarning('version',
335
                            'version "' . $version . '" should be "' .
336
                            implode('.' ,$versioncomponents) . '"');
337
                    }
338
                } else {
339
                    $vlen = strlen($versioncomponents[0] . '');
340
                    $majver = substr($name, strlen($name) - $vlen);
341
                    while ($majver && !is_numeric($majver{0})) {
342
                        $majver = substr($majver, 1);
343
                    }
344
                    if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
345
                        $this->_addWarning('version', 'first version number "' .
346
                            $versioncomponents[0] . '" must match the postfix of ' .
347
                            'package name "' . $name . '" (' .
348
                            $majver . ')');
349
                        return true;
350
                    }
351
                    if ($versioncomponents[0] == $majver) {
352
                        if ($versioncomponents[2]{0} == '0') {
353
                            if ($versioncomponents[2] == '0') {
354
                                // version 2.*.0000
355
                                $this->_addWarning('version',
356
                                    "version $majver." . $versioncomponents[1] .
357
                                        '.0 probably should not be alpha or beta');
358
                                return false;
359
                            } elseif (strlen($versioncomponents[2]) > 1) {
360
                                // version 2.*.0RC1 or 2.*.0beta24 etc.
361
                                return true;
362
                            } else {
363
                                // version 2.*.0
364
                                $this->_addWarning('version',
365
                                    "version $majver." . $versioncomponents[1] .
366
                                        '.0 cannot be alpha or beta');
367
                                return true;
368
                            }
369
                        } else {
370
                            $this->_addWarning('version',
371
                                "bugfix versions ($majver.x.y where y > 0) should " .
372
                                'not be alpha or beta');
373
                            return true;
374
                        }
375
                    } elseif ($versioncomponents[0] != '0') {
376
                        $this->_addWarning('version',
377
                            "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases");
378
                        return true;
379
                    }
380
                    if ($versioncomponents[0] . 'a' == '0a') {
381
                        return true;
382
                    }
383
                    if ($versioncomponents[0] == 0) {
384
                        $versioncomponents[0] = '0';
385
                        $this->_addWarning('version',
386
                            'version "' . $version . '" should be "' .
387
                            implode('.' ,$versioncomponents) . '"');
388
                    }
389
                }
390
                return true;
391
            break;
392
            case 'stable' :
393
                if ($versioncomponents[0] == '0') {
394
                    $this->_addWarning('version', 'versions less than 1.0.0 cannot ' .
395
                    'be stable');
396
                    return true;
397
                }
398
                if (!is_numeric($versioncomponents[2])) {
399
                    if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i',
400
                          $versioncomponents[2])) {
401
                        $this->_addWarning('version', 'version "' . $version . '" or any ' .
402
                            'RC/beta/alpha version cannot be stable');
403
                        return true;
404
                    }
405
                }
406
                // check for a package that extends a package,
407
                // like Foo and Foo2
408
                if ($this->_packagexml->getExtends()) {
409
                    $vlen = strlen($versioncomponents[0] . '');
410
                    $majver = substr($name, strlen($name) - $vlen);
411
                    while ($majver && !is_numeric($majver{0})) {
412
                        $majver = substr($majver, 1);
413
                    }
414
                    if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
415
                        $this->_addWarning('version', 'first version number "' .
416
                            $versioncomponents[0] . '" must match the postfix of ' .
417
                            'package name "' . $name . '" (' .
418
                            $majver . ')');
419
                        return true;
420
                    }
421
                } elseif ($versioncomponents[0] > 1) {
422
                    $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' .
423
                        '1 for any package that does not have an <extends> tag');
424
                }
425
                return true;
426
            break;
427
            default :
428
                return false;
429
            break;
430
        }
431
    }
432
 
433
    /**
434
     * @access protected
435
     */
436
    function validateMaintainers()
437
    {
438
        // maintainers can only be truly validated server-side for most channels
439
        // but allow this customization for those who wish it
440
        return true;
441
    }
442
 
443
    /**
444
     * @access protected
445
     */
446
    function validateDate()
447
    {
448
        if ($this->_state == PEAR_VALIDATE_NORMAL ||
449
              $this->_state == PEAR_VALIDATE_PACKAGING) {
450
 
451
            if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/',
452
                  $this->_packagexml->getDate(), $res) ||
453
                  count($res) < 4
454
                  || !checkdate($res[2], $res[3], $res[1])
455
                ) {
456
                $this->_addFailure('date', 'invalid release date "' .
457
                    $this->_packagexml->getDate() . '"');
458
                return false;
459
            }
460
 
461
 
462
            if ($this->_state == PEAR_VALIDATE_PACKAGING &&
463
                  $this->_packagexml->getDate() != date('Y-m-d')) {
464
                $this->_addWarning('date', 'Release Date "' .
465
                    $this->_packagexml->getDate() . '" is not today');
466
            }
467
        }
468
        return true;
469
    }
470
 
471
    /**
472
     * @access protected
473
     */
474
    function validateTime()
475
    {
476
        if (!$this->_packagexml->getTime()) {
477
            // default of no time value set
478
            return true;
479
        }
480
        // packager automatically sets time, so only validate if
481
        // pear validate is called
482
        if ($this->_state = PEAR_VALIDATE_NORMAL) {
483
            if (!preg_match('/\d\d:\d\d:\d\d/',
484
                  $this->_packagexml->getTime())) {
485
                $this->_addFailure('time', 'invalid release time "' .
486
                    $this->_packagexml->getTime() . '"');
487
                return false;
488
            }
489
            if (strtotime($this->_packagexml->getTime()) == -1) {
490
                $this->_addFailure('time', 'invalid release time "' .
491
                    $this->_packagexml->getTime() . '"');
492
                return false;
493
            }
494
        }
495
        return true;
496
    }
497
 
498
    /**
499
     * @access protected
500
     */
501
    function validateState()
502
    {
503
        // this is the closest to "final" php4 can get
504
        if (!PEAR_Validate::validState($this->_packagexml->getState())) {
505
            if (strtolower($this->_packagexml->getState() == 'rc')) {
506
                $this->_addFailure('state', 'RC is not a state, it is a version ' .
507
                    'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta');
508
            }
509
            $this->_addFailure('state', 'invalid release state "' .
510
                $this->_packagexml->getState() . '", must be one of: ' .
511
                implode(', ', PEAR_Validate::getValidStates()));
512
            return false;
513
        }
514
        return true;
515
    }
516
 
517
    /**
518
     * @access protected
519
     */
520
    function validateStability()
521
    {
522
        $ret = true;
523
        $packagestability = $this->_packagexml->getState();
524
        $apistability = $this->_packagexml->getState('api');
525
        if (!PEAR_Validate::validState($packagestability)) {
526
            $this->_addFailure('state', 'invalid release stability "' .
527
                $this->_packagexml->getState() . '", must be one of: ' .
528
                implode(', ', PEAR_Validate::getValidStates()));
529
            $ret = false;
530
        }
531
        $apistates = PEAR_Validate::getValidStates();
532
        array_shift($apistates); // snapshot is not allowed
533
        if (!in_array($apistability, $apistates)) {
534
            $this->_addFailure('state', 'invalid API stability "' .
535
                $this->_packagexml->getState('api') . '", must be one of: ' .
536
                implode(', ', $apistates));
537
            $ret = false;
538
        }
539
        return $ret;
540
    }
541
 
542
    /**
543
     * @access protected
544
     */
545
    function validateSummary()
546
    {
547
        return true;
548
    }
549
 
550
    /**
551
     * @access protected
552
     */
553
    function validateDescription()
554
    {
555
        return true;
556
    }
557
 
558
    /**
559
     * @access protected
560
     */
561
    function validateLicense()
562
    {
563
        return true;
564
    }
565
 
566
    /**
567
     * @access protected
568
     */
569
    function validateNotes()
570
    {
571
        return true;
572
    }
573
 
574
    /**
575
     * for package.xml 2.0 only - channels can't use package.xml 1.0
576
     * @access protected
577
     */
578
    function validateDependencies()
579
    {
580
        return true;
581
    }
582
 
583
    /**
584
     * for package.xml 1.0 only
585
     * @access private
586
     */
587
    function _validateFilelist()
588
    {
589
        return true; // placeholder for now
590
    }
591
 
592
    /**
593
     * for package.xml 2.0 only
594
     * @access protected
595
     */
596
    function validateMainFilelist()
597
    {
598
        return true; // placeholder for now
599
    }
600
 
601
    /**
602
     * for package.xml 2.0 only
603
     * @access protected
604
     */
605
    function validateReleaseFilelist()
606
    {
607
        return true; // placeholder for now
608
    }
609
 
610
    /**
611
     * @access protected
612
     */
613
    function validateChangelog()
614
    {
615
        return true;
616
    }
617
 
618
    /**
619
     * @access protected
620
     */
621
    function validateFilelist()
622
    {
623
        return true;
624
    }
625
 
626
    /**
627
     * @access protected
628
     */
629
    function validateDeps()
630
    {
631
        return true;
632
    }
633
}
634
?>