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