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


Generated: Sun Nov 17 01:00:03 2019 Cross-referenced by PHPXref 0.7.1