Source for file Parser.php
Documentation is available at Parser.php
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more |
// | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author |
// +----------------------------------------------------------------------+
// $Id: Parser.php,v 1.36 2005/05/03 21:12:43 chagenbu Exp $
require_once 'SOAP/Base.php';
require_once 'SOAP/Value.php';
* This class is used by SOAP::Message and SOAP::Server to parse soap
* packets. Originally based on SOAPx4 by Dietrich Ayala
* http://dietrich.ganx4.com/soapx4
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
* @author Dietrich Ayala <dietrich@ganx4.com> Original Author
var $entities = array ( '&' => '&', '<' => '<', '>' => '>', "'" => ''', '"' => '"' );
var $bodyDepth; // used to handle non-root elements before root body element
* SOAP_Parser constructor
* @param string xml content
* @param string xml character encoding, defaults to 'UTF-8'
function SOAP_Parser(&$xml, $encoding = SOAP_DEFAULT_ENCODING , $attachments = null )
$this->attachments = $attachments;
// Check the xml tag for encoding.
if (preg_match('/<\?xml[^>]+encoding\s*?=\s*?(\'([^\']*)\'|"([^"]*)")[^>]*?[\?]>/', $xml, $m)) {
// Determines where in the message we are
// (envelope,header,body,method). Check whether content has
// Prepare the xml parser.
// Some lame soap implementations add null bytes at the
// end of the soap stream, and expat choaks on that.
if ($xml[strlen($xml) - 1 ] == 0 ) {
$err = sprintf('XML error on line %d col %d byte %d %s',
* recurse to build a multi-dim array, used by buildResponse
function domulti ($d, &$ar, &$r, &$v, $ad=0 )
$this->domulti ($d-1 , $ar, $r[$ar[$ad]], $v, $ad+1 );
* loop through msg, building response structures
function &buildResponse ($pos)
if (isset ($this->message[$pos]['children'])) {
foreach ($children as $c => $child_pos) {
if ($this->message[$child_pos]['type'] != null ) {
$response[] = & $this->buildResponse ($child_pos);
for ($i = 0; $i < $ardepth; $i++ ) {
$ar[$i] += $this->message[$pos]['arrayOffset'][$i];
for ($i = 0; $i < $elc; $i++ ) {
// recurse to build a multi-dimensional array
$this->domulti ($ardepth, $ar, $newresp, $response[$i]);
// increment our array pointers
while ($ad > 0 && $ar[$ad] >= $this->message[$pos]['arraySize'][$ad]) {
} elseif (isset ($this->message[$pos]['arrayOffset']) &&
$this->message[$pos]['arrayOffset'][0 ] > 0 ) {
$pad = $this->message[$pos]['arrayOffset'][0 ] + count($response) * -1;
$response = array_pad($response, $pad, null );
foreach ($this->message[$pos]['attrs'] as $atn => $atv) {
// Add current node's value.
$nqn = & new Qname ($this->message[$pos]['name'], $this->message[$pos]['namespace']);
$tqn = & new Qname ($this->message[$pos]['type'], $this->message[$pos]['type_namespace']);
$response = & new SOAP_Value($nqn->fqn (), $tqn->fqn (), $response, $attrs);
if (isset ($this->message[$pos]['arrayType'])) {
$response->arrayType = $this->message[$pos]['arrayType'];
$nqn = & new Qname ($this->message[$pos]['name'], $this->message[$pos]['namespace']);
$tqn = & new Qname ($this->message[$pos]['type'], $this->message[$pos]['type_namespace']);
$response = & new SOAP_Value($nqn->fqn (), $tqn->fqn (), $this->message[$pos]['cdata'], $attrs);
// handle header attribute that we need
$response->actor = $this->message[$pos]['actor'];
$response->mustunderstand = $this->message[$pos]['mustUnderstand'];
* start-element handler used with xml parser
function startElement ($parser, $name, $attrs)
// position in a total number of elements, starting from 0
// update class level pos
$this->message[$pos]['type_namespace'] = '';
$this->message[$pos]['cdata'] = '';
$this->message[$pos]['pos'] = $pos;
// parent/child/depth determinations
// depth = how many levels removed from root?
// set mine as current global depth and increment global depth value
// else add self as child to whoever the current parent is
// set self as current value for this depth
// set self as current parent
$qname = & new QName($name);
} elseif (strcasecmp('header', $qname->name ) == 0 ) {
$this->message[$pos]['type'] = 'Struct';
} elseif (strcasecmp('body', $qname->name ) == 0 ) {
} elseif ($this->status == 'body') {
// Is this element allowed to be a root?
// XXX this needs to be optimized, we loop through attrs twice now.
foreach ($attrs as $key => $value) {
if (stristr($key, ':root') && !$value) {
$this->message[$pos]['type'] = 'Struct';
$this->message[$pos]['attrs'] = $attrs;
// Loop through attributes, logging ns and type declarations.
foreach ($attrs as $key => $value) {
// If ns declarations, add to class level array of valid
if ($kqn->ns == 'xmlns') {
if (in_array($value, $this->_XMLSchema)) {
$this->_setSchemaVersion ($value);
$this->_namespaces[$value] = $prefix;
} elseif ($key == 'xmlns') {
$qname->ns = $this->_getNamespacePrefix ($value);
$qname->namespace = $value;
} elseif ($kqn->name == 'actor') {
$this->message[$pos]['actor'] = $value;
} elseif ($kqn->name == 'mustUnderstand') {
$this->message[$pos]['mustUnderstand'] = $value;
// If it's a type declaration, set type.
} elseif ($kqn->name == 'type') {
$vqn = & new QName($value);
$this->message[$pos]['type'] = $vqn->name;
$this->message[$pos]['type_namespace'] = $this->_getNamespaceForPrefix ($vqn->ns );
// Should do something here with the namespace of
} elseif ($kqn->name == 'arrayType') {
$vqn = & new QName($value);
$this->message[$pos]['type'] = 'Array';
if (isset ($vqn->arraySize )) {
$this->message[$pos]['arraySize'] = $vqn->arraySize;
$this->message[$pos]['arrayType'] = $vqn->name;
} elseif ($kqn->name == 'offset') {
} elseif ($kqn->name == 'id') {
// Save id to reference array.
$this->message[$pos]['id'] = $value;
} elseif ($kqn->name == 'href') {
$this->message[$pos]['children'] = &$this->message[$ref_pos]['children'];
$this->message[$pos]['arraySize'] = &$this->message[$ref_pos]['arraySize'];
$this->message[$pos]['arrayType'] = &$this->message[$ref_pos]['arrayType'];
// Reverse reference, store in 'need reference'.
} elseif (isset ($this->attachments[$value])) {
$this->message[$pos]['cdata'] = $this->attachments[$value];
// See if namespace is defined in tag.
$namespace = $attrs['xmlns:' . $qname->ns ];
} elseif ($qname->ns && !$qname->namespace ) {
$namespace = $this->_getNamespaceForPrefix ($qname->ns );
$this->message[$pos]['namespace'] = $namespace;
* end-element handler used with xml parser
function endElement ($parser, $name)
// Position of current element is equal to the last value left
// in depth_array for my depth.
// Bring depth down a notch.
$qname = & new QName($name);
// Get type if not explicitly declared in an xsi:type attribute.
// XXX check on integrating wsdl validation here
if ($this->message[$pos]['type'] == '') {
if (isset ($this->message[$pos]['children'])) {
/* this is slow, need to look at some faster method
$children = explode('|', $this->message[$pos]['children']);
if (count($children) > 2 &&
$this->message[$children[1]]['name'] == $this->message[$children[2]]['name']) {
$this->message[$pos]['type'] = 'Array';
$this->message[$pos]['type'] = 'Struct';
$this->message[$pos]['type'] = 'Struct';
$parent = $this->message[$pos]['parent'];
if ($this->message[$parent]['type'] == 'Array' &&
$this->message[$pos]['type'] = 'string';
// If tag we are currently closing is the method wrapper.
} elseif ($qname->name == 'Body' || $qname->name == 'Header') {
// Set parent back to my parent.
// Handle any reverse references now.
$idref = $this->message[$pos]['id'];
// XXX is this stuff there already?
$this->message[$ref_pos]['children'] = &$this->message[$pos]['children'];
$this->message[$ref_pos]['arraySize'] = &$this->message[$pos]['arraySize'];
$this->message[$ref_pos]['arrayType'] = &$this->message[$pos]['arrayType'];
* element content handler used with xml parser
function characterData ($parser, $data)
if (isset ($this->message[$pos]['cdata'])) {
$this->message[$pos]['cdata'] .= $data;
$this->message[$pos]['cdata'] = $data;
* returns an array of responses
* after parsing a soap message, use this to get the response
return $this->_raiseSoapFault ("couldn't build response");
* returns an array of header responses
* after parsing a soap message, use this to get the response
// We don't fault if there are no headers that can be handled
// by the app if necessary.
* removes entities from text
function decodeEntities ($text)
return strtr($text, $trans_tbl);
Documentation generated on Mon, 11 Mar 2019 14:20:04 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|