[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[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_element_handler($this->_parser, array($this, 'tag_open'), array($this, 'tag_close')); 97 xml_set_character_data_handler($this->_parser, array($this, 'cdata')); 98 99 // 256Kb, parse in chunks to avoid the RAM usage on very large messages 100 $chunk_size = 262144; 101 102 /** 103 * Filters the chunk size that can be used to parse an XML-RPC response message. 104 * 105 * @since 4.4.0 106 * 107 * @param int $chunk_size Chunk size to parse in bytes. 108 */ 109 $chunk_size = apply_filters( 'xmlrpc_chunk_parsing_size', $chunk_size ); 110 111 $final = false; 112 113 do { 114 if (strlen($this->message) <= $chunk_size) { 115 $final = true; 116 } 117 118 $part = substr($this->message, 0, $chunk_size); 119 $this->message = substr($this->message, $chunk_size); 120 121 if (!xml_parse($this->_parser, $part, $final)) { 122 if (PHP_VERSION_ID < 80000) { // xml_parser_free() has no effect as of PHP 8.0. 123 xml_parser_free($this->_parser); 124 } 125 126 unset($this->_parser); 127 return false; 128 } 129 130 if ($final) { 131 break; 132 } 133 } while (true); 134 135 if (PHP_VERSION_ID < 80000) { // xml_parser_free() has no effect as of PHP 8.0. 136 xml_parser_free($this->_parser); 137 } 138 139 unset($this->_parser); 140 141 // Grab the error messages, if any 142 if ($this->messageType == 'fault') { 143 $this->faultCode = $this->params[0]['faultCode']; 144 $this->faultString = $this->params[0]['faultString']; 145 } 146 return true; 147 } 148 149 function tag_open($parser, $tag, $attr) 150 { 151 $this->_currentTagContents = ''; 152 $this->_currentTag = $tag; 153 switch($tag) { 154 case 'methodCall': 155 case 'methodResponse': 156 case 'fault': 157 $this->messageType = $tag; 158 break; 159 /* Deal with stacks of arrays and structs */ 160 case 'data': // data is to all intents and puposes more interesting than array 161 $this->_arraystructstypes[] = 'array'; 162 $this->_arraystructs[] = array(); 163 break; 164 case 'struct': 165 $this->_arraystructstypes[] = 'struct'; 166 $this->_arraystructs[] = array(); 167 break; 168 } 169 } 170 171 function cdata($parser, $cdata) 172 { 173 $this->_currentTagContents .= $cdata; 174 } 175 176 function tag_close($parser, $tag) 177 { 178 $valueFlag = false; 179 switch($tag) { 180 case 'int': 181 case 'i4': 182 $value = (int)trim($this->_currentTagContents); 183 $valueFlag = true; 184 break; 185 case 'double': 186 $value = (float)trim($this->_currentTagContents); 187 $valueFlag = true; 188 break; 189 case 'string': 190 $value = (string)trim($this->_currentTagContents); 191 $valueFlag = true; 192 break; 193 case 'dateTime.iso8601': 194 $value = new IXR_Date(trim($this->_currentTagContents)); 195 $valueFlag = true; 196 break; 197 case 'value': 198 // "If no type is indicated, the type is string." 199 if (trim($this->_currentTagContents) != '') { 200 $value = (string)$this->_currentTagContents; 201 $valueFlag = true; 202 } 203 break; 204 case 'boolean': 205 $value = (bool)trim($this->_currentTagContents); 206 $valueFlag = true; 207 break; 208 case 'base64': 209 $value = base64_decode($this->_currentTagContents); 210 $valueFlag = true; 211 break; 212 /* Deal with stacks of arrays and structs */ 213 case 'data': 214 case 'struct': 215 $value = array_pop($this->_arraystructs); 216 array_pop($this->_arraystructstypes); 217 $valueFlag = true; 218 break; 219 case 'member': 220 array_pop($this->_currentStructName); 221 break; 222 case 'name': 223 $this->_currentStructName[] = trim($this->_currentTagContents); 224 break; 225 case 'methodName': 226 $this->methodName = trim($this->_currentTagContents); 227 break; 228 } 229 230 if ($valueFlag) { 231 if (count($this->_arraystructs) > 0) { 232 // Add value to struct or array 233 if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') { 234 // Add to struct 235 $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value; 236 } else { 237 // Add to array 238 $this->_arraystructs[count($this->_arraystructs)-1][] = $value; 239 } 240 } else { 241 // Just add as a parameter 242 $this->params[] = $value; 243 } 244 } 245 $this->_currentTagContents = ''; 246 } 247 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue Sep 9 08:20:04 2025 | Cross-referenced by PHPXref |