PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/wp-includes/IXR/class-IXR-message.php

https://gitlab.com/VTTE/sitios-vtte
PHP | 234 lines | 171 code | 18 blank | 45 comment | 24 complexity | ff847c4c6e95a9147d44fbd7e8313497 MD5 | raw file
  1. <?php
  2. /**
  3. * IXR_MESSAGE
  4. *
  5. * @package IXR
  6. * @since 1.5.0
  7. *
  8. */
  9. class IXR_Message
  10. {
  11. var $message = false;
  12. var $messageType = false; // methodCall / methodResponse / fault
  13. var $faultCode = false;
  14. var $faultString = false;
  15. var $methodName = '';
  16. var $params = array();
  17. // Current variable stacks
  18. var $_arraystructs = array(); // The stack used to keep track of the current array/struct
  19. var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
  20. var $_currentStructName = array(); // A stack as well
  21. var $_param;
  22. var $_value;
  23. var $_currentTag;
  24. var $_currentTagContents;
  25. // The XML parser
  26. var $_parser;
  27. /**
  28. * PHP5 constructor.
  29. */
  30. function __construct( $message )
  31. {
  32. $this->message =& $message;
  33. }
  34. /**
  35. * PHP4 constructor.
  36. */
  37. public function IXR_Message( $message ) {
  38. self::__construct( $message );
  39. }
  40. function parse()
  41. {
  42. if ( ! function_exists( 'xml_parser_create' ) ) {
  43. trigger_error( __( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ) );
  44. return false;
  45. }
  46. // first remove the XML declaration
  47. // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
  48. $header = preg_replace( '/<\?xml.*?\?'.'>/s', '', substr( $this->message, 0, 100 ), 1 );
  49. $this->message = trim( substr_replace( $this->message, $header, 0, 100 ) );
  50. if ( '' == $this->message ) {
  51. return false;
  52. }
  53. // Then remove the DOCTYPE
  54. $header = preg_replace( '/^<!DOCTYPE[^>]*+>/i', '', substr( $this->message, 0, 200 ), 1 );
  55. $this->message = trim( substr_replace( $this->message, $header, 0, 200 ) );
  56. if ( '' == $this->message ) {
  57. return false;
  58. }
  59. // Check that the root tag is valid
  60. $root_tag = substr( $this->message, 0, strcspn( substr( $this->message, 0, 20 ), "> \t\r\n" ) );
  61. if ( '<!DOCTYPE' === strtoupper( $root_tag ) ) {
  62. return false;
  63. }
  64. if ( ! in_array( $root_tag, array( '<methodCall', '<methodResponse', '<fault' ) ) ) {
  65. return false;
  66. }
  67. // Bail if there are too many elements to parse
  68. $element_limit = 30000;
  69. if ( function_exists( 'apply_filters' ) ) {
  70. /**
  71. * Filters the number of elements to parse in an XML-RPC response.
  72. *
  73. * @since 4.0.0
  74. *
  75. * @param int $element_limit Default elements limit.
  76. */
  77. $element_limit = apply_filters( 'xmlrpc_element_limit', $element_limit );
  78. }
  79. if ( $element_limit && 2 * $element_limit < substr_count( $this->message, '<' ) ) {
  80. return false;
  81. }
  82. $this->_parser = xml_parser_create();
  83. // Set XML parser to take the case of tags in to account
  84. xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
  85. // Set XML parser callback functions
  86. xml_set_object($this->_parser, $this);
  87. xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
  88. xml_set_character_data_handler($this->_parser, 'cdata');
  89. // 256Kb, parse in chunks to avoid the RAM usage on very large messages
  90. $chunk_size = 262144;
  91. /**
  92. * Filters the chunk size that can be used to parse an XML-RPC response message.
  93. *
  94. * @since 4.4.0
  95. *
  96. * @param int $chunk_size Chunk size to parse in bytes.
  97. */
  98. $chunk_size = apply_filters( 'xmlrpc_chunk_parsing_size', $chunk_size );
  99. $final = false;
  100. do {
  101. if (strlen($this->message) <= $chunk_size) {
  102. $final = true;
  103. }
  104. $part = substr($this->message, 0, $chunk_size);
  105. $this->message = substr($this->message, $chunk_size);
  106. if (!xml_parse($this->_parser, $part, $final)) {
  107. return false;
  108. }
  109. if ($final) {
  110. break;
  111. }
  112. } while (true);
  113. xml_parser_free($this->_parser);
  114. // Grab the error messages, if any
  115. if ($this->messageType == 'fault') {
  116. $this->faultCode = $this->params[0]['faultCode'];
  117. $this->faultString = $this->params[0]['faultString'];
  118. }
  119. return true;
  120. }
  121. function tag_open($parser, $tag, $attr)
  122. {
  123. $this->_currentTagContents = '';
  124. $this->currentTag = $tag;
  125. switch($tag) {
  126. case 'methodCall':
  127. case 'methodResponse':
  128. case 'fault':
  129. $this->messageType = $tag;
  130. break;
  131. /* Deal with stacks of arrays and structs */
  132. case 'data': // data is to all intents and puposes more interesting than array
  133. $this->_arraystructstypes[] = 'array';
  134. $this->_arraystructs[] = array();
  135. break;
  136. case 'struct':
  137. $this->_arraystructstypes[] = 'struct';
  138. $this->_arraystructs[] = array();
  139. break;
  140. }
  141. }
  142. function cdata($parser, $cdata)
  143. {
  144. $this->_currentTagContents .= $cdata;
  145. }
  146. function tag_close($parser, $tag)
  147. {
  148. $valueFlag = false;
  149. switch($tag) {
  150. case 'int':
  151. case 'i4':
  152. $value = (int)trim($this->_currentTagContents);
  153. $valueFlag = true;
  154. break;
  155. case 'double':
  156. $value = (double)trim($this->_currentTagContents);
  157. $valueFlag = true;
  158. break;
  159. case 'string':
  160. $value = (string)trim($this->_currentTagContents);
  161. $valueFlag = true;
  162. break;
  163. case 'dateTime.iso8601':
  164. $value = new IXR_Date(trim($this->_currentTagContents));
  165. $valueFlag = true;
  166. break;
  167. case 'value':
  168. // "If no type is indicated, the type is string."
  169. if (trim($this->_currentTagContents) != '') {
  170. $value = (string)$this->_currentTagContents;
  171. $valueFlag = true;
  172. }
  173. break;
  174. case 'boolean':
  175. $value = (boolean)trim($this->_currentTagContents);
  176. $valueFlag = true;
  177. break;
  178. case 'base64':
  179. $value = base64_decode($this->_currentTagContents);
  180. $valueFlag = true;
  181. break;
  182. /* Deal with stacks of arrays and structs */
  183. case 'data':
  184. case 'struct':
  185. $value = array_pop($this->_arraystructs);
  186. array_pop($this->_arraystructstypes);
  187. $valueFlag = true;
  188. break;
  189. case 'member':
  190. array_pop($this->_currentStructName);
  191. break;
  192. case 'name':
  193. $this->_currentStructName[] = trim($this->_currentTagContents);
  194. break;
  195. case 'methodName':
  196. $this->methodName = trim($this->_currentTagContents);
  197. break;
  198. }
  199. if ($valueFlag) {
  200. if (count($this->_arraystructs) > 0) {
  201. // Add value to struct or array
  202. if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
  203. // Add to struct
  204. $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
  205. } else {
  206. // Add to array
  207. $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
  208. }
  209. } else {
  210. // Just add as a parameter
  211. $this->params[] = $value;
  212. }
  213. }
  214. $this->_currentTagContents = '';
  215. }
  216. }