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_ChannelFile, the channel handling class
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
/**
17
 * Needed for error handling
18
 */
19
require_once 'PEAR/ErrorStack.php';
20
require_once 'PEAR/XMLParser.php';
21
require_once 'PEAR/Common.php';
22
 
23
/**
24
 * Error code if the channel.xml <channel> tag does not contain a valid version
25
 */
26
define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
27
/**
28
 * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
29
 * currently
30
 */
31
define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
32
 
33
/**
34
 * Error code if parsing is attempted with no xml extension
35
 */
36
define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
37
 
38
/**
39
 * Error code if creating the xml parser resource fails
40
 */
41
define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
42
 
43
/**
44
 * Error code used for all sax xml parsing errors
45
 */
46
define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
47
 
48
/**#@+
49
 * Validation errors
50
 */
51
/**
52
 * Error code when channel name is missing
53
 */
54
define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
55
/**
56
 * Error code when channel name is invalid
57
 */
58
define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
59
/**
60
 * Error code when channel summary is missing
61
 */
62
define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
63
/**
64
 * Error code when channel summary is multi-line
65
 */
66
define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
67
/**
187 mathias 68
 * Error code when channel server is missing for protocol
94 jpm 69
 */
70
define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
71
/**
187 mathias 72
 * Error code when channel server is invalid for protocol
94 jpm 73
 */
74
define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
75
/**
76
 * Error code when a mirror name is invalid
77
 */
78
define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
79
/**
80
 * Error code when a mirror type is invalid
81
 */
82
define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
83
/**
84
 * Error code when an attempt is made to generate xml, but the parsed content is invalid
85
 */
86
define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
87
/**
88
 * Error code when an empty package name validate regex is passed in
89
 */
90
define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
91
/**
92
 * Error code when a <function> tag has no version
93
 */
94
define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
95
/**
96
 * Error code when a <function> tag has no name
97
 */
98
define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
99
/**
100
 * Error code when a <validatepackage> tag has no name
101
 */
102
define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
103
/**
104
 * Error code when a <validatepackage> tag has no version attribute
105
 */
106
define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
107
/**
108
 * Error code when a mirror does not exist but is called for in one of the set*
109
 * methods.
110
 */
111
define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
112
/**
113
 * Error code when a server port is not numeric
114
 */
115
define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
116
/**
117
 * Error code when <static> contains no version attribute
118
 */
119
define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
120
/**
121
 * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
122
 */
123
define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
187 mathias 124
/**
94 jpm 125
 * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
126
 */
127
define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
187 mathias 128
/**
94 jpm 129
 * Error code when ssl attribute is present and is not "yes"
130
 */
131
define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
132
/**#@-*/
133
 
134
/**
135
 * Mirror types allowed.  Currently only internet servers are recognized.
136
 */
137
$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] =  array('server');
138
 
139
 
140
/**
141
 * The Channel handling class
142
 *
143
 * @category   pear
144
 * @package    PEAR
145
 * @author     Greg Beaver <cellog@php.net>
187 mathias 146
 * @copyright  1997-2009 The Authors
147
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
148
 * @version    Release: 1.10.1
94 jpm 149
 * @link       http://pear.php.net/package/PEAR
150
 * @since      Class available since Release 1.4.0a1
151
 */
187 mathias 152
class PEAR_ChannelFile
153
{
94 jpm 154
    /**
155
     * @access private
156
     * @var PEAR_ErrorStack
157
     * @access private
158
     */
159
    var $_stack;
187 mathias 160
 
94 jpm 161
    /**
162
     * Supported channel.xml versions, for parsing
163
     * @var array
164
     * @access private
165
     */
166
    var $_supportedVersions = array('1.0');
167
 
168
    /**
169
     * Parsed channel information
170
     * @var array
171
     * @access private
172
     */
173
    var $_channelInfo;
174
 
175
    /**
176
     * index into the subchannels array, used for parsing xml
177
     * @var int
178
     * @access private
179
     */
180
    var $_subchannelIndex;
181
 
182
    /**
183
     * index into the mirrors array, used for parsing xml
184
     * @var int
185
     * @access private
186
     */
187
    var $_mirrorIndex;
187 mathias 188
 
94 jpm 189
    /**
190
     * Flag used to determine the validity of parsed content
191
     * @var boolean
192
     * @access private
193
     */
194
    var $_isValid = false;
195
 
187 mathias 196
    function __construct()
94 jpm 197
    {
187 mathias 198
        $this->_stack = new PEAR_ErrorStack('PEAR_ChannelFile');
94 jpm 199
        $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
200
        $this->_isValid = false;
201
    }
187 mathias 202
 
94 jpm 203
    /**
204
     * @return array
205
     * @access protected
206
     */
207
    function _getErrorMessage()
208
    {
209
        return
210
            array(
211
                PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
212
                    'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
213
                PEAR_CHANNELFILE_ERROR_NO_VERSION =>
214
                    'No version number found in <channel> tag',
215
                PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
216
                    '%error%',
217
                PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
218
                    'Unable to create XML parser',
219
                PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
220
                    '%error%',
221
                PEAR_CHANNELFILE_ERROR_NO_NAME =>
222
                    'Missing channel name',
223
                PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
224
                    'Invalid channel %tag% "%name%"',
225
                PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
226
                    'Missing channel summary',
227
                PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
228
                    'Channel summary should be on one line, but is multi-line',
229
                PEAR_CHANNELFILE_ERROR_NO_HOST =>
230
                    'Missing channel server for %type% server',
231
                PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
232
                    'Server name "%server%" is invalid for %type% server',
233
                PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
234
                    'Invalid mirror name "%name%", mirror type %type%',
235
                PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
236
                    'Invalid mirror type "%type%"',
237
                PEAR_CHANNELFILE_ERROR_INVALID =>
238
                    'Cannot generate xml, contents are invalid',
239
                PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
240
                    'packagenameregex cannot be empty',
241
                PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
242
                    '%parent% %protocol% function has no version',
243
                PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
244
                    '%parent% %protocol% function has no name',
245
                PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
246
                    '%parent% rest baseurl has no type',
247
                PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
248
                    'Validation package has no name in <validatepackage> tag',
249
                PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
250
                    'Validation package "%package%" has no version',
251
                PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
252
                    'Mirror "%mirror%" does not exist',
253
                PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
254
                    'Port "%port%" must be numeric',
255
                PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
256
                    '<static> tag must contain version attribute',
257
                PEAR_CHANNELFILE_URI_CANT_MIRROR =>
258
                    'The __uri pseudo-channel cannot have mirrors',
259
                PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
260
                    '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
261
            );
262
    }
263
 
264
    /**
265
     * @param string contents of package.xml file
266
     * @return bool success of parsing
267
     */
268
    function fromXmlString($data)
269
    {
270
        if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
271
            if (!in_array($channelversion[1], $this->_supportedVersions)) {
272
                $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
273
                    array('version' => $channelversion[1]));
274
                return false;
275
            }
276
            $parser = new PEAR_XMLParser;
277
            $result = $parser->parse($data);
278
            if ($result !== true) {
279
                if ($result->getCode() == 1) {
280
                    $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
187 mathias 281
                        array('error' => $result->getMessage()));
94 jpm 282
                } else {
283
                    $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
284
                }
285
                return false;
286
            }
287
            $this->_channelInfo = $parser->getData();
288
            return true;
289
        } else {
290
            $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
291
            return false;
292
        }
293
    }
187 mathias 294
 
94 jpm 295
    /**
296
     * @return array
297
     */
298
    function toArray()
299
    {
300
        if (!$this->_isValid && !$this->validate()) {
301
            return false;
302
        }
303
        return $this->_channelInfo;
304
    }
187 mathias 305
 
94 jpm 306
    /**
307
     * @param array
187 mathias 308
     *
94 jpm 309
     * @return PEAR_ChannelFile|false false if invalid
310
     */
187 mathias 311
    public static function &fromArray(
312
        $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
313
    ) {
94 jpm 314
        $a = new PEAR_ChannelFile($compatibility, $stackClass);
315
        $a->_fromArray($data);
316
        if (!$a->validate()) {
317
            $a = false;
318
            return $a;
319
        }
320
        return $a;
321
    }
322
 
323
    /**
324
     * Unlike {@link fromArray()} this does not do any validation
187 mathias 325
     *
94 jpm 326
     * @param array
187 mathias 327
     *
94 jpm 328
     * @return PEAR_ChannelFile
329
     */
187 mathias 330
    public static function &fromArrayWithErrors(
331
        $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
332
    ) {
94 jpm 333
        $a = new PEAR_ChannelFile($compatibility, $stackClass);
334
        $a->_fromArray($data);
335
        return $a;
336
    }
187 mathias 337
 
94 jpm 338
    /**
339
     * @param array
340
     * @access private
341
     */
342
    function _fromArray($data)
343
    {
344
        $this->_channelInfo = $data;
345
    }
187 mathias 346
 
94 jpm 347
    /**
348
     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
349
     * @param boolean determines whether to purge the error stack after retrieving
350
     * @return array
351
     */
352
    function getErrors($purge = false)
353
    {
354
        return $this->_stack->getErrors($purge);
355
    }
356
 
357
    /**
358
     * Unindent given string (?)
359
     *
360
     * @param string $str The string that has to be unindented.
361
     * @return string
362
     * @access private
363
     */
364
    function _unIndent($str)
365
    {
366
        // remove leading newlines
367
        $str = preg_replace('/^[\r\n]+/', '', $str);
368
        // find whitespace at the beginning of the first line
369
        $indent_len = strspn($str, " \t");
370
        $indent = substr($str, 0, $indent_len);
371
        $data = '';
372
        // remove the same amount of whitespace from following lines
373
        foreach (explode("\n", $str) as $line) {
374
            if (substr($line, 0, $indent_len) == $indent) {
375
                $data .= substr($line, $indent_len) . "\n";
376
            }
377
        }
378
        return $data;
379
    }
380
 
381
    /**
382
     * Parse a channel.xml file.  Expects the name of
383
     * a channel xml file as input.
384
     *
385
     * @param string  $descfile  name of channel xml file
386
     * @return bool success of parsing
387
     */
388
    function fromXmlFile($descfile)
389
    {
390
        if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
391
             (!$fp = fopen($descfile, 'r'))) {
392
            require_once 'PEAR.php';
393
            return PEAR::raiseError("Unable to open $descfile");
394
        }
395
 
396
        // read the whole thing so we only get one cdata callback
397
        // for each block of cdata
398
        fclose($fp);
399
        $data = file_get_contents($descfile);
400
        return $this->fromXmlString($data);
401
    }
402
 
403
    /**
404
     * Parse channel information from different sources
405
     *
406
     * This method is able to extract information about a channel
407
     * from an .xml file or a string
408
     *
409
     * @access public
410
     * @param  string Filename of the source or the source itself
411
     * @return bool
412
     */
413
    function fromAny($info)
414
    {
415
        if (is_string($info) && file_exists($info) && strlen($info) < 255) {
416
            $tmp = substr($info, -4);
417
            if ($tmp == '.xml') {
418
                $info = $this->fromXmlFile($info);
419
            } else {
420
                $fp = fopen($info, "r");
421
                $test = fread($fp, 5);
422
                fclose($fp);
423
                if ($test == "<?xml") {
424
                    $info = $this->fromXmlFile($info);
425
                }
426
            }
427
            if (PEAR::isError($info)) {
428
                require_once 'PEAR.php';
429
                return PEAR::raiseError($info);
430
            }
431
        }
432
        if (is_string($info)) {
433
            $info = $this->fromXmlString($info);
434
        }
435
        return $info;
436
    }
437
 
438
    /**
439
     * Return an XML document based on previous parsing and modifications
440
     *
441
     * @return string XML data
442
     *
443
     * @access public
444
     */
445
    function toXml()
446
    {
447
        if (!$this->_isValid && !$this->validate()) {
448
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
449
            return false;
450
        }
451
        if (!isset($this->_channelInfo['attribs']['version'])) {
452
            $this->_channelInfo['attribs']['version'] = '1.0';
453
        }
454
        $channelInfo = $this->_channelInfo;
455
        $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
456
        $ret .= "<channel version=\"" .
457
            $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
458
  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
459
  xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
460
            . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
461
            $channelInfo['attribs']['version'] . ".xsd\">
462
 <name>$channelInfo[name]</name>
463
 <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
464
";
465
        if (isset($channelInfo['suggestedalias'])) {
466
            $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
467
        }
468
        if (isset($channelInfo['validatepackage'])) {
469
            $ret .= ' <validatepackage version="' .
470
                $channelInfo['validatepackage']['attribs']['version']. '">' .
471
                htmlspecialchars($channelInfo['validatepackage']['_content']) .
472
                "</validatepackage>\n";
473
        }
474
        $ret .= " <servers>\n";
475
        $ret .= '  <primary';
476
        if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
477
            $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
478
        }
479
        if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
480
            $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
481
        }
482
        $ret .= ">\n";
483
        if (isset($channelInfo['servers']['primary']['rest'])) {
484
            $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], '   ');
485
        }
486
        $ret .= "  </primary>\n";
487
        if (isset($channelInfo['servers']['mirror'])) {
488
            $ret .= $this->_makeMirrorsXml($channelInfo);
489
        }
490
        $ret .= " </servers>\n";
491
        $ret .= "</channel>";
492
        return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
493
    }
494
 
495
    /**
496
     * Generate the <rest> tag
497
     * @access private
498
     */
499
    function _makeRestXml($info, $indent)
500
    {
501
        $ret = $indent . "<rest>\n";
187 mathias 502
        if (isset($info['baseurl']) && !isset($info['baseurl'][0])) {
94 jpm 503
            $info['baseurl'] = array($info['baseurl']);
504
        }
187 mathias 505
 
506
        if (isset($info['baseurl'])) {
507
            foreach ($info['baseurl'] as $url) {
508
                $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
509
                $ret .= ">" . $url['_content'] . "</baseurl>\n";
510
            }
94 jpm 511
        }
512
        $ret .= $indent . "</rest>\n";
513
        return $ret;
514
    }
515
 
516
    /**
517
     * Generate the <mirrors> tag
518
     * @access private
519
     */
520
    function _makeMirrorsXml($channelInfo)
521
    {
522
        $ret = "";
523
        if (!isset($channelInfo['servers']['mirror'][0])) {
524
            $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
525
        }
526
        foreach ($channelInfo['servers']['mirror'] as $mirror) {
527
            $ret .= '  <mirror host="' . $mirror['attribs']['host'] . '"';
528
            if (isset($mirror['attribs']['port'])) {
529
                $ret .= ' port="' . $mirror['attribs']['port'] . '"';
530
            }
531
            if (isset($mirror['attribs']['ssl'])) {
532
                $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
533
            }
534
            $ret .= ">\n";
187 mathias 535
            if (isset($mirror['rest'])) {
94 jpm 536
                if (isset($mirror['rest'])) {
537
                    $ret .= $this->_makeRestXml($mirror['rest'], '   ');
538
                }
539
                $ret .= "  </mirror>\n";
540
            } else {
541
                $ret .= "/>\n";
542
            }
543
        }
544
        return $ret;
545
    }
546
 
547
    /**
548
     * Generate the <functions> tag
549
     * @access private
550
     */
551
    function _makeFunctionsXml($functions, $indent, $rest = false)
552
    {
553
        $ret = '';
554
        if (!isset($functions[0])) {
555
            $functions = array($functions);
556
        }
557
        foreach ($functions as $function) {
558
            $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
559
            if ($rest) {
560
                $ret .= ' uri="' . $function['attribs']['uri'] . '"';
561
            }
562
            $ret .= ">" . $function['_content'] . "</function>\n";
563
        }
564
        return $ret;
565
    }
566
 
567
    /**
568
     * Validation error.  Also marks the object contents as invalid
569
     * @param error code
570
     * @param array error information
571
     * @access private
572
     */
573
    function _validateError($code, $params = array())
574
    {
575
        $this->_stack->push($code, 'error', $params);
576
        $this->_isValid = false;
577
    }
578
 
579
    /**
580
     * Validation warning.  Does not mark the object contents invalid.
581
     * @param error code
582
     * @param array error information
583
     * @access private
584
     */
585
    function _validateWarning($code, $params = array())
586
    {
587
        $this->_stack->push($code, 'warning', $params);
588
    }
589
 
590
    /**
591
     * Validate parsed file.
592
     *
593
     * @access public
594
     * @return boolean
595
     */
596
    function validate()
597
    {
598
        $this->_isValid = true;
599
        $info = $this->_channelInfo;
600
        if (empty($info['name'])) {
601
            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
602
        } elseif (!$this->validChannelServer($info['name'])) {
603
            if ($info['name'] != '__uri') {
604
                $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
605
                    'name' => $info['name']));
606
            }
607
        }
608
        if (empty($info['summary'])) {
609
            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
610
        } elseif (strpos(trim($info['summary']), "\n") !== false) {
611
            $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
612
                array('summary' => $info['summary']));
613
        }
614
        if (isset($info['suggestedalias'])) {
615
            if (!$this->validChannelServer($info['suggestedalias'])) {
616
                $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
617
                    array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
618
            }
619
        }
620
        if (isset($info['localalias'])) {
621
            if (!$this->validChannelServer($info['localalias'])) {
622
                $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
623
                    array('tag' => 'localalias', 'name' =>$info['localalias']));
624
            }
625
        }
626
        if (isset($info['validatepackage'])) {
627
            if (!isset($info['validatepackage']['_content'])) {
628
                $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
629
            }
630
            if (!isset($info['validatepackage']['attribs']['version'])) {
631
                $content = isset($info['validatepackage']['_content']) ?
632
                    $info['validatepackage']['_content'] :
633
                    null;
634
                $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
635
                    array('package' => $content));
636
            }
637
        }
187 mathias 638
 
639
        if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) &&
94 jpm 640
              !is_numeric($info['servers']['primary']['attribs']['port'])) {
641
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
642
                array('port' => $info['servers']['primary']['attribs']['port']));
643
        }
187 mathias 644
 
645
        if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) &&
94 jpm 646
              $info['servers']['primary']['attribs']['ssl'] != 'yes') {
647
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
648
                array('ssl' => $info['servers']['primary']['attribs']['ssl'],
649
                    'server' => $info['name']));
650
        }
651
 
652
        if (isset($info['servers']['primary']['rest']) &&
653
              isset($info['servers']['primary']['rest']['baseurl'])) {
654
            $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
655
        }
656
        if (isset($info['servers']['mirror'])) {
657
            if ($this->_channelInfo['name'] == '__uri') {
658
                $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
659
            }
660
            if (!isset($info['servers']['mirror'][0])) {
661
                $info['servers']['mirror'] = array($info['servers']['mirror']);
662
            }
663
            foreach ($info['servers']['mirror'] as $mirror) {
664
                if (!isset($mirror['attribs']['host'])) {
665
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
666
                      array('type' => 'mirror'));
667
                } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
668
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
669
                        array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
670
                }
671
                if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
672
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
673
                        array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
674
                }
675
                if (isset($mirror['rest'])) {
676
                    $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
677
                        $mirror['attribs']['host']);
678
                }
679
            }
680
        }
681
        return $this->_isValid;
682
    }
683
 
684
    /**
187 mathias 685
     * @param string  rest - protocol name this function applies to
94 jpm 686
     * @param array the functions
687
     * @param string the name of the parent element (mirror name, for instance)
688
     */
689
    function _validateFunctions($protocol, $functions, $parent = '')
690
    {
691
        if (!isset($functions[0])) {
692
            $functions = array($functions);
693
        }
187 mathias 694
 
94 jpm 695
        foreach ($functions as $function) {
696
            if (!isset($function['_content']) || empty($function['_content'])) {
697
                $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
698
                    array('parent' => $parent, 'protocol' => $protocol));
699
            }
187 mathias 700
 
94 jpm 701
            if ($protocol == 'rest') {
702
                if (!isset($function['attribs']['type']) ||
703
                      empty($function['attribs']['type'])) {
187 mathias 704
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE,
94 jpm 705
                        array('parent' => $parent, 'protocol' => $protocol));
706
                }
707
            } else {
708
                if (!isset($function['attribs']['version']) ||
709
                      empty($function['attribs']['version'])) {
710
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
711
                        array('parent' => $parent, 'protocol' => $protocol));
712
                }
713
            }
714
        }
715
    }
716
 
717
    /**
718
     * Test whether a string contains a valid channel server.
719
     * @param string $ver the package version to test
720
     * @return bool
721
     */
722
    function validChannelServer($server)
723
    {
724
        if ($server == '__uri') {
725
            return true;
726
        }
727
        return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
728
    }
729
 
730
    /**
731
     * @return string|false
732
     */
733
    function getName()
734
    {
735
        if (isset($this->_channelInfo['name'])) {
736
            return $this->_channelInfo['name'];
737
        }
187 mathias 738
 
739
        return false;
94 jpm 740
    }
741
 
742
    /**
743
     * @return string|false
744
     */
745
    function getServer()
746
    {
747
        if (isset($this->_channelInfo['name'])) {
748
            return $this->_channelInfo['name'];
749
        }
187 mathias 750
 
751
        return false;
94 jpm 752
    }
753
 
754
    /**
755
     * @return int|80 port number to connect to
756
     */
757
    function getPort($mirror = false)
758
    {
759
        if ($mirror) {
760
            if ($mir = $this->getMirror($mirror)) {
761
                if (isset($mir['attribs']['port'])) {
762
                    return $mir['attribs']['port'];
763
                }
187 mathias 764
 
765
                if ($this->getSSL($mirror)) {
766
                    return 443;
767
                }
768
 
769
                return 80;
94 jpm 770
            }
187 mathias 771
 
94 jpm 772
            return false;
773
        }
187 mathias 774
 
94 jpm 775
        if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
776
            return $this->_channelInfo['servers']['primary']['attribs']['port'];
777
        }
187 mathias 778
 
94 jpm 779
        if ($this->getSSL()) {
780
            return 443;
781
        }
187 mathias 782
 
94 jpm 783
        return 80;
784
    }
785
 
786
    /**
787
     * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
788
     */
789
    function getSSL($mirror = false)
790
    {
791
        if ($mirror) {
792
            if ($mir = $this->getMirror($mirror)) {
793
                if (isset($mir['attribs']['ssl'])) {
794
                    return true;
795
                }
187 mathias 796
 
797
                return false;
94 jpm 798
            }
187 mathias 799
 
94 jpm 800
            return false;
801
        }
187 mathias 802
 
94 jpm 803
        if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
804
            return true;
805
        }
187 mathias 806
 
94 jpm 807
        return false;
808
    }
809
 
810
    /**
811
     * @return string|false
812
     */
813
    function getSummary()
814
    {
815
        if (isset($this->_channelInfo['summary'])) {
816
            return $this->_channelInfo['summary'];
817
        }
818
 
187 mathias 819
        return false;
94 jpm 820
    }
821
 
822
    /**
187 mathias 823
     * @param string protocol type
94 jpm 824
     * @param string Mirror name
825
     * @return array|false
826
     */
827
    function getFunctions($protocol, $mirror = false)
828
    {
829
        if ($this->getName() == '__uri') {
830
            return false;
831
        }
187 mathias 832
 
833
        $function = $protocol == 'rest' ? 'baseurl' : 'function';
94 jpm 834
        if ($mirror) {
835
            if ($mir = $this->getMirror($mirror)) {
836
                if (isset($mir[$protocol][$function])) {
837
                    return $mir[$protocol][$function];
838
                }
839
            }
187 mathias 840
 
94 jpm 841
            return false;
842
        }
187 mathias 843
 
94 jpm 844
        if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
845
            return $this->_channelInfo['servers']['primary'][$protocol][$function];
846
        }
187 mathias 847
 
848
        return false;
94 jpm 849
    }
850
 
851
    /**
852
     * @param string Protocol type
853
     * @param string Function name (null to return the
854
     *               first protocol of the type requested)
855
     * @param string Mirror name, if any
856
     * @return array
857
     */
858
     function getFunction($type, $name = null, $mirror = false)
859
     {
860
        $protocols = $this->getFunctions($type, $mirror);
861
        if (!$protocols) {
862
            return false;
863
        }
187 mathias 864
 
94 jpm 865
        foreach ($protocols as $protocol) {
866
            if ($name === null) {
867
                return $protocol;
868
            }
187 mathias 869
 
94 jpm 870
            if ($protocol['_content'] != $name) {
871
                continue;
872
            }
187 mathias 873
 
94 jpm 874
            return $protocol;
875
        }
187 mathias 876
 
94 jpm 877
        return false;
878
     }
879
 
880
    /**
881
     * @param string protocol type
882
     * @param string protocol name
883
     * @param string version
884
     * @param string mirror name
885
     * @return boolean
886
     */
887
    function supports($type, $name = null, $mirror = false, $version = '1.0')
888
    {
889
        $protocols = $this->getFunctions($type, $mirror);
890
        if (!$protocols) {
891
            return false;
892
        }
187 mathias 893
 
94 jpm 894
        foreach ($protocols as $protocol) {
895
            if ($protocol['attribs']['version'] != $version) {
896
                continue;
897
            }
187 mathias 898
 
94 jpm 899
            if ($name === null) {
900
                return true;
901
            }
187 mathias 902
 
94 jpm 903
            if ($protocol['_content'] != $name) {
904
                continue;
905
            }
187 mathias 906
 
94 jpm 907
            return true;
908
        }
187 mathias 909
 
94 jpm 910
        return false;
911
    }
912
 
913
    /**
914
     * Determines whether a channel supports Representational State Transfer (REST) protocols
915
     * for retrieving channel information
916
     * @param string
917
     * @return bool
918
     */
919
    function supportsREST($mirror = false)
920
    {
921
        if ($mirror == $this->_channelInfo['name']) {
922
            $mirror = false;
923
        }
187 mathias 924
 
94 jpm 925
        if ($mirror) {
926
            if ($mir = $this->getMirror($mirror)) {
927
                return isset($mir['rest']);
928
            }
187 mathias 929
 
94 jpm 930
            return false;
931
        }
187 mathias 932
 
94 jpm 933
        return isset($this->_channelInfo['servers']['primary']['rest']);
934
    }
935
 
936
    /**
937
     * Get the URL to access a base resource.
938
     *
939
     * Hyperlinks in the returned xml will be used to retrieve the proper information
940
     * needed.  This allows extreme extensibility and flexibility in implementation
941
     * @param string Resource Type to retrieve
942
     */
943
    function getBaseURL($resourceType, $mirror = false)
944
    {
945
        if ($mirror == $this->_channelInfo['name']) {
946
            $mirror = false;
947
        }
187 mathias 948
 
94 jpm 949
        if ($mirror) {
187 mathias 950
            $mir = $this->getMirror($mirror);
951
            if (!$mir) {
94 jpm 952
                return false;
953
            }
187 mathias 954
 
955
            $rest = $mir['rest'];
94 jpm 956
        } else {
957
            $rest = $this->_channelInfo['servers']['primary']['rest'];
958
        }
187 mathias 959
 
94 jpm 960
        if (!isset($rest['baseurl'][0])) {
961
            $rest['baseurl'] = array($rest['baseurl']);
962
        }
187 mathias 963
 
94 jpm 964
        foreach ($rest['baseurl'] as $baseurl) {
965
            if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
966
                return $baseurl['_content'];
967
            }
968
        }
187 mathias 969
 
94 jpm 970
        return false;
971
    }
972
 
973
    /**
974
     * Since REST does not implement RPC, provide this as a logical wrapper around
975
     * resetFunctions for REST
976
     * @param string|false mirror name, if any
977
     */
978
    function resetREST($mirror = false)
979
    {
980
        return $this->resetFunctions('rest', $mirror);
981
    }
982
 
983
    /**
984
     * Empty all protocol definitions
187 mathias 985
     * @param string protocol type
94 jpm 986
     * @param string|false mirror name, if any
987
     */
988
    function resetFunctions($type, $mirror = false)
989
    {
990
        if ($mirror) {
991
            if (isset($this->_channelInfo['servers']['mirror'])) {
992
                $mirrors = $this->_channelInfo['servers']['mirror'];
993
                if (!isset($mirrors[0])) {
994
                    $mirrors = array($mirrors);
995
                }
187 mathias 996
 
94 jpm 997
                foreach ($mirrors as $i => $mir) {
998
                    if ($mir['attribs']['host'] == $mirror) {
999
                        if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
1000
                            unset($this->_channelInfo['servers']['mirror'][$i][$type]);
1001
                        }
187 mathias 1002
 
94 jpm 1003
                        return true;
1004
                    }
1005
                }
187 mathias 1006
 
94 jpm 1007
                return false;
1008
            }
187 mathias 1009
 
1010
            return false;
94 jpm 1011
        }
187 mathias 1012
 
1013
        if (isset($this->_channelInfo['servers']['primary'][$type])) {
1014
            unset($this->_channelInfo['servers']['primary'][$type]);
1015
        }
1016
 
1017
        return true;
94 jpm 1018
    }
1019
 
1020
    /**
1021
     * Set a channel's protocols to the protocols supported by pearweb
1022
     */
1023
    function setDefaultPEARProtocols($version = '1.0', $mirror = false)
1024
    {
1025
        switch ($version) {
1026
            case '1.0' :
1027
                $this->resetREST($mirror);
187 mathias 1028
 
1029
                if (!isset($this->_channelInfo['servers'])) {
1030
                    $this->_channelInfo['servers'] = array('primary' =>
1031
                        array('rest' => array()));
1032
                } elseif (!isset($this->_channelInfo['servers']['primary'])) {
1033
                    $this->_channelInfo['servers']['primary'] = array('rest' => array());
1034
                }
1035
 
94 jpm 1036
                return true;
1037
            break;
1038
            default :
1039
                return false;
1040
            break;
1041
        }
1042
    }
187 mathias 1043
 
94 jpm 1044
    /**
1045
     * @return array
1046
     */
1047
    function getMirrors()
1048
    {
1049
        if (isset($this->_channelInfo['servers']['mirror'])) {
1050
            $mirrors = $this->_channelInfo['servers']['mirror'];
1051
            if (!isset($mirrors[0])) {
1052
                $mirrors = array($mirrors);
1053
            }
187 mathias 1054
 
94 jpm 1055
            return $mirrors;
1056
        }
187 mathias 1057
 
1058
        return array();
94 jpm 1059
    }
1060
 
1061
    /**
1062
     * Get the unserialized XML representing a mirror
1063
     * @return array|false
1064
     */
1065
    function getMirror($server)
1066
    {
1067
        foreach ($this->getMirrors() as $mirror) {
1068
            if ($mirror['attribs']['host'] == $server) {
1069
                return $mirror;
1070
            }
1071
        }
187 mathias 1072
 
94 jpm 1073
        return false;
1074
    }
1075
 
1076
    /**
1077
     * @param string
1078
     * @return string|false
1079
     * @error PEAR_CHANNELFILE_ERROR_NO_NAME
1080
     * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
1081
     */
1082
    function setName($name)
1083
    {
1084
        return $this->setServer($name);
1085
    }
1086
 
1087
    /**
1088
     * Set the socket number (port) that is used to connect to this channel
1089
     * @param integer
1090
     * @param string|false name of the mirror server, or false for the primary
1091
     */
1092
    function setPort($port, $mirror = false)
1093
    {
1094
        if ($mirror) {
1095
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1096
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1097
                    array('mirror' => $mirror));
1098
                return false;
1099
            }
187 mathias 1100
 
94 jpm 1101
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1102
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1103
                    if ($mirror == $mir['attribs']['host']) {
1104
                        $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
1105
                        return true;
1106
                    }
1107
                }
187 mathias 1108
 
94 jpm 1109
                return false;
1110
            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1111
                $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
1112
                $this->_isValid = false;
1113
                return true;
1114
            }
1115
        }
187 mathias 1116
 
94 jpm 1117
        $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
1118
        $this->_isValid = false;
1119
        return true;
1120
    }
1121
 
1122
    /**
1123
     * Set the socket number (port) that is used to connect to this channel
1124
     * @param bool Determines whether to turn on SSL support or turn it off
1125
     * @param string|false name of the mirror server, or false for the primary
1126
     */
1127
    function setSSL($ssl = true, $mirror = false)
1128
    {
1129
        if ($mirror) {
1130
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1131
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1132
                    array('mirror' => $mirror));
1133
                return false;
1134
            }
187 mathias 1135
 
94 jpm 1136
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1137
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1138
                    if ($mirror == $mir['attribs']['host']) {
1139
                        if (!$ssl) {
1140
                            if (isset($this->_channelInfo['servers']['mirror'][$i]
1141
                                  ['attribs']['ssl'])) {
1142
                                unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
1143
                            }
1144
                        } else {
1145
                            $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
1146
                        }
187 mathias 1147
 
94 jpm 1148
                        return true;
1149
                    }
1150
                }
187 mathias 1151
 
94 jpm 1152
                return false;
1153
            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1154
                if (!$ssl) {
1155
                    if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
1156
                        unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
1157
                    }
1158
                } else {
1159
                    $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
1160
                }
187 mathias 1161
 
94 jpm 1162
                $this->_isValid = false;
1163
                return true;
1164
            }
1165
        }
187 mathias 1166
 
94 jpm 1167
        if ($ssl) {
1168
            $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
1169
        } else {
1170
            if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
1171
                unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
1172
            }
1173
        }
1174
 
1175
        $this->_isValid = false;
1176
        return true;
1177
    }
1178
 
1179
    /**
1180
     * @param string
1181
     * @return string|false
1182
     * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
1183
     * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
1184
     */
1185
    function setServer($server, $mirror = false)
1186
    {
1187
        if (empty($server)) {
1188
            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
1189
            return false;
1190
        } elseif (!$this->validChannelServer($server)) {
1191
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
1192
                array('tag' => 'name', 'name' => $server));
1193
            return false;
1194
        }
187 mathias 1195
 
94 jpm 1196
        if ($mirror) {
1197
            $found = false;
1198
            foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1199
                if ($mirror == $mir['attribs']['host']) {
1200
                    $found = true;
1201
                    break;
1202
                }
1203
            }
187 mathias 1204
 
94 jpm 1205
            if (!$found) {
1206
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1207
                    array('mirror' => $mirror));
1208
                return false;
1209
            }
187 mathias 1210
 
94 jpm 1211
            $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
1212
            return true;
1213
        }
187 mathias 1214
 
94 jpm 1215
        $this->_channelInfo['name'] = $server;
1216
        return true;
1217
    }
1218
 
1219
    /**
1220
     * @param string
1221
     * @return boolean success
1222
     * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
1223
     * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
1224
     */
1225
    function setSummary($summary)
1226
    {
1227
        if (empty($summary)) {
1228
            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
1229
            return false;
1230
        } elseif (strpos(trim($summary), "\n") !== false) {
1231
            $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
1232
                array('summary' => $summary));
1233
        }
187 mathias 1234
 
94 jpm 1235
        $this->_channelInfo['summary'] = $summary;
1236
        return true;
1237
    }
1238
 
1239
    /**
1240
     * @param string
1241
     * @param boolean determines whether the alias is in channel.xml or local
1242
     * @return boolean success
1243
     */
1244
    function setAlias($alias, $local = false)
1245
    {
1246
        if (!$this->validChannelServer($alias)) {
1247
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
1248
                array('tag' => 'suggestedalias', 'name' => $alias));
1249
            return false;
1250
        }
187 mathias 1251
 
94 jpm 1252
        if ($local) {
1253
            $this->_channelInfo['localalias'] = $alias;
1254
        } else {
1255
            $this->_channelInfo['suggestedalias'] = $alias;
1256
        }
187 mathias 1257
 
94 jpm 1258
        return true;
1259
    }
1260
 
1261
    /**
1262
     * @return string
1263
     */
1264
    function getAlias()
1265
    {
1266
        if (isset($this->_channelInfo['localalias'])) {
1267
            return $this->_channelInfo['localalias'];
1268
        }
1269
        if (isset($this->_channelInfo['suggestedalias'])) {
1270
            return $this->_channelInfo['suggestedalias'];
1271
        }
1272
        if (isset($this->_channelInfo['name'])) {
1273
            return $this->_channelInfo['name'];
1274
        }
187 mathias 1275
        return '';
94 jpm 1276
    }
1277
 
1278
    /**
1279
     * Set the package validation object if it differs from PEAR's default
1280
     * The class must be includeable via changing _ in the classname to path separator,
1281
     * but no checking of this is made.
1282
     * @param string|false pass in false to reset to the default packagename regex
1283
     * @return boolean success
1284
     */
1285
    function setValidationPackage($validateclass, $version)
1286
    {
1287
        if (empty($validateclass)) {
1288
            unset($this->_channelInfo['validatepackage']);
1289
        }
1290
        $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
1291
        $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
1292
    }
1293
 
1294
    /**
1295
     * Add a protocol to the provides section
1296
     * @param string protocol type
1297
     * @param string protocol version
1298
     * @param string protocol name, if any
1299
     * @param string mirror name, if this is a mirror's protocol
1300
     * @return bool
1301
     */
1302
    function addFunction($type, $version, $name = '', $mirror = false)
1303
    {
1304
        if ($mirror) {
1305
            return $this->addMirrorFunction($mirror, $type, $version, $name);
1306
        }
187 mathias 1307
 
94 jpm 1308
        $set = array('attribs' => array('version' => $version), '_content' => $name);
1309
        if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
1310
            if (!isset($this->_channelInfo['servers'])) {
1311
                $this->_channelInfo['servers'] = array('primary' =>
1312
                    array($type => array()));
1313
            } elseif (!isset($this->_channelInfo['servers']['primary'])) {
1314
                $this->_channelInfo['servers']['primary'] = array($type => array());
1315
            }
187 mathias 1316
 
94 jpm 1317
            $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
1318
            $this->_isValid = false;
1319
            return true;
1320
        } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
1321
            $this->_channelInfo['servers']['primary'][$type]['function'] = array(
1322
                $this->_channelInfo['servers']['primary'][$type]['function']);
1323
        }
187 mathias 1324
 
94 jpm 1325
        $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
1326
        return true;
1327
    }
1328
    /**
1329
     * Add a protocol to a mirror's provides section
1330
     * @param string mirror name (server)
1331
     * @param string protocol type
1332
     * @param string protocol version
1333
     * @param string protocol name, if any
1334
     */
1335
    function addMirrorFunction($mirror, $type, $version, $name = '')
1336
    {
1337
        if (!isset($this->_channelInfo['servers']['mirror'])) {
1338
            $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1339
                array('mirror' => $mirror));
1340
            return false;
1341
        }
187 mathias 1342
 
94 jpm 1343
        $setmirror = false;
1344
        if (isset($this->_channelInfo['servers']['mirror'][0])) {
1345
            foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1346
                if ($mirror == $mir['attribs']['host']) {
1347
                    $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
1348
                    break;
1349
                }
1350
            }
1351
        } else {
1352
            if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1353
                $setmirror = &$this->_channelInfo['servers']['mirror'];
1354
            }
1355
        }
187 mathias 1356
 
94 jpm 1357
        if (!$setmirror) {
1358
            $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1359
                array('mirror' => $mirror));
1360
            return false;
1361
        }
187 mathias 1362
 
94 jpm 1363
        $set = array('attribs' => array('version' => $version), '_content' => $name);
1364
        if (!isset($setmirror[$type]['function'])) {
1365
            $setmirror[$type]['function'] = $set;
1366
            $this->_isValid = false;
1367
            return true;
1368
        } elseif (!isset($setmirror[$type]['function'][0])) {
1369
            $setmirror[$type]['function'] = array($setmirror[$type]['function']);
1370
        }
187 mathias 1371
 
94 jpm 1372
        $setmirror[$type]['function'][] = $set;
1373
        $this->_isValid = false;
1374
        return true;
1375
    }
1376
 
1377
    /**
1378
     * @param string Resource Type this url links to
1379
     * @param string URL
1380
     * @param string|false mirror name, if this is not a primary server REST base URL
1381
     */
1382
    function setBaseURL($resourceType, $url, $mirror = false)
1383
    {
1384
        if ($mirror) {
1385
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1386
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1387
                    array('mirror' => $mirror));
1388
                return false;
1389
            }
187 mathias 1390
 
94 jpm 1391
            $setmirror = false;
1392
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1393
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1394
                    if ($mirror == $mir['attribs']['host']) {
1395
                        $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
1396
                        break;
1397
                    }
1398
                }
1399
            } else {
1400
                if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1401
                    $setmirror = &$this->_channelInfo['servers']['mirror'];
1402
                }
1403
            }
1404
        } else {
1405
            $setmirror = &$this->_channelInfo['servers']['primary'];
1406
        }
187 mathias 1407
 
94 jpm 1408
        $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
1409
        if (!isset($setmirror['rest'])) {
1410
            $setmirror['rest'] = array();
1411
        }
187 mathias 1412
 
94 jpm 1413
        if (!isset($setmirror['rest']['baseurl'])) {
1414
            $setmirror['rest']['baseurl'] = $set;
1415
            $this->_isValid = false;
1416
            return true;
1417
        } elseif (!isset($setmirror['rest']['baseurl'][0])) {
1418
            $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
1419
        }
187 mathias 1420
 
94 jpm 1421
        foreach ($setmirror['rest']['baseurl'] as $i => $url) {
1422
            if ($url['attribs']['type'] == $resourceType) {
1423
                $this->_isValid = false;
1424
                $setmirror['rest']['baseurl'][$i] = $set;
1425
                return true;
1426
            }
1427
        }
187 mathias 1428
 
94 jpm 1429
        $setmirror['rest']['baseurl'][] = $set;
1430
        $this->_isValid = false;
1431
        return true;
1432
    }
1433
 
1434
    /**
1435
     * @param string mirror server
1436
     * @param int mirror http port
1437
     * @return boolean
1438
     */
1439
    function addMirror($server, $port = null)
1440
    {
1441
        if ($this->_channelInfo['name'] == '__uri') {
1442
            return false; // the __uri channel cannot have mirrors by definition
1443
        }
187 mathias 1444
 
94 jpm 1445
        $set = array('attribs' => array('host' => $server));
1446
        if (is_numeric($port)) {
1447
            $set['attribs']['port'] = $port;
1448
        }
187 mathias 1449
 
94 jpm 1450
        if (!isset($this->_channelInfo['servers']['mirror'])) {
1451
            $this->_channelInfo['servers']['mirror'] = $set;
1452
            return true;
1453
        }
187 mathias 1454
 
1455
        if (!isset($this->_channelInfo['servers']['mirror'][0])) {
1456
            $this->_channelInfo['servers']['mirror'] =
1457
                array($this->_channelInfo['servers']['mirror']);
1458
        }
1459
 
94 jpm 1460
        $this->_channelInfo['servers']['mirror'][] = $set;
1461
        return true;
1462
    }
1463
 
1464
    /**
1465
     * Retrieve the name of the validation package for this channel
1466
     * @return string|false
1467
     */
1468
    function getValidationPackage()
1469
    {
1470
        if (!$this->_isValid && !$this->validate()) {
1471
            return false;
1472
        }
187 mathias 1473
 
94 jpm 1474
        if (!isset($this->_channelInfo['validatepackage'])) {
1475
            return array('attribs' => array('version' => 'default'),
1476
                '_content' => 'PEAR_Validate');
1477
        }
187 mathias 1478
 
94 jpm 1479
        return $this->_channelInfo['validatepackage'];
1480
    }
1481
 
1482
    /**
1483
     * Retrieve the object that can be used for custom validation
1484
     * @param string|false the name of the package to validate.  If the package is
1485
     *                     the channel validation package, PEAR_Validate is returned
1486
     * @return PEAR_Validate|false false is returned if the validation package
1487
     *         cannot be located
1488
     */
1489
    function &getValidationObject($package = false)
1490
    {
1491
        if (!class_exists('PEAR_Validate')) {
1492
            require_once 'PEAR/Validate.php';
1493
        }
187 mathias 1494
 
94 jpm 1495
        if (!$this->_isValid) {
1496
            if (!$this->validate()) {
1497
                $a = false;
1498
                return $a;
1499
            }
1500
        }
187 mathias 1501
 
94 jpm 1502
        if (isset($this->_channelInfo['validatepackage'])) {
1503
            if ($package == $this->_channelInfo['validatepackage']) {
1504
                // channel validation packages are always validated by PEAR_Validate
187 mathias 1505
                $val = new PEAR_Validate;
94 jpm 1506
                return $val;
1507
            }
187 mathias 1508
 
94 jpm 1509
            if (!class_exists(str_replace('.', '_',
1510
                  $this->_channelInfo['validatepackage']['_content']))) {
1511
                if ($this->isIncludeable(str_replace('_', '/',
1512
                      $this->_channelInfo['validatepackage']['_content']) . '.php')) {
1513
                    include_once str_replace('_', '/',
1514
                        $this->_channelInfo['validatepackage']['_content']) . '.php';
1515
                    $vclass = str_replace('.', '_',
1516
                        $this->_channelInfo['validatepackage']['_content']);
187 mathias 1517
                    $val = new $vclass;
94 jpm 1518
                } else {
1519
                    $a = false;
1520
                    return $a;
1521
                }
1522
            } else {
1523
                $vclass = str_replace('.', '_',
1524
                    $this->_channelInfo['validatepackage']['_content']);
187 mathias 1525
                $val = new $vclass;
94 jpm 1526
            }
1527
        } else {
187 mathias 1528
            $val = new PEAR_Validate;
94 jpm 1529
        }
187 mathias 1530
 
94 jpm 1531
        return $val;
1532
    }
1533
 
1534
    function isIncludeable($path)
1535
    {
1536
        $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
1537
        foreach ($possibilities as $dir) {
1538
            if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
1539
                  && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
1540
                return true;
1541
            }
1542
        }
187 mathias 1543
 
94 jpm 1544
        return false;
1545
    }
1546
 
1547
    /**
1548
     * This function is used by the channel updater and retrieves a value set by
1549
     * the registry, or the current time if it has not been set
1550
     * @return string
1551
     */
1552
    function lastModified()
1553
    {
1554
        if (isset($this->_channelInfo['_lastmodified'])) {
1555
            return $this->_channelInfo['_lastmodified'];
1556
        }
187 mathias 1557
 
94 jpm 1558
        return time();
1559
    }
1560
}