[ Index ]

PHP Cross Reference of WordPress

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_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  }


Generated: Tue Aug 4 01:00:03 2020 Cross-referenced by PHPXref 0.7.1