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