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