ChannelFile.php 50 KB

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