IXR_Message::parse()

In this article

Source

function parse()
{
    if ( ! function_exists( 'xml_parser_create' ) ) {
        trigger_error( __( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ) );
        return false;
    }

    // first remove the XML declaration
    // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
    $header = preg_replace( '/<\?xml.*?\?'.'>/s', '', substr( $this->message, 0, 100 ), 1 );
    $this->message = trim( substr_replace( $this->message, $header, 0, 100 ) );
    if ( '' == $this->message ) {
        return false;
    }

    // Then remove the DOCTYPE
    $header = preg_replace( '/^<!DOCTYPE[^>]*+>/i', '', substr( $this->message, 0, 200 ), 1 );
    $this->message = trim( substr_replace( $this->message, $header, 0, 200 ) );
    if ( '' == $this->message ) {
        return false;
    }

    // Check that the root tag is valid
    $root_tag = substr( $this->message, 0, strcspn( substr( $this->message, 0, 20 ), "> \t\r\n" ) );
    if ( '<!DOCTYPE' === strtoupper( $root_tag ) ) {
        return false;
    }
    if ( ! in_array( $root_tag, array( '<methodCall', '<methodResponse', '<fault' ) ) ) {
        return false;
    }

    // Bail if there are too many elements to parse
    $element_limit = 30000;
    if ( function_exists( 'apply_filters' ) ) {
        /**
         * Filters the number of elements to parse in an XML-RPC response.
         *
         * @since 4.0.0
         *
         * @param int $element_limit Default elements limit.
         */
        $element_limit = apply_filters( 'xmlrpc_element_limit', $element_limit );
    }
    if ( $element_limit && 2 * $element_limit < substr_count( $this->message, '<' ) ) {
        return false;
    }

    $this->_parser = xml_parser_create();
    // Set XML parser to take the case of tags in to account
    xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
    // Set XML parser callback functions
    xml_set_object($this->_parser, $this);
    xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
    xml_set_character_data_handler($this->_parser, 'cdata');

    // 256Kb, parse in chunks to avoid the RAM usage on very large messages
    $chunk_size = 262144;

    /**
     * Filters the chunk size that can be used to parse an XML-RPC response message.
     *
     * @since 4.4.0
     *
     * @param int $chunk_size Chunk size to parse in bytes.
     */
    $chunk_size = apply_filters( 'xmlrpc_chunk_parsing_size', $chunk_size );

    $final = false;

    do {
        if (strlen($this->message) <= $chunk_size) {
            $final = true;
        }

        $part = substr($this->message, 0, $chunk_size);
        $this->message = substr($this->message, $chunk_size);

        if (!xml_parse($this->_parser, $part, $final)) {
            xml_parser_free($this->_parser);
            unset($this->_parser);
            return false;
        }

        if ($final) {
            break;
        }
    } while (true);

    xml_parser_free($this->_parser);
    unset($this->_parser);

    // Grab the error messages, if any
    if ($this->messageType == 'fault') {
        $this->faultCode = $this->params[0]['faultCode'];
        $this->faultString = $this->params[0]['faultString'];
    }
    return true;
}

Hooks

apply_filters( ‘xmlrpc_chunk_parsing_size’, int $chunk_size )

Filters the chunk size that can be used to parse an XML-RPC response message.

apply_filters( ‘xmlrpc_element_limit’, int $element_limit )

Filters the number of elements to parse in an XML-RPC response.

User Contributed Notes

You must log in before being able to contribute a note or feedback.