Хранилища Subversion ant

Редакция

Содержимое файла | Последнее изменение | Открыть журнал | RSS

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