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