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
 * LICENSE: This source file is subject to version 3.0 of the PHP license
8
 * that is available through the world-wide-web at the following URI:
9
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
10
 * the PHP License and are unable to obtain it through the web, please
11
 * send a note to license@php.net so we can mail you a copy immediately.
12
 *
13
 * @category   pear
14
 * @package    PEAR
15
 * @author     Greg Beaver <cellog@php.net>
16
 * @copyright  1997-2006 The PHP Group
17
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
18
 * @version    CVS: $Id: ChannelFile.php,v 1.78 2006/10/31 02:54:40 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-2006 The PHP Group
154
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
155
 * @version    Release: 1.5.1
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' => $error));
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
            $i = 0;
715
            foreach ($info['servers']['mirror'] as $mirror) {
716
                if (!isset($mirror['attribs']['host'])) {
717
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
718
                      array('type' => 'mirror'));
719
                } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
720
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
721
                        array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
722
                }
723
                if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
724
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
725
                        array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
726
                }
727
                if (isset($mirror['xmlrpc'])) {
728
                    $this->_validateFunctions('xmlrpc',
729
                        $mirror['xmlrpc']['function'], $mirror['attribs']['host']);
730
                }
731
                if (isset($mirror['soap'])) {
732
                    $this->_validateFunctions('soap', $mirror['soap']['function'],
733
                        $mirror['attribs']['host']);
734
                }
735
                if (isset($mirror['rest'])) {
736
                    $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
737
                        $mirror['attribs']['host']);
738
                }
739
            }
740
        }
741
        return $this->_isValid;
742
    }
743
 
744
    /**
745
     * @param string xmlrpc or soap - protocol name this function applies to
746
     * @param array the functions
747
     * @param string the name of the parent element (mirror name, for instance)
748
     */
749
    function _validateFunctions($protocol, $functions, $parent = '')
750
    {
751
        if (!isset($functions[0])) {
752
            $functions = array($functions);
753
        }
754
        foreach ($functions as $function) {
755
            if (!isset($function['_content']) || empty($function['_content'])) {
756
                $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
757
                    array('parent' => $parent, 'protocol' => $protocol));
758
            }
759
            if ($protocol == 'rest') {
760
                if (!isset($function['attribs']['type']) ||
761
                      empty($function['attribs']['type'])) {
762
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE,
763
                        array('parent' => $parent, 'protocol' => $protocol));
764
                }
765
            } else {
766
                if (!isset($function['attribs']['version']) ||
767
                      empty($function['attribs']['version'])) {
768
                    $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
769
                        array('parent' => $parent, 'protocol' => $protocol));
770
                }
771
            }
772
        }
773
    }
774
 
775
    /**
776
     * Test whether a string contains a valid channel server.
777
     * @param string $ver the package version to test
778
     * @return bool
779
     */
780
    function validChannelServer($server)
781
    {
782
        if ($server == '__uri') {
783
            return true;
784
        }
785
        return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
786
    }
787
 
788
    /**
789
     * @return string|false
790
     */
791
    function getName()
792
    {
793
        if (isset($this->_channelInfo['name'])) {
794
            return $this->_channelInfo['name'];
795
        } else {
796
            return false;
797
        }
798
    }
799
 
800
    /**
801
     * @return string|false
802
     */
803
    function getServer()
804
    {
805
        if (isset($this->_channelInfo['name'])) {
806
            return $this->_channelInfo['name'];
807
        } else {
808
            return false;
809
        }
810
    }
811
 
812
    /**
813
     * @return int|80 port number to connect to
814
     */
815
    function getPort($mirror = false)
816
    {
817
        if ($mirror) {
818
            if ($mir = $this->getMirror($mirror)) {
819
                if (isset($mir['attribs']['port'])) {
820
                    return $mir['attribs']['port'];
821
                } else {
822
                    if ($this->getSSL($mirror)) {
823
                        return 443;
824
                    }
825
                    return 80;
826
                }
827
            }
828
            return false;
829
        }
830
        if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
831
            return $this->_channelInfo['servers']['primary']['attribs']['port'];
832
        }
833
        if ($this->getSSL()) {
834
            return 443;
835
        }
836
        return 80;
837
    }
838
 
839
    /**
840
     * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
841
     */
842
    function getSSL($mirror = false)
843
    {
844
        if ($mirror) {
845
            if ($mir = $this->getMirror($mirror)) {
846
                if (isset($mir['attribs']['ssl'])) {
847
                    return true;
848
                } else {
849
                    return false;
850
                }
851
            }
852
            return false;
853
        }
854
        if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
855
            return true;
856
        }
857
        return false;
858
    }
859
 
860
    /**
861
     * @return string|false
862
     */
863
    function getSummary()
864
    {
865
        if (isset($this->_channelInfo['summary'])) {
866
            return $this->_channelInfo['summary'];
867
        } else {
868
            return false;
869
        }
870
    }
871
 
872
    /**
873
     * @param string xmlrpc or soap
874
     * @param string|false mirror name or false for primary server
875
     */
876
    function getPath($protocol, $mirror = false)
877
    {
878
        if (!in_array($protocol, array('xmlrpc', 'soap'))) {
879
            return false;
880
        }
881
        if ($mirror) {
882
            if (!($mir = $this->getMirror($mirror))) {
883
                return false;
884
            }
885
            if (isset($mir[$protocol]['attribs']['path'])) {
886
                return $mir[$protocol]['attribs']['path'];
887
            } else {
888
                return $protocol . '.php';
889
            }
890
        } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) {
891
            return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'];
892
        }
893
        return $protocol . '.php';
894
    }
895
 
896
    /**
897
     * @param string protocol type (xmlrpc, soap)
898
     * @param string Mirror name
899
     * @return array|false
900
     */
901
    function getFunctions($protocol, $mirror = false)
902
    {
903
        if ($this->getName() == '__uri') {
904
            return false;
905
        }
906
        if ($protocol == 'rest') {
907
            $function = 'baseurl';
908
        } else {
909
            $function = 'function';
910
        }
911
        if ($mirror) {
912
            if ($mir = $this->getMirror($mirror)) {
913
                if (isset($mir[$protocol][$function])) {
914
                    return $mir[$protocol][$function];
915
                }
916
            }
917
            return false;
918
        }
919
        if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
920
            return $this->_channelInfo['servers']['primary'][$protocol][$function];
921
        } else {
922
            return false;
923
        }
924
    }
925
 
926
    /**
927
     * @param string Protocol type
928
     * @param string Function name (null to return the
929
     *               first protocol of the type requested)
930
     * @param string Mirror name, if any
931
     * @return array
932
     */
933
     function getFunction($type, $name = null, $mirror = false)
934
     {
935
        $protocols = $this->getFunctions($type, $mirror);
936
        if (!$protocols) {
937
            return false;
938
        }
939
        foreach ($protocols as $protocol) {
940
            if ($name === null) {
941
                return $protocol;
942
            }
943
            if ($protocol['_content'] != $name) {
944
                continue;
945
            }
946
            return $protocol;
947
        }
948
        return false;
949
     }
950
 
951
    /**
952
     * @param string protocol type
953
     * @param string protocol name
954
     * @param string version
955
     * @param string mirror name
956
     * @return boolean
957
     */
958
    function supports($type, $name = null, $mirror = false, $version = '1.0')
959
    {
960
        $protocols = $this->getFunctions($type, $mirror);
961
        if (!$protocols) {
962
            return false;
963
        }
964
        foreach ($protocols as $protocol) {
965
            if ($protocol['attribs']['version'] != $version) {
966
                continue;
967
            }
968
            if ($name === null) {
969
                return true;
970
            }
971
            if ($protocol['_content'] != $name) {
972
                continue;
973
            }
974
            return true;
975
        }
976
        return false;
977
    }
978
 
979
    /**
980
     * Determines whether a channel supports Representational State Transfer (REST) protocols
981
     * for retrieving channel information
982
     * @param string
983
     * @return bool
984
     */
985
    function supportsREST($mirror = false)
986
    {
987
        if ($mirror == $this->_channelInfo['name']) {
988
            $mirror = false;
989
        }
990
        if ($mirror) {
991
            if ($mir = $this->getMirror($mirror)) {
992
                return isset($mir['rest']);
993
            }
994
            return false;
995
        }
996
        return isset($this->_channelInfo['servers']['primary']['rest']);
997
    }
998
 
999
    /**
1000
     * Get the URL to access a base resource.
1001
     *
1002
     * Hyperlinks in the returned xml will be used to retrieve the proper information
1003
     * needed.  This allows extreme extensibility and flexibility in implementation
1004
     * @param string Resource Type to retrieve
1005
     */
1006
    function getBaseURL($resourceType, $mirror = false)
1007
    {
1008
        if ($mirror == $this->_channelInfo['name']) {
1009
            $mirror = false;
1010
        }
1011
        if ($mirror) {
1012
            if ($mir = $this->getMirror($mirror)) {
1013
                $rest = $mir['rest'];
1014
            } else {
1015
                return false;
1016
            }
1017
            $server = $mirror;
1018
        } else {
1019
            $rest = $this->_channelInfo['servers']['primary']['rest'];
1020
            $server = $this->getServer();
1021
        }
1022
        if (!isset($rest['baseurl'][0])) {
1023
            $rest['baseurl'] = array($rest['baseurl']);
1024
        }
1025
        foreach ($rest['baseurl'] as $baseurl) {
1026
            if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
1027
                return $baseurl['_content'];
1028
            }
1029
        }
1030
        return false;
1031
    }
1032
 
1033
    /**
1034
     * Since REST does not implement RPC, provide this as a logical wrapper around
1035
     * resetFunctions for REST
1036
     * @param string|false mirror name, if any
1037
     */
1038
    function resetREST($mirror = false)
1039
    {
1040
        return $this->resetFunctions('rest', $mirror);
1041
    }
1042
 
1043
    /**
1044
     * Empty all protocol definitions
1045
     * @param string protocol type (xmlrpc, soap)
1046
     * @param string|false mirror name, if any
1047
     */
1048
    function resetFunctions($type, $mirror = false)
1049
    {
1050
        if ($mirror) {
1051
            if (isset($this->_channelInfo['servers']['mirror'])) {
1052
                $mirrors = $this->_channelInfo['servers']['mirror'];
1053
                if (!isset($mirrors[0])) {
1054
                    $mirrors = array($mirrors);
1055
                }
1056
                foreach ($mirrors as $i => $mir) {
1057
                    if ($mir['attribs']['host'] == $mirror) {
1058
                        if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
1059
                            unset($this->_channelInfo['servers']['mirror'][$i][$type]);
1060
                        }
1061
                        return true;
1062
                    }
1063
                }
1064
                return false;
1065
            } else {
1066
                return false;
1067
            }
1068
        } else {
1069
            if (isset($this->_channelInfo['servers']['primary'][$type])) {
1070
                unset($this->_channelInfo['servers']['primary'][$type]);
1071
            }
1072
            return true;
1073
        }
1074
    }
1075
 
1076
    /**
1077
     * Set a channel's protocols to the protocols supported by pearweb
1078
     */
1079
    function setDefaultPEARProtocols($version = '1.0', $mirror = false)
1080
    {
1081
        switch ($version) {
1082
            case '1.0' :
1083
                $this->resetFunctions('xmlrpc', $mirror);
1084
                $this->resetFunctions('soap', $mirror);
1085
                $this->resetREST($mirror);
1086
                $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror);
1087
                $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror);
1088
                $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror);
1089
                $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror);
1090
                $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror);
1091
                $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror);
1092
                $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror);
1093
                $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror);
1094
                $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror);
1095
                $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror);
1096
                return true;
1097
            break;
1098
            default :
1099
                return false;
1100
            break;
1101
        }
1102
    }
1103
 
1104
    /**
1105
     * @return array
1106
     */
1107
    function getMirrors()
1108
    {
1109
        if (isset($this->_channelInfo['servers']['mirror'])) {
1110
            $mirrors = $this->_channelInfo['servers']['mirror'];
1111
            if (!isset($mirrors[0])) {
1112
                $mirrors = array($mirrors);
1113
            }
1114
            return $mirrors;
1115
        } else {
1116
            return array();
1117
        }
1118
    }
1119
 
1120
    /**
1121
     * Get the unserialized XML representing a mirror
1122
     * @return array|false
1123
     */
1124
    function getMirror($server)
1125
    {
1126
        foreach ($this->getMirrors() as $mirror) {
1127
            if ($mirror['attribs']['host'] == $server) {
1128
                return $mirror;
1129
            }
1130
        }
1131
        return false;
1132
    }
1133
 
1134
    /**
1135
     * @param string
1136
     * @return string|false
1137
     * @error PEAR_CHANNELFILE_ERROR_NO_NAME
1138
     * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
1139
     */
1140
    function setName($name)
1141
    {
1142
        return $this->setServer($name);
1143
    }
1144
 
1145
    /**
1146
     * Set the socket number (port) that is used to connect to this channel
1147
     * @param integer
1148
     * @param string|false name of the mirror server, or false for the primary
1149
     */
1150
    function setPort($port, $mirror = false)
1151
    {
1152
        if ($mirror) {
1153
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1154
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1155
                    array('mirror' => $mirror));
1156
                return false;
1157
            }
1158
            $setmirror = false;
1159
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1160
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1161
                    if ($mirror == $mir['attribs']['host']) {
1162
                        $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
1163
                        return true;
1164
                    }
1165
                }
1166
                return false;
1167
            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1168
                $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
1169
                $this->_isValid = false;
1170
                return true;
1171
            }
1172
        }
1173
        $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
1174
        $this->_isValid = false;
1175
        return true;
1176
    }
1177
 
1178
    /**
1179
     * Set the socket number (port) that is used to connect to this channel
1180
     * @param bool Determines whether to turn on SSL support or turn it off
1181
     * @param string|false name of the mirror server, or false for the primary
1182
     */
1183
    function setSSL($ssl = true, $mirror = false)
1184
    {
1185
        if ($mirror) {
1186
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1187
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1188
                    array('mirror' => $mirror));
1189
                return false;
1190
            }
1191
            $setmirror = false;
1192
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1193
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1194
                    if ($mirror == $mir['attribs']['host']) {
1195
                        if (!$ssl) {
1196
                            if (isset($this->_channelInfo['servers']['mirror'][$i]
1197
                                  ['attribs']['ssl'])) {
1198
                                unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
1199
                            }
1200
                        } else {
1201
                            $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
1202
                        }
1203
                        return true;
1204
                    }
1205
                }
1206
                return false;
1207
            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1208
                if (!$ssl) {
1209
                    if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
1210
                        unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
1211
                    }
1212
                } else {
1213
                    $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
1214
                }
1215
                $this->_isValid = false;
1216
                return true;
1217
            }
1218
        }
1219
        if ($ssl) {
1220
            $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
1221
        } else {
1222
            if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
1223
                unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
1224
            }
1225
        }
1226
        $this->_isValid = false;
1227
        return true;
1228
    }
1229
 
1230
    /**
1231
     * Set the socket number (port) that is used to connect to this channel
1232
     * @param integer
1233
     * @param string|false name of the mirror server, or false for the primary
1234
     */
1235
    function setPath($protocol, $path, $mirror = false)
1236
    {
1237
        if (!in_array($protocol, array('xmlrpc', 'soap'))) {
1238
            return false;
1239
        }
1240
        if ($mirror) {
1241
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1242
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1243
                    array('mirror' => $mirror));
1244
                return false;
1245
            }
1246
            $setmirror = false;
1247
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1248
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1249
                    if ($mirror == $mir['attribs']['host']) {
1250
                        $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] =
1251
                            $path;
1252
                        return true;
1253
                    }
1254
                }
1255
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1256
                    array('mirror' => $mirror));
1257
                return false;
1258
            } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1259
                $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path;
1260
                $this->_isValid = false;
1261
                return true;
1262
            }
1263
        }
1264
        $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path;
1265
        $this->_isValid = false;
1266
        return true;
1267
    }
1268
 
1269
    /**
1270
     * @param string
1271
     * @return string|false
1272
     * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
1273
     * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
1274
     */
1275
    function setServer($server, $mirror = false)
1276
    {
1277
        if (empty($server)) {
1278
            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
1279
            return false;
1280
        } elseif (!$this->validChannelServer($server)) {
1281
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
1282
                array('tag' => 'name', 'name' => $server));
1283
            return false;
1284
        }
1285
        if ($mirror) {
1286
            $found = false;
1287
            foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1288
                if ($mirror == $mir['attribs']['host']) {
1289
                    $found = true;
1290
                    break;
1291
                }
1292
            }
1293
            if (!$found) {
1294
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1295
                    array('mirror' => $mirror));
1296
                return false;
1297
            }
1298
            $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
1299
            return true;
1300
        }
1301
        $this->_channelInfo['name'] = $server;
1302
        return true;
1303
    }
1304
 
1305
    /**
1306
     * @param string
1307
     * @return boolean success
1308
     * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
1309
     * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
1310
     */
1311
    function setSummary($summary)
1312
    {
1313
        if (empty($summary)) {
1314
            $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
1315
            return false;
1316
        } elseif (strpos(trim($summary), "\n") !== false) {
1317
            $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
1318
                array('summary' => $summary));
1319
        }
1320
        $this->_channelInfo['summary'] = $summary;
1321
        return true;
1322
    }
1323
 
1324
    /**
1325
     * @param string
1326
     * @param boolean determines whether the alias is in channel.xml or local
1327
     * @return boolean success
1328
     */
1329
    function setAlias($alias, $local = false)
1330
    {
1331
        if (!$this->validChannelServer($alias)) {
1332
            $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
1333
                array('tag' => 'suggestedalias', 'name' => $alias));
1334
            return false;
1335
        }
1336
        if ($local) {
1337
            $this->_channelInfo['localalias'] = $alias;
1338
        } else {
1339
            $this->_channelInfo['suggestedalias'] = $alias;
1340
        }
1341
        return true;
1342
    }
1343
 
1344
    /**
1345
     * @return string
1346
     */
1347
    function getAlias()
1348
    {
1349
        if (isset($this->_channelInfo['localalias'])) {
1350
            return $this->_channelInfo['localalias'];
1351
        }
1352
        if (isset($this->_channelInfo['suggestedalias'])) {
1353
            return $this->_channelInfo['suggestedalias'];
1354
        }
1355
        if (isset($this->_channelInfo['name'])) {
1356
            return $this->_channelInfo['name'];
1357
        }
1358
    }
1359
 
1360
    /**
1361
     * Set the package validation object if it differs from PEAR's default
1362
     * The class must be includeable via changing _ in the classname to path separator,
1363
     * but no checking of this is made.
1364
     * @param string|false pass in false to reset to the default packagename regex
1365
     * @return boolean success
1366
     */
1367
    function setValidationPackage($validateclass, $version)
1368
    {
1369
        if (empty($validateclass)) {
1370
            unset($this->_channelInfo['validatepackage']);
1371
        }
1372
        $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
1373
        $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
1374
    }
1375
 
1376
    /**
1377
     * Add a protocol to the provides section
1378
     * @param string protocol type
1379
     * @param string protocol version
1380
     * @param string protocol name, if any
1381
     * @param string mirror name, if this is a mirror's protocol
1382
     * @return bool
1383
     */
1384
    function addFunction($type, $version, $name = '', $mirror = false)
1385
    {
1386
        if ($mirror) {
1387
            return $this->addMirrorFunction($mirror, $type, $version, $name);
1388
        }
1389
        $set = array('attribs' => array('version' => $version), '_content' => $name);
1390
        if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
1391
            if (!isset($this->_channelInfo['servers'])) {
1392
                $this->_channelInfo['servers'] = array('primary' =>
1393
                    array($type => array()));
1394
            } elseif (!isset($this->_channelInfo['servers']['primary'])) {
1395
                $this->_channelInfo['servers']['primary'] = array($type => array());
1396
            }
1397
            $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
1398
            $this->_isValid = false;
1399
            return true;
1400
        } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
1401
            $this->_channelInfo['servers']['primary'][$type]['function'] = array(
1402
                $this->_channelInfo['servers']['primary'][$type]['function']);
1403
        }
1404
        $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
1405
        return true;
1406
    }
1407
    /**
1408
     * Add a protocol to a mirror's provides section
1409
     * @param string mirror name (server)
1410
     * @param string protocol type
1411
     * @param string protocol version
1412
     * @param string protocol name, if any
1413
     */
1414
    function addMirrorFunction($mirror, $type, $version, $name = '')
1415
    {
1416
        $found = false;
1417
        if (!isset($this->_channelInfo['servers']['mirror'])) {
1418
            $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1419
                array('mirror' => $mirror));
1420
            return false;
1421
        }
1422
        $setmirror = false;
1423
        if (isset($this->_channelInfo['servers']['mirror'][0])) {
1424
            foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1425
                if ($mirror == $mir['attribs']['host']) {
1426
                    $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
1427
                    break;
1428
                }
1429
            }
1430
        } else {
1431
            if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1432
                $setmirror = &$this->_channelInfo['servers']['mirror'];
1433
            }
1434
        }
1435
        if (!$setmirror) {
1436
            $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1437
                array('mirror' => $mirror));
1438
            return false;
1439
        }
1440
        $set = array('attribs' => array('version' => $version), '_content' => $name);
1441
        if (!isset($setmirror[$type]['function'])) {
1442
            $setmirror[$type]['function'] = $set;
1443
            $this->_isValid = false;
1444
            return true;
1445
        } elseif (!isset($setmirror[$type]['function'][0])) {
1446
            $setmirror[$type]['function'] = array($setmirror[$type]['function']);
1447
        }
1448
        $setmirror[$type]['function'][] = $set;
1449
        $this->_isValid = false;
1450
        return true;
1451
    }
1452
 
1453
    /**
1454
     * @param string Resource Type this url links to
1455
     * @param string URL
1456
     * @param string|false mirror name, if this is not a primary server REST base URL
1457
     */
1458
    function setBaseURL($resourceType, $url, $mirror = false)
1459
    {
1460
        if ($mirror) {
1461
            $found = false;
1462
            if (!isset($this->_channelInfo['servers']['mirror'])) {
1463
                $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
1464
                    array('mirror' => $mirror));
1465
                return false;
1466
            }
1467
            $setmirror = false;
1468
            if (isset($this->_channelInfo['servers']['mirror'][0])) {
1469
                foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
1470
                    if ($mirror == $mir['attribs']['host']) {
1471
                        $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
1472
                        break;
1473
                    }
1474
                }
1475
            } else {
1476
                if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
1477
                    $setmirror = &$this->_channelInfo['servers']['mirror'];
1478
                }
1479
            }
1480
        } else {
1481
            $setmirror = &$this->_channelInfo['servers']['primary'];
1482
        }
1483
        $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
1484
        if (!isset($setmirror['rest'])) {
1485
            $setmirror['rest'] = array();
1486
        }
1487
        if (!isset($setmirror['rest']['baseurl'])) {
1488
            $setmirror['rest']['baseurl'] = $set;
1489
            $this->_isValid = false;
1490
            return true;
1491
        } elseif (!isset($setmirror['rest']['baseurl'][0])) {
1492
            $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
1493
        }
1494
        foreach ($setmirror['rest']['baseurl'] as $i => $url) {
1495
            if ($url['attribs']['type'] == $resourceType) {
1496
                $this->_isValid = false;
1497
                $setmirror['rest']['baseurl'][$i] = $set;
1498
                return true;
1499
            }
1500
        }
1501
        $setmirror['rest']['baseurl'][] = $set;
1502
        $this->_isValid = false;
1503
        return true;
1504
    }
1505
 
1506
    /**
1507
     * @param string mirror server
1508
     * @param int mirror http port
1509
     * @return boolean
1510
     */
1511
    function addMirror($server, $port = null)
1512
    {
1513
        if ($this->_channelInfo['name'] == '__uri') {
1514
            return false; // the __uri channel cannot have mirrors by definition
1515
        }
1516
        $set = array('attribs' => array('host' => $server));
1517
        if (is_numeric($port)) {
1518
            $set['attribs']['port'] = $port;
1519
        }
1520
        if (!isset($this->_channelInfo['servers']['mirror'])) {
1521
            $this->_channelInfo['servers']['mirror'] = $set;
1522
            return true;
1523
        } else {
1524
            if (!isset($this->_channelInfo['servers']['mirror'][0])) {
1525
                $this->_channelInfo['servers']['mirror'] =
1526
                    array($this->_channelInfo['servers']['mirror']);
1527
            }
1528
        }
1529
        $this->_channelInfo['servers']['mirror'][] = $set;
1530
        return true;
1531
    }
1532
 
1533
    /**
1534
     * Retrieve the name of the validation package for this channel
1535
     * @return string|false
1536
     */
1537
    function getValidationPackage()
1538
    {
1539
        if (!$this->_isValid && !$this->validate()) {
1540
            return false;
1541
        }
1542
        if (!isset($this->_channelInfo['validatepackage'])) {
1543
            return array('attribs' => array('version' => 'default'),
1544
                '_content' => 'PEAR_Validate');
1545
        }
1546
        return $this->_channelInfo['validatepackage'];
1547
    }
1548
 
1549
    /**
1550
     * Retrieve the object that can be used for custom validation
1551
     * @param string|false the name of the package to validate.  If the package is
1552
     *                     the channel validation package, PEAR_Validate is returned
1553
     * @return PEAR_Validate|false false is returned if the validation package
1554
     *         cannot be located
1555
     */
1556
    function &getValidationObject($package = false)
1557
    {
1558
        if (!class_exists('PEAR_Validate')) {
1559
            require_once 'PEAR/Validate.php';
1560
        }
1561
        if (!$this->_isValid) {
1562
            if (!$this->validate()) {
1563
                $a = false;
1564
                return $a;
1565
            }
1566
        }
1567
        if (isset($this->_channelInfo['validatepackage'])) {
1568
            if ($package == $this->_channelInfo['validatepackage']) {
1569
                // channel validation packages are always validated by PEAR_Validate
1570
                $val = &new PEAR_Validate;
1571
                return $val;
1572
            }
1573
            if (!class_exists(str_replace('.', '_',
1574
                  $this->_channelInfo['validatepackage']['_content']))) {
1575
                if ($this->isIncludeable(str_replace('_', '/',
1576
                      $this->_channelInfo['validatepackage']['_content']) . '.php')) {
1577
                    include_once str_replace('_', '/',
1578
                        $this->_channelInfo['validatepackage']['_content']) . '.php';
1579
                    $vclass = str_replace('.', '_',
1580
                        $this->_channelInfo['validatepackage']['_content']);
1581
                    $val = &new $vclass;
1582
                } else {
1583
                    $a = false;
1584
                    return $a;
1585
                }
1586
            } else {
1587
                $vclass = str_replace('.', '_',
1588
                    $this->_channelInfo['validatepackage']['_content']);
1589
                $val = &new $vclass;
1590
            }
1591
        } else {
1592
            $val = &new PEAR_Validate;
1593
        }
1594
        return $val;
1595
    }
1596
 
1597
    function isIncludeable($path)
1598
    {
1599
        $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
1600
        foreach ($possibilities as $dir) {
1601
            if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
1602
                  && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
1603
                return true;
1604
            }
1605
        }
1606
        return false;
1607
    }
1608
 
1609
    /**
1610
     * This function is used by the channel updater and retrieves a value set by
1611
     * the registry, or the current time if it has not been set
1612
     * @return string
1613
     */
1614
    function lastModified()
1615
    {
1616
        if (isset($this->_channelInfo['_lastmodified'])) {
1617
            return $this->_channelInfo['_lastmodified'];
1618
        }
1619
        return time();
1620
    }
1621
}
1622
?>