PageRenderTime 64ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/include/xmlrpc.inc

https://github.com/leachim6/upc
PHP | 498 lines | 400 code | 44 blank | 54 comment | 62 complexity | ebbb79bfa0093347e299854623ea8601 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. * @brief
  4. * XML-RPC Library
  5. * @file
  6. * An XML-RPC implementation by Keith Devens, version 2.5f.
  7. * http://www.keithdevens.com/software/xmlrpc/
  8. * Release history available at:
  9. * http://www.keithdevens.com/software/xmlrpc/history/
  10. * This code is Open Source, released under terms similar to the Artistic License.
  11. * Read the license at http://www.keithdevens.com/software/license/
  12. * Note: this code requires version 4.1.0 or higher of PHP.
  13. *
  14. * @see http://keithdevens.com/software/xmlrpc
  15. */
  16. function & XML_serialize(&$data, $level = 0, $prior_key = NULL){
  17. #assumes a hash, keys are the variable names
  18. $xml_serialized_string = "";
  19. while(list($key, $value) = each($data)){
  20. $inline = false;
  21. $numeric_array = false;
  22. $attributes = "";
  23. #echo "My current key is '$key', called with prior key '$prior_key'<br>";
  24. if(!strstr($key, " attr")){ #if it's not an attribute
  25. if(array_key_exists("$key attr", $data)){
  26. while(list($attr_name, $attr_value) = each($data["$key attr"])){
  27. #echo "Found attribute $attribute_name with value $attribute_value<br>";
  28. $attr_value = &htmlspecialchars($attr_value, ENT_QUOTES);
  29. $attributes .= " $attr_name=\"$attr_value\"";
  30. }
  31. }
  32. if(is_numeric($key)){
  33. #echo "My current key ($key) is numeric. My parent key is '$prior_key'<br>";
  34. $key = $prior_key;
  35. }else{
  36. #you can't have numeric keys at two levels in a row, so this is ok
  37. #echo "Checking to see if a numeric key exists in data.";
  38. if(is_array($value) and array_key_exists(0, $value)){
  39. # echo " It does! Calling myself as a result of a numeric array.<br>";
  40. $numeric_array = true;
  41. $xml_serialized_string .= XML_serialize($value, $level, $key);
  42. }
  43. #echo "<br>";
  44. }
  45. if(!$numeric_array){
  46. $xml_serialized_string .= str_repeat("\t", $level) . "<$key$attributes>";
  47. if(is_array($value)){
  48. $xml_serialized_string .= "\r\n" . XML_serialize($value, $level+1);
  49. }else{
  50. $inline = true;
  51. $xml_serialized_string .= htmlspecialchars($value);
  52. }
  53. $xml_serialized_string .= (!$inline ? str_repeat("\t", $level) : "") . "</$key>\r\n";
  54. }
  55. }else{
  56. #echo "Skipping attribute record for key $key<bR>";
  57. }
  58. }
  59. if($level == 0){
  60. $xml_serialized_string = "<?xml version=\"1.0\" ?>\r\n" . $xml_serialized_string;
  61. return $xml_serialized_string;
  62. }else{
  63. return $xml_serialized_string;
  64. }
  65. }
  66. class XML {
  67. var $parser; #a reference to the XML parser
  68. var $document; #the entire XML structure built up so far
  69. var $current; #a pointer to the current item - what is this
  70. var $parent; #a pointer to the current parent - the parent will be an array
  71. var $parents; #an array of the most recent parent at each level
  72. var $last_opened_tag;
  73. function XML($data=null){
  74. $this->parser = xml_parser_create();
  75. xml_parser_set_option ($this->parser, XML_OPTION_CASE_FOLDING, 0);
  76. xml_set_object($this->parser, &$this);
  77. xml_set_element_handler($this->parser, "open", "close");
  78. xml_set_character_data_handler($this->parser, "data");
  79. # register_shutdown_function(array(&$this, 'destruct'));
  80. }
  81. function destruct(){
  82. xml_parser_free($this->parser);
  83. }
  84. function parse($data){
  85. $this->document = array();
  86. $this->parent = &$this->document;
  87. $this->parents = array();
  88. $this->last_opened_tag = NULL;
  89. xml_parse($this->parser, $data);
  90. return $this->document;
  91. }
  92. function open($parser, $tag, $attributes){
  93. #echo "Opening tag $tag<br>\n";
  94. $this->data = "";
  95. $this->last_opened_tag = $tag; #tag is a string
  96. if(array_key_exists($tag, $this->parent)){
  97. #echo "There's already an instance of '$tag' at the current level ($level)<br>\n";
  98. if(is_array($this->parent[$tag]) and array_key_exists(0, $this->parent[$tag])){ #if the keys are numeric
  99. #need to make sure they're numeric (account for attributes)
  100. $key = count_numeric_items($this->parent[$tag]);
  101. #echo "There are $key instances: the keys are numeric.<br>\n";
  102. }else{
  103. #echo "There is only one instance. Shifting everything around<br>\n";
  104. $temp = &$this->parent[$tag];
  105. unset($this->parent[$tag]);
  106. $this->parent[$tag][0] = &$temp;
  107. if(array_key_exists("$tag attr", $this->parent)){
  108. #shift the attributes around too if they exist
  109. $temp = &$this->parent["$tag attr"];
  110. unset($this->parent["$tag attr"]);
  111. $this->parent[$tag]["0 attr"] = &$temp;
  112. }
  113. $key = 1;
  114. }
  115. $this->parent = &$this->parent[$tag];
  116. }else{
  117. $key = $tag;
  118. }
  119. if($attributes){
  120. $this->parent["$key attr"] = $attributes;
  121. }
  122. $this->parent[$key] = array();
  123. $this->parent = &$this->parent[$key];
  124. array_unshift($this->parents, &$this->parent);
  125. }
  126. function data($parser, $data){
  127. #echo "Data is '", htmlspecialchars($data), "'<br>\n";
  128. if($this->last_opened_tag != NULL){
  129. $this->data .= $data;
  130. }
  131. }
  132. function close($parser, $tag){
  133. #echo "Close tag $tag<br>\n";
  134. if($this->last_opened_tag == $tag){
  135. $this->parent = $this->data;
  136. $this->last_opened_tag = NULL;
  137. }
  138. array_shift($this->parents);
  139. $this->parent = &$this->parents[0];
  140. }
  141. }
  142. function & XML_unserialize(&$xml){
  143. $xml_parser = new XML();
  144. $data = &$xml_parser->parse(&$xml);
  145. $xml_parser->destruct();
  146. return $data;
  147. }
  148. function & XMLRPC_parse(&$request){
  149. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  150. XMLRPC_debug('XMLRPC_parse', "<p>Received the following raw request:</p>" . XMLRPC_show($request, 'print_r', true));
  151. }
  152. $data = &XML_unserialize(&$request);
  153. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  154. XMLRPC_debug('XMLRPC_parse', "<p>Returning the following parsed request:</p>" . XMLRPC_show($data, 'print_r', true));
  155. }
  156. return $data;
  157. }
  158. function & XMLRPC_prepare($data, $type = NULL){
  159. if(is_array($data)){
  160. $num_elements = count($data);
  161. if((array_key_exists(0, $data) or !$num_elements) and $type != 'struct'){ #it's an array
  162. if(!$num_elements){ #if the array is empty
  163. $returnvalue = array('array' => array('data' => NULL));
  164. }else{
  165. $returnvalue['array']['data']['value'] = array();
  166. $temp = &$returnvalue['array']['data']['value'];
  167. $count = count_numeric_items($data);
  168. for($n=0; $n<$count; $n++){
  169. $type = NULL;
  170. if(array_key_exists("$n type", $data)){
  171. $type = $data["$n type"];
  172. }
  173. $temp[$n] = XMLRPC_prepare(&$data[$n], $type);
  174. }
  175. }
  176. }else{ #it's a struct
  177. if(!$num_elements){ #if the struct is empty
  178. $returnvalue = array('struct' => NULL);
  179. }else{
  180. $returnvalue['struct']['member'] = array();
  181. $temp = &$returnvalue['struct']['member'];
  182. while(list($key, $value) = each($data)){
  183. if(substr($key, -5) != ' type'){ #if it's not a type specifier
  184. $type = NULL;
  185. if(array_key_exists("$key type", $data)){
  186. $type = $data["$key type"];
  187. }
  188. $temp[] = array('name' => $key, 'value' => XMLRPC_prepare(&$value, $type));
  189. }
  190. }
  191. }
  192. }
  193. }else{ #it's a scalar
  194. if(!$type){
  195. if(is_int($data)){
  196. $returnvalue['int'] = $data;
  197. return $returnvalue;
  198. }elseif(is_float($data)){
  199. $returnvalue['double'] = $data;
  200. return $returnvalue;
  201. }elseif(is_bool($data)){
  202. $returnvalue['boolean'] = ($data ? 1 : 0);
  203. return $returnvalue;
  204. }elseif(preg_match('/^\d{8}T\d{2}:\d{2}:\d{2}$/', $data, $matches)){ #it's a date
  205. $returnvalue['dateTime.iso8601'] = $data;
  206. return $returnvalue;
  207. }elseif(is_string($data)){
  208. $returnvalue['string'] = htmlspecialchars($data);
  209. return $returnvalue;
  210. }
  211. }else{
  212. $returnvalue[$type] = htmlspecialchars($data);
  213. }
  214. }
  215. return $returnvalue;
  216. }
  217. function & XMLRPC_adjustValue(&$current_node){
  218. if(is_array($current_node)){
  219. if(isset($current_node['array'])){
  220. if(!is_array($current_node['array']['data'])){
  221. #If there are no elements, return an empty array
  222. return array();
  223. }else{
  224. #echo "Getting rid of array -> data -> value<br>\n";
  225. $temp = &$current_node['array']['data']['value'];
  226. if(is_array($temp) and array_key_exists(0, $temp)){
  227. $count = count($temp);
  228. for($n=0;$n<$count;$n++){
  229. $temp2[$n] = &XMLRPC_adjustValue(&$temp[$n]);
  230. }
  231. $temp = &$temp2;
  232. }else{
  233. $temp2 = &XMLRPC_adjustValue(&$temp);
  234. $temp = array(&$temp2);
  235. #I do the temp assignment because it avoids copying,
  236. # since I can put a reference in the array
  237. #PHP's reference model is a bit silly, and I can't just say:
  238. # $temp = array(&XMLRPC_adjustValue(&$temp));
  239. }
  240. }
  241. }elseif(isset($current_node['struct'])){
  242. if(!is_array($current_node['struct'])){
  243. #If there are no members, return an empty array
  244. return array();
  245. }else{
  246. #echo "Getting rid of struct -> member<br>\n";
  247. $temp = &$current_node['struct']['member'];
  248. if(is_array($temp) and array_key_exists(0, $temp)){
  249. $count = count($temp);
  250. for($n=0;$n<$count;$n++){
  251. #echo "Passing name {$temp[$n][name]}. Value is: " . show($temp[$n][value], var_dump, true) . "<br>\n";
  252. $temp2[$temp[$n]['name']] = &XMLRPC_adjustValue(&$temp[$n]['value']);
  253. #echo "adjustValue(): After assigning, the value is " . show($temp2[$temp[$n]['name']], var_dump, true) . "<br>\n";
  254. }
  255. }else{
  256. #echo "Passing name $temp[name]<br>\n";
  257. $temp2[$temp['name']] = &XMLRPC_adjustValue(&$temp['value']);
  258. }
  259. $temp = &$temp2;
  260. }
  261. }else{
  262. $types = array('string', 'int', 'i4', 'double', 'dateTime.iso8601', 'base64', 'boolean');
  263. $fell_through = true;
  264. foreach($types as $type){
  265. if(array_key_exists($type, $current_node)){
  266. #echo "Getting rid of '$type'<br>\n";
  267. $temp = &$current_node[$type];
  268. #echo "adjustValue(): The current node is set with a type of $type<br>\n";
  269. $fell_through = false;
  270. break;
  271. }
  272. }
  273. if($fell_through){
  274. $type = 'string';
  275. #echo "Fell through! Type is $type<br>\n";
  276. }
  277. switch ($type){
  278. case 'int': case 'i4': $temp = (int)$temp; break;
  279. case 'string': $temp = (string)$temp; break;
  280. case 'double': $temp = (double)$temp; break;
  281. case 'boolean': $temp = (bool)$temp; break;
  282. }
  283. }
  284. }else{
  285. $temp = (string)$current_node;
  286. }
  287. return $temp;
  288. }
  289. function XMLRPC_getParams($request){
  290. if(!is_array($request['methodCall']['params'])){
  291. #If there are no parameters, return an empty array
  292. return array();
  293. }else{
  294. #echo "Getting rid of methodCall -> params -> param<br>\n";
  295. $temp = &$request['methodCall']['params']['param'];
  296. if(is_array($temp) and array_key_exists(0, $temp)){
  297. $count = count($temp);
  298. for($n = 0; $n < $count; $n++){
  299. #echo "Serializing parameter $n<br>";
  300. $temp2[$n] = &XMLRPC_adjustValue(&$temp[$n]['value']);
  301. }
  302. }else{
  303. $temp2[0] = &XMLRPC_adjustValue($temp['value']);
  304. }
  305. $temp = &$temp2;
  306. return $temp;
  307. }
  308. }
  309. function XMLRPC_getMethodName($methodCall){
  310. #returns the method name
  311. return $methodCall['methodCall']['methodName'];
  312. }
  313. function XMLRPC_request($site, $location, $methodName, $params = NULL, $user_agent = NULL){
  314. $site = explode(':', $site);
  315. if(isset($site[1]) and is_numeric($site[1])){
  316. $port = $site[1];
  317. }else{
  318. $port = 80;
  319. }
  320. $site = $site[0];
  321. $data["methodCall"]["methodName"] = $methodName;
  322. $param_count = count($params);
  323. if(!$param_count){
  324. $data["methodCall"]["params"] = NULL;
  325. }else{
  326. for($n = 0; $n<$param_count; $n++){
  327. $data["methodCall"]["params"]["param"][$n]["value"] = $params[$n];
  328. }
  329. }
  330. $data = XML_serialize($data);
  331. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  332. XMLRPC_debug('XMLRPC_request', "<p>Received the following parameter list to send:</p>" . XMLRPC_show($params, 'print_r', true));
  333. }
  334. $conn = fsockopen ($site, $port); #open the connection
  335. if(!$conn){ #if the connection was not opened successfully
  336. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  337. XMLRPC_debug('XMLRPC_request', "<p>Connection failed: Couldn't make the connection to $site.</p>");
  338. }
  339. return array(false, array('faultCode'=>10532, 'faultString'=>"Connection failed: Couldn't make the connection to $site."));
  340. }else{
  341. $headers =
  342. "POST $location HTTP/1.0\r\n" .
  343. "Host: $site\r\n" .
  344. "Connection: close\r\n" .
  345. ($user_agent ? "User-Agent: $user_agent\r\n" : '') .
  346. "Content-Type: text/xml\r\n" .
  347. "Content-Length: " . strlen($data) . "\r\n\r\n";
  348. fputs($conn, "$headers");
  349. fputs($conn, $data);
  350. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  351. XMLRPC_debug('XMLRPC_request', "<p>Sent the following request:</p>\n\n" . XMLRPC_show($headers . $data, 'print_r', true));
  352. }
  353. #socket_set_blocking ($conn, false);
  354. $response = "";
  355. while(!feof($conn)){
  356. $response .= fgets($conn, 1024);
  357. }
  358. fclose($conn);
  359. #strip headers off of response
  360. $data = XML_unserialize(substr($response, strpos($response, "\r\n\r\n")+4));
  361. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  362. XMLRPC_debug('XMLRPC_request', "<p>Received the following response:</p>\n\n" . XMLRPC_show($response, 'print_r', true) . "<p>Which was serialized into the following data:</p>\n\n" . XMLRPC_show($data, 'print_r', true));
  363. }
  364. if(isset($data['methodResponse']['fault'])){
  365. $return = array(false, XMLRPC_adjustValue(&$data['methodResponse']['fault']['value']));
  366. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  367. XMLRPC_debug('XMLRPC_request', "<p>Returning:</p>\n\n" . XMLRPC_show($return, 'var_dump', true));
  368. }
  369. return $return;
  370. }else{
  371. $return = array(true, XMLRPC_adjustValue(&$data['methodResponse']['params']['param']['value']));
  372. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  373. XMLRPC_debug('XMLRPC_request', "<p>Returning:</p>\n\n" . XMLRPC_show($return, 'var_dump', true));
  374. }
  375. return $return;
  376. }
  377. }
  378. }
  379. function XMLRPC_response($return_value, $server = NULL){
  380. $data["methodResponse"]["params"]["param"]["value"] = &$return_value;
  381. $return = XML_serialize(&$data);
  382. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  383. XMLRPC_debug('XMLRPC_response', "<p>Received the following data to return:</p>\n\n" . XMLRPC_show($return_value, 'print_r', true));
  384. }
  385. header("Connection: close");
  386. header("Content-Length: " . strlen($return));
  387. header("Content-Type: text/xml");
  388. header("Date: " . date("r"));
  389. if($server){
  390. header("Server: $server");
  391. }
  392. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  393. XMLRPC_debug('XMLRPC_response', "<p>Sent the following response:</p>\n\n" . XMLRPC_show($return, 'print_r', true));
  394. }
  395. echo $return;
  396. }
  397. function XMLRPC_error($faultCode, $faultString, $server = NULL){
  398. $array["methodResponse"]["fault"]["value"]["struct"]["member"] = array();
  399. $temp = &$array["methodResponse"]["fault"]["value"]["struct"]["member"];
  400. $temp[0]["name"] = "faultCode";
  401. $temp[0]["value"]["int"] = $faultCode;
  402. $temp[1]["name"] = "faultString";
  403. $temp[1]["value"]["string"] = $faultString;
  404. $return = XML_serialize($array);
  405. header("Connection: close");
  406. header("Content-Length: " . strlen($return));
  407. header("Content-Type: text/xml");
  408. header("Date: " . date("r"));
  409. if($server){
  410. header("Server: $server");
  411. }
  412. if(defined('XMLRPC_DEBUG') and XMLRPC_DEBUG){
  413. XMLRPC_debug('XMLRPC_error', "<p>Sent the following error response:</p>\n\n" . XMLRPC_show($return, 'print_r', true));
  414. }
  415. echo $return;
  416. }
  417. function XMLRPC_convert_timestamp_to_iso8601($timestamp){
  418. #takes a unix timestamp and converts it to iso8601 required by XMLRPC
  419. #an example iso8601 datetime is "20010822T03:14:33"
  420. return date("Ymd\TH:i:s", $timestamp);
  421. }
  422. function XMLRPC_convert_iso8601_to_timestamp($iso8601){
  423. return strtotime($iso8601);
  424. }
  425. function count_numeric_items(&$array){
  426. return is_array($array) ? count(array_filter(array_keys($array), 'is_numeric')) : 0;
  427. }
  428. function XMLRPC_debug($function_name, $debug_message){
  429. $GLOBALS['XMLRPC_DEBUG_INFO'][] = array($function_name, $debug_message);
  430. }
  431. function XMLRPC_debug_print(){
  432. if($GLOBALS['XMLRPC_DEBUG_INFO']){
  433. echo "<table border=\"1\" width=\"100%\">\n";
  434. foreach($GLOBALS['XMLRPC_DEBUG_INFO'] as $debug){
  435. echo "<tr><th style=\"vertical-align: top\">$debug[0]</th><td>$debug[1]</td></tr>\n";
  436. }
  437. echo "</table>\n";
  438. unset($GLOBALS['XMLRPC_DEBUG_INFO']);
  439. }else{
  440. echo "<p>No debugging information available yet.</p>";
  441. }
  442. }
  443. function XMLRPC_show($data, $func = "print_r", $return_str = false){
  444. ob_start();
  445. $func($data);
  446. $output = ob_get_contents();
  447. ob_end_clean();
  448. if($return_str){
  449. return "<pre>" . htmlspecialchars($output) . "</pre>\n";
  450. }else{
  451. echo "<pre>", htmlspecialchars($output), "</pre>\n";
  452. }
  453. }
  454. ?>