source: branches/version-2_13-dev/data/module/PEAR/ChannelFile.php @ 23125

Revision 23125, 49.7 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

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