PageRenderTime 63ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/phpgwapi/inc/class.soap_parser.inc.php

https://github.com/muchael/expressolivre
PHP | 383 lines | 295 code | 22 blank | 66 comment | 43 complexity | 7a2db3ca8415358daaec5f2b61376671 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-2-Clause, BSD-3-Clause, AGPL-3.0
  1. <?php
  2. /***************************************************************************
  3. * Expresso Livre *
  4. * http://www.expressolivre.org *
  5. * -------------------------------------------- *
  6. * This program is free software; you can redistribute it and/or modify it *
  7. * under the terms of the GNU General Public License as published by the *
  8. * Free Software Foundation; either version 2 of the License, or (at your *
  9. * option) any later version. *
  10. \**************************************************************************/
  11. class soap_parser
  12. {
  13. function soap_parser($xml='',$encoding='UTF-8')
  14. {
  15. global $soapTypes;
  16. $this->soapTypes = $soapTypes;
  17. $this->xml = $xml;
  18. $this->xml_encoding = $encoding;
  19. $this->root_struct = "";
  20. // options: envelope,header,body,method
  21. // determines where in the message we are (envelope,header,body,method)
  22. $this->status = '';
  23. $this->position = 0;
  24. $this->pos_stat = 0;
  25. $this->depth = 0;
  26. $this->default_namespace = '';
  27. $this->namespaces = array();
  28. $this->message = array();
  29. $this->fault = false;
  30. $this->fault_code = '';
  31. $this->fault_str = '';
  32. $this->fault_detail = '';
  33. $this->eval_str = '';
  34. $this->depth_array = array();
  35. $this->debug_flag = True;
  36. $this->debug_str = '';
  37. $this->previous_element = '';
  38. $this->entities = array (
  39. '&' => '&amp;',
  40. '<' => '&lt;',
  41. '>' => '&gt;',
  42. "'" => '&apos;',
  43. '"' => '&quot;'
  44. );
  45. // Check whether content has been read.
  46. if(!empty($xml))
  47. {
  48. $this->debug('Entering soap_parser()');
  49. //$this->debug("DATA DUMP:\n\n$xml");
  50. // Create an XML parser.
  51. $this->parser = xml_parser_create($this->xml_encoding);
  52. // Set the options for parsing the XML data.
  53. //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  54. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
  55. // Set the object for the parser.
  56. xml_set_object($this->parser, &$this);
  57. // Set the element handlers for the parser.
  58. xml_set_element_handler($this->parser, 'start_element','end_element');
  59. xml_set_character_data_handler($this->parser,'character_data');
  60. xml_set_default_handler($this->parser, 'default_handler');
  61. // Parse the XML file.
  62. if(!xml_parse($this->parser,$xml,true))
  63. {
  64. // Display an error message.
  65. $this->debug(sprintf("XML error on line %d: %s",
  66. xml_get_current_line_number($this->parser),
  67. xml_error_string(xml_get_error_code($this->parser))));
  68. $this->fault = true;
  69. }
  70. else
  71. {
  72. // get final eval string
  73. $this->eval_str = "\$response = ".trim($this->build_eval($this->root_struct)).";";
  74. }
  75. xml_parser_free($this->parser);
  76. }
  77. else
  78. {
  79. $this->debug("xml was empty, didn't parse!");
  80. }
  81. }
  82. // loop through msg, building eval_str
  83. function build_eval($pos)
  84. {
  85. $this->debug("inside build_eval() for $pos: ".$this->message[$pos]["name"]);
  86. $eval_str = $this->message[$pos]['eval_str'];
  87. // loop through children, building...
  88. if($this->message[$pos]['children'] != '')
  89. {
  90. $this->debug('children string = '.$this->message[$pos]['children']);
  91. $children = explode('|',$this->message[$pos]['children']);
  92. $this->debug('it has '.count($children).' children');
  93. @reset($children);
  94. while(list($c,$child_pos) = @each($children))
  95. /* foreach($children as $c => $child_pos) */
  96. {
  97. //$this->debug("child pos $child_pos: ".$this->message[$child_pos]["name"]);
  98. if($this->message[$child_pos]['eval_str'] != '')
  99. {
  100. $this->debug('entering build_eval() for '.$this->message[$child_pos]['name'].", array pos $c, pos: $child_pos");
  101. $eval_str .= $this->build_eval($child_pos).', ';
  102. }
  103. }
  104. $eval_str = substr($eval_str,0,strlen($eval_str)-2);
  105. }
  106. // add current node's eval_str
  107. $eval_str .= $this->message[$pos]['end_eval_str'];
  108. return $eval_str;
  109. }
  110. // start-element handler
  111. function start_element($parser, $name, $attrs)
  112. {
  113. // position in a total number of elements, starting from 0
  114. // update class level pos
  115. $pos = $this->position++;
  116. // and set mine
  117. $this->message[$pos]['pos'] = $pos;
  118. // parent/child/depth determinations
  119. // depth = how many levels removed from root?
  120. // set mine as current global depth and increment global depth value
  121. $this->message[$pos]['depth'] = $this->depth++;
  122. // else add self as child to whoever the current parent is
  123. if($pos != 0)
  124. {
  125. $this->message[$this->parent]['children'] .= "|$pos";
  126. }
  127. // set my parent
  128. $this->message[$pos]['parent'] = $this->parent;
  129. // set self as current value for this depth
  130. $this->depth_array[$this->depth] = $pos;
  131. // set self as current parent
  132. $this->parent = $pos;
  133. // set status
  134. if(preg_match('/:Envelope$/',$name))
  135. {
  136. $this->status = 'envelope';
  137. }
  138. elseif(preg_match('/:Header$/',$name))
  139. {
  140. $this->status = 'header';
  141. }
  142. elseif(preg_match('/:Body$/',$name))
  143. {
  144. $this->status = 'body';
  145. // set method
  146. }
  147. elseif($this->status == 'body')
  148. {
  149. $this->status = 'method';
  150. if(preg_match('/:/',$name))
  151. {
  152. $this->root_struct_name = substr(strrchr($name,':'),1);
  153. }
  154. else
  155. {
  156. $this->root_struct_name = $name;
  157. }
  158. $this->root_struct = $pos;
  159. $this->message[$pos]['type'] = 'struct';
  160. }
  161. // set my status
  162. $this->message[$pos]['status'] = $this->status;
  163. // set name
  164. $this->message[$pos]['name'] = htmlspecialchars($name);
  165. // set attrs
  166. $this->message[$pos]['attrs'] = $attrs;
  167. // get namespace
  168. if(preg_match('/:/',$name))
  169. {
  170. $namespace = substr($name,0,strpos($name,':'));
  171. $this->message[$pos]['namespace'] = $namespace;
  172. $this->default_namespace = $namespace;
  173. }
  174. else
  175. {
  176. $this->message[$pos]['namespace'] = $this->default_namespace;
  177. }
  178. // loop through atts, logging ns and type declarations
  179. @reset($attrs);
  180. while (list($key,$value) = @each($attrs))
  181. /* foreach($attrs as $key => $value) */
  182. {
  183. // if ns declarations, add to class level array of valid namespaces
  184. if(preg_match('/xmlns:/',$key))
  185. {
  186. $namespaces[substr(strrchr($key,':'),1)] = $value;
  187. if($name == $this->root_struct_name)
  188. {
  189. $this->methodNamespace = $value;
  190. }
  191. }
  192. // if it's a type declaration, set type
  193. elseif($key == 'xsi:type')
  194. {
  195. // then get attname and set $type
  196. $type = substr(strrchr($value,':'),1);
  197. }
  198. }
  199. // set type if available
  200. if($type)
  201. {
  202. $this->message[$pos]['type'] = $type;
  203. }
  204. // debug
  205. //$this->debug("parsed $name start, eval = '".$this->message[$pos]["eval_str"]."'");
  206. }
  207. // end-element handler
  208. function end_element($parser, $name)
  209. {
  210. // position of current element is equal to the last value left in depth_array for my depth
  211. $pos = $this->depth_array[$this->depth];
  212. // bring depth down a notch
  213. $this->depth--;
  214. // get type if not set already
  215. if($this->message[$pos]['type'] == '')
  216. {
  217. // if($this->message[$pos]['cdata'] == '' && $this->message[$pos]['children'] != '')
  218. if($this->message[$pos]['children'] != '')
  219. {
  220. $this->message[$pos]['type'] = 'SOAPStruct';
  221. }
  222. else
  223. {
  224. $this->message[$pos]['type'] = 'string';
  225. }
  226. }
  227. // set eval str start if it has a valid type and is inside the method
  228. if($pos >= $this->root_struct)
  229. {
  230. $this->message[$pos]['eval_str'] .= "\n CreateObject(\"phpgwapi.soapval\",\"".htmlspecialchars($name)."\", \"".$this->message[$pos]["type"]."\" ";
  231. $this->message[$pos]['end_eval_str'] = ')';
  232. $this->message[$pos]['inval'] = 'true';
  233. /*
  234. if($this->message[$pos]["name"] == $this->root_struct_name){
  235. $this->message[$pos]["end_eval_str"] .= " ,\"$this->methodNamespace\"";
  236. }
  237. */
  238. if($this->message[$pos]['children'] != '')
  239. {
  240. $this->message[$pos]['eval_str'] .= ', array( ';
  241. $this->message[$pos]['end_eval_str'] .= ' )';
  242. }
  243. }
  244. // if i have no children and have cdata...then i must be a scalar value, so add my data to the eval_str
  245. if($this->status == 'method' && $this->message[$pos]['children'] == '')
  246. {
  247. // add cdata w/ no quotes if only int/float/dbl
  248. if($this->message[$pos]['type'] == 'string')
  249. {
  250. $this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
  251. }
  252. elseif($this->message[$pos]['type'] == 'int' || $this->message[$pos]['type'] == 'float' || $this->message[$pos]['type'] == 'double')
  253. {
  254. //$this->debug("adding cdata w/o quotes");
  255. $this->message[$pos]['eval_str'] .= ', '.trim($this->message[$pos]['cdata']);
  256. }
  257. elseif(is_string($this->message[$pos]['cdata']))
  258. {
  259. //$this->debug("adding cdata w/ quotes");
  260. $this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
  261. }
  262. }
  263. // if in the process of making a soap_val, close the parentheses and move on...
  264. if($this->message[$pos]['inval'] == 'true')
  265. {
  266. $this->message[$pos]['inval'] == 'false';
  267. }
  268. // if tag we are currently closing is the method wrapper
  269. if($pos == $this->root_struct)
  270. {
  271. $this->status = 'body';
  272. }
  273. elseif(preg_match('/:Body/',$name))
  274. {
  275. $this->status = 'header';
  276. }
  277. elseif(preg_match('/:Header/',$name))
  278. {
  279. $this->status = 'envelope';
  280. }
  281. // set parent back to my parent
  282. $this->parent = $this->message[$pos]['parent'];
  283. $this->debug("parsed $name end, type '".$this->message[$pos]['type']."'eval_str = '".trim($this->message[$pos]['eval_str'])."' and children = ".$this->message[$pos]['children']);
  284. }
  285. // element content handler
  286. function character_data($parser, $data)
  287. {
  288. $pos = $this->depth_array[$this->depth];
  289. $this->message[$pos]['cdata'] .= $data;
  290. //$this->debug("parsed ".$this->message[$pos]["name"]." cdata, eval = '$this->eval_str'");
  291. }
  292. // default handler
  293. function default_handler($parser, $data)
  294. {
  295. //$this->debug("DEFAULT HANDLER: $data");
  296. }
  297. // function to get fault code
  298. function fault()
  299. {
  300. if($this->fault)
  301. {
  302. return true;
  303. }
  304. else
  305. {
  306. return false;
  307. }
  308. }
  309. // have this return a soap_val object
  310. function get_response()
  311. {
  312. $this->debug("eval()ing eval_str: $this->eval_str");
  313. @eval("$this->eval_str");
  314. if($response)
  315. {
  316. $this->debug("successfully eval'd msg");
  317. return $response;
  318. }
  319. else
  320. {
  321. $this->debug('ERROR: did not successfully eval the msg');
  322. $this->fault = true;
  323. return CreateObject('phpgwapi.soapval',
  324. 'Fault',
  325. 'struct',
  326. array(
  327. CreateObject('phpgwapi.soapval',
  328. 'faultcode',
  329. 'string',
  330. 'SOAP-ENV:Server'
  331. ),
  332. CreateObject('phpgwapi.soapval',
  333. 'faultstring',
  334. 'string',
  335. "couldn't eval \"$this->eval_str\""
  336. )
  337. )
  338. );
  339. }
  340. }
  341. function debug($string)
  342. {
  343. if($this->debug_flag)
  344. {
  345. $this->debug_str .= "$string\n";
  346. }
  347. }
  348. function decode_entities($text)
  349. {
  350. @reset($this->entities);
  351. while(list($entity,$encoded) = @each($this->entities))
  352. /* foreach($this->entities as $entity => $encoded) */
  353. {
  354. $text = str_replace($encoded,$entity,$text);
  355. }
  356. return $text;
  357. }
  358. }
  359. ?>