mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-25 09:23:28 +01:00
232252475f
Patch is mostly created by script in egroupware/doc/fix_depricated.php in separate commit. I do NOT advice to apply this patch to a production system (it's commited to trunk!), as the automatic modified regular expressions have a good change to break something ...
376 lines
10 KiB
PHP
376 lines
10 KiB
PHP
<?php
|
|
/* $Id$ */
|
|
|
|
class soap_parser
|
|
{
|
|
function soap_parser($xml='',$encoding='UTF-8')
|
|
{
|
|
global $soapTypes;
|
|
|
|
$this->soapTypes = $soapTypes;
|
|
$this->xml = $xml;
|
|
$this->xml_encoding = $encoding;
|
|
$this->root_struct = "";
|
|
// options: envelope,header,body,method
|
|
// determines where in the message we are (envelope,header,body,method)
|
|
$this->status = '';
|
|
$this->position = 0;
|
|
$this->pos_stat = 0;
|
|
$this->depth = 0;
|
|
$this->default_namespace = '';
|
|
$this->namespaces = array();
|
|
$this->message = array();
|
|
$this->fault = false;
|
|
$this->fault_code = '';
|
|
$this->fault_str = '';
|
|
$this->fault_detail = '';
|
|
$this->eval_str = '';
|
|
$this->depth_array = array();
|
|
$this->debug_flag = True;
|
|
$this->debug_str = '';
|
|
$this->previous_element = '';
|
|
|
|
$this->entities = array (
|
|
'&' => '&',
|
|
'<' => '<',
|
|
'>' => '>',
|
|
"'" => ''',
|
|
'"' => '"'
|
|
);
|
|
|
|
// Check whether content has been read.
|
|
if(!empty($xml))
|
|
{
|
|
$this->debug('Entering soap_parser()');
|
|
//$this->debug("DATA DUMP:\n\n$xml");
|
|
// Create an XML parser.
|
|
$this->parser = xml_parser_create($this->xml_encoding);
|
|
// Set the options for parsing the XML data.
|
|
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
|
|
// Set the object for the parser.
|
|
xml_set_object($this->parser, &$this);
|
|
// Set the element handlers for the parser.
|
|
xml_set_element_handler($this->parser, 'start_element','end_element');
|
|
xml_set_character_data_handler($this->parser,'character_data');
|
|
xml_set_default_handler($this->parser, 'default_handler');
|
|
|
|
// Parse the XML file.
|
|
if(!xml_parse($this->parser,$xml,true))
|
|
{
|
|
// Display an error message.
|
|
$this->debug(sprintf("XML error on line %d: %s",
|
|
xml_get_current_line_number($this->parser),
|
|
xml_error_string(xml_get_error_code($this->parser))));
|
|
$this->fault = true;
|
|
}
|
|
else
|
|
{
|
|
// get final eval string
|
|
$this->eval_str = "\$response = ".trim($this->build_eval($this->root_struct)).";";
|
|
}
|
|
xml_parser_free($this->parser);
|
|
}
|
|
else
|
|
{
|
|
$this->debug("xml was empty, didn't parse!");
|
|
}
|
|
}
|
|
|
|
// loop through msg, building eval_str
|
|
function build_eval($pos)
|
|
{
|
|
$this->debug("inside build_eval() for $pos: ".$this->message[$pos]["name"]);
|
|
$eval_str = $this->message[$pos]['eval_str'];
|
|
// loop through children, building...
|
|
if($this->message[$pos]['children'] != '')
|
|
{
|
|
$this->debug('children string = '.$this->message[$pos]['children']);
|
|
$children = explode('|',$this->message[$pos]['children']);
|
|
$this->debug('it has '.count($children).' children');
|
|
@reset($children);
|
|
while(list($c,$child_pos) = @each($children))
|
|
/* foreach($children as $c => $child_pos) */
|
|
{
|
|
//$this->debug("child pos $child_pos: ".$this->message[$child_pos]["name"]);
|
|
if($this->message[$child_pos]['eval_str'] != '')
|
|
{
|
|
$this->debug('entering build_eval() for '.$this->message[$child_pos]['name'].", array pos $c, pos: $child_pos");
|
|
$eval_str .= $this->build_eval($child_pos).', ';
|
|
}
|
|
}
|
|
$eval_str = substr($eval_str,0,strlen($eval_str)-2);
|
|
}
|
|
// add current node's eval_str
|
|
$eval_str .= $this->message[$pos]['end_eval_str'];
|
|
return $eval_str;
|
|
}
|
|
|
|
// start-element handler
|
|
function start_element($parser, $name, $attrs)
|
|
{
|
|
// position in a total number of elements, starting from 0
|
|
// update class level pos
|
|
$pos = $this->position++;
|
|
// and set mine
|
|
$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
|
|
$this->message[$pos]['depth'] = $this->depth++;
|
|
|
|
// else add self as child to whoever the current parent is
|
|
if($pos != 0)
|
|
{
|
|
$this->message[$this->parent]['children'] .= "|$pos";
|
|
}
|
|
// set my parent
|
|
$this->message[$pos]['parent'] = $this->parent;
|
|
// set self as current value for this depth
|
|
$this->depth_array[$this->depth] = $pos;
|
|
// set self as current parent
|
|
$this->parent = $pos;
|
|
|
|
// set status
|
|
if(preg_match('/'.":Envelope$".'/',$name))
|
|
{
|
|
$this->status = 'envelope';
|
|
}
|
|
elseif(preg_match('/'.":Header$".'/',$name))
|
|
{
|
|
$this->status = 'header';
|
|
}
|
|
elseif(preg_match('/'.":Body$".'/',$name))
|
|
{
|
|
$this->status = 'body';
|
|
// set method
|
|
}
|
|
elseif($this->status == 'body')
|
|
{
|
|
$this->status = 'method';
|
|
if(preg_match('/:/',$name))
|
|
{
|
|
$this->root_struct_name = substr(strrchr($name,':'),1);
|
|
}
|
|
else
|
|
{
|
|
$this->root_struct_name = $name;
|
|
}
|
|
$this->root_struct = $pos;
|
|
$this->message[$pos]['type'] = 'struct';
|
|
}
|
|
// set my status
|
|
$this->message[$pos]['status'] = $this->status;
|
|
|
|
// set name
|
|
$this->message[$pos]['name'] = htmlspecialchars($name);
|
|
// set attrs
|
|
$this->message[$pos]['attrs'] = $attrs;
|
|
// get namespace
|
|
if(preg_match('/'.":".'/',$name))
|
|
{
|
|
$namespace = substr($name,0,strpos($name,':'));
|
|
$this->message[$pos]['namespace'] = $namespace;
|
|
$this->default_namespace = $namespace;
|
|
}
|
|
else
|
|
{
|
|
$this->message[$pos]['namespace'] = $this->default_namespace;
|
|
}
|
|
// loop through atts, logging ns and type declarations
|
|
@reset($attrs);
|
|
while (list($key,$value) = @each($attrs))
|
|
/* foreach($attrs as $key => $value) */
|
|
{
|
|
// if ns declarations, add to class level array of valid namespaces
|
|
if(preg_match('/xmlns:/',$key))
|
|
{
|
|
$namespaces[substr(strrchr($key,':'),1)] = $value;
|
|
if($name == $this->root_struct_name)
|
|
{
|
|
$this->methodNamespace = $value;
|
|
}
|
|
}
|
|
// if it's a type declaration, set type
|
|
elseif($key == 'xsi:type')
|
|
{
|
|
// then get attname and set $type
|
|
$type = substr(strrchr($value,':'),1);
|
|
}
|
|
}
|
|
|
|
// set type if available
|
|
if($type)
|
|
{
|
|
$this->message[$pos]['type'] = $type;
|
|
}
|
|
|
|
// debug
|
|
//$this->debug("parsed $name start, eval = '".$this->message[$pos]["eval_str"]."'");
|
|
}
|
|
|
|
// end-element handler
|
|
function end_element($parser, $name)
|
|
{
|
|
// position of current element is equal to the last value left in depth_array for my depth
|
|
$pos = $this->depth_array[$this->depth];
|
|
// bring depth down a notch
|
|
$this->depth--;
|
|
|
|
// get type if not set already
|
|
if($this->message[$pos]['type'] == '')
|
|
{
|
|
// if($this->message[$pos]['cdata'] == '' && $this->message[$pos]['children'] != '')
|
|
if($this->message[$pos]['children'] != '')
|
|
{
|
|
$this->message[$pos]['type'] = 'SOAPStruct';
|
|
}
|
|
else
|
|
{
|
|
$this->message[$pos]['type'] = 'string';
|
|
}
|
|
}
|
|
|
|
// set eval str start if it has a valid type and is inside the method
|
|
if($pos >= $this->root_struct)
|
|
{
|
|
$this->message[$pos]['eval_str'] .= "\n CreateObject(\"phpgwapi.soapval\",\"".htmlspecialchars($name)."\", \"".$this->message[$pos]["type"]."\" ";
|
|
$this->message[$pos]['end_eval_str'] = ')';
|
|
$this->message[$pos]['inval'] = 'true';
|
|
/*
|
|
if($this->message[$pos]["name"] == $this->root_struct_name){
|
|
$this->message[$pos]["end_eval_str"] .= " ,\"$this->methodNamespace\"";
|
|
}
|
|
*/
|
|
if($this->message[$pos]['children'] != '')
|
|
{
|
|
$this->message[$pos]['eval_str'] .= ', array( ';
|
|
$this->message[$pos]['end_eval_str'] .= ' )';
|
|
}
|
|
}
|
|
|
|
// if i have no children and have cdata...then i must be a scalar value, so add my data to the eval_str
|
|
if($this->status == 'method' && $this->message[$pos]['children'] == '')
|
|
{
|
|
// add cdata w/ no quotes if only int/float/dbl
|
|
if($this->message[$pos]['type'] == 'string')
|
|
{
|
|
$this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
|
|
}
|
|
elseif($this->message[$pos]['type'] == 'int' || $this->message[$pos]['type'] == 'float' || $this->message[$pos]['type'] == 'double')
|
|
{
|
|
//$this->debug("adding cdata w/o quotes");
|
|
$this->message[$pos]['eval_str'] .= ', '.trim($this->message[$pos]['cdata']);
|
|
}
|
|
elseif(is_string($this->message[$pos]['cdata']))
|
|
{
|
|
//$this->debug("adding cdata w/ quotes");
|
|
$this->message[$pos]['eval_str'] .= ", \"".$this->message[$pos]['cdata']."\"";
|
|
}
|
|
}
|
|
// if in the process of making a soap_val, close the parentheses and move on...
|
|
if($this->message[$pos]['inval'] == 'true')
|
|
{
|
|
$this->message[$pos]['inval'] == 'false';
|
|
}
|
|
// if tag we are currently closing is the method wrapper
|
|
if($pos == $this->root_struct)
|
|
{
|
|
$this->status = 'body';
|
|
}
|
|
elseif(preg_match('/:Body/',$name))
|
|
{
|
|
$this->status = 'header';
|
|
}
|
|
elseif(preg_match('/:Header/',$name))
|
|
{
|
|
$this->status = 'envelope';
|
|
}
|
|
// set parent back to my parent
|
|
$this->parent = $this->message[$pos]['parent'];
|
|
$this->debug("parsed $name end, type '".$this->message[$pos]['type']."'eval_str = '".trim($this->message[$pos]['eval_str'])."' and children = ".$this->message[$pos]['children']);
|
|
}
|
|
|
|
// element content handler
|
|
function character_data($parser, $data)
|
|
{
|
|
$pos = $this->depth_array[$this->depth];
|
|
$this->message[$pos]['cdata'] .= $data;
|
|
//$this->debug("parsed ".$this->message[$pos]["name"]." cdata, eval = '$this->eval_str'");
|
|
}
|
|
|
|
// default handler
|
|
function default_handler($parser, $data)
|
|
{
|
|
//$this->debug("DEFAULT HANDLER: $data");
|
|
}
|
|
|
|
// function to get fault code
|
|
function fault()
|
|
{
|
|
if($this->fault)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// have this return a soap_val object
|
|
function get_response()
|
|
{
|
|
$this->debug("eval()ing eval_str: $this->eval_str");
|
|
@eval("$this->eval_str");
|
|
if($response)
|
|
{
|
|
$this->debug("successfully eval'd msg");
|
|
return $response;
|
|
}
|
|
else
|
|
{
|
|
$this->debug('ERROR: did not successfully eval the msg');
|
|
$this->fault = true;
|
|
return CreateObject('phpgwapi.soapval',
|
|
'Fault',
|
|
'struct',
|
|
array(
|
|
CreateObject('phpgwapi.soapval',
|
|
'faultcode',
|
|
'string',
|
|
'SOAP-ENV:Server'
|
|
),
|
|
CreateObject('phpgwapi.soapval',
|
|
'faultstring',
|
|
'string',
|
|
"couldn't eval \"$this->eval_str\""
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
function debug($string)
|
|
{
|
|
if($this->debug_flag)
|
|
{
|
|
$this->debug_str .= "$string\n";
|
|
}
|
|
}
|
|
|
|
function decode_entities($text)
|
|
{
|
|
@reset($this->entities);
|
|
while(list($entity,$encoded) = @each($this->entities))
|
|
/* foreach($this->entities as $entity => $encoded) */
|
|
{
|
|
$text = str_replace($encoded,$entity,$text);
|
|
}
|
|
return $text;
|
|
}
|
|
}
|
|
?>
|