[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/IXR/ -> class-IXR-message.php (source)

   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                  xml_parser_free($this->_parser);
 123                  unset($this->_parser);
 124                  return false;
 125              }
 126  
 127              if ($final) {
 128                  break;
 129              }
 130          } while (true);
 131  
 132          xml_parser_free($this->_parser);
 133          unset($this->_parser);
 134  
 135          // Grab the error messages, if any
 136          if ($this->messageType == 'fault') {
 137              $this->faultCode = $this->params[0]['faultCode'];
 138              $this->faultString = $this->params[0]['faultString'];
 139          }
 140          return true;
 141      }
 142  
 143      function tag_open($parser, $tag, $attr)
 144      {
 145          $this->_currentTagContents = '';
 146          $this->_currentTag = $tag;
 147          switch($tag) {
 148              case 'methodCall':
 149              case 'methodResponse':
 150              case 'fault':
 151                  $this->messageType = $tag;
 152                  break;
 153                  /* Deal with stacks of arrays and structs */
 154              case 'data':    // data is to all intents and puposes more interesting than array
 155                  $this->_arraystructstypes[] = 'array';
 156                  $this->_arraystructs[] = array();
 157                  break;
 158              case 'struct':
 159                  $this->_arraystructstypes[] = 'struct';
 160                  $this->_arraystructs[] = array();
 161                  break;
 162          }
 163      }
 164  
 165      function cdata($parser, $cdata)
 166      {
 167          $this->_currentTagContents .= $cdata;
 168      }
 169  
 170      function tag_close($parser, $tag)
 171      {
 172          $valueFlag = false;
 173          switch($tag) {
 174              case 'int':
 175              case 'i4':
 176                  $value = (int)trim($this->_currentTagContents);
 177                  $valueFlag = true;
 178                  break;
 179              case 'double':
 180                  $value = (double)trim($this->_currentTagContents);
 181                  $valueFlag = true;
 182                  break;
 183              case 'string':
 184                  $value = (string)trim($this->_currentTagContents);
 185                  $valueFlag = true;
 186                  break;
 187              case 'dateTime.iso8601':
 188                  $value = new IXR_Date(trim($this->_currentTagContents));
 189                  $valueFlag = true;
 190                  break;
 191              case 'value':
 192                  // "If no type is indicated, the type is string."
 193                  if (trim($this->_currentTagContents) != '') {
 194                      $value = (string)$this->_currentTagContents;
 195                      $valueFlag = true;
 196                  }
 197                  break;
 198              case 'boolean':
 199                  $value = (boolean)trim($this->_currentTagContents);
 200                  $valueFlag = true;
 201                  break;
 202              case 'base64':
 203                  $value = base64_decode($this->_currentTagContents);
 204                  $valueFlag = true;
 205                  break;
 206                  /* Deal with stacks of arrays and structs */
 207              case 'data':
 208              case 'struct':
 209                  $value = array_pop($this->_arraystructs);
 210                  array_pop($this->_arraystructstypes);
 211                  $valueFlag = true;
 212                  break;
 213              case 'member':
 214                  array_pop($this->_currentStructName);
 215                  break;
 216              case 'name':
 217                  $this->_currentStructName[] = trim($this->_currentTagContents);
 218                  break;
 219              case 'methodName':
 220                  $this->methodName = trim($this->_currentTagContents);
 221                  break;
 222          }
 223  
 224          if ($valueFlag) {
 225              if (count($this->_arraystructs) > 0) {
 226                  // Add value to struct or array
 227                  if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
 228                      // Add to struct
 229                      $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
 230                  } else {
 231                      // Add to array
 232                      $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
 233                  }
 234              } else {
 235                  // Just add as a parameter
 236                  $this->params[] = $value;
 237              }
 238          }
 239          $this->_currentTagContents = '';
 240      }
 241  }


Generated : Thu Nov 21 08:20:01 2024 Cross-referenced by PHPXref