2001-07-16 08:05:33 +02:00
< ? php
2001-08-18 16:37:52 +02:00
/* $Id$ */
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
class soap_parser
{
function soap_parser ( $xml = '' , $encoding = 'UTF-8' )
{
global $soapTypes ;
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
$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 = '' ;
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
$this -> entities = array (
'&' => '&' ,
'<' => '<' ,
'>' => '>' ,
" ' " => ''' ,
'"' => '"'
);
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
// Check whether content has been read.
if ( ! empty ( $xml ))
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$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 );
2001-07-16 08:05:33 +02:00
}
else
{
2001-08-18 16:37:52 +02:00
$this -> debug ( " xml was empty, didn't parse! " );
2001-07-16 08:05:33 +02:00
}
}
2001-08-18 16:37:52 +02:00
// loop through msg, building eval_str
function build_eval ( $pos )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$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' ] != '' )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$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) */
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
//$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 ) . ', ' ;
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
$eval_str = substr ( $eval_str , 0 , strlen ( $eval_str ) - 2 );
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// add current node's eval_str
$eval_str .= $this -> message [ $pos ][ 'end_eval_str' ];
return $eval_str ;
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// 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 ;
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
// parent/child/depth determinations
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
// depth = how many levels removed from root?
// set mine as current global depth and increment global depth value
$this -> message [ $pos ][ 'depth' ] = $this -> depth ++ ;
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
// 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 ;
2001-07-16 08:05:33 +02:00
2001-08-18 16:37:52 +02:00
// set status
if ( ereg ( " :Envelope $ " , $name ))
{
$this -> status = 'envelope' ;
}
elseif ( ereg ( " :Header $ " , $name ))
{
$this -> status = 'header' ;
}
elseif ( ereg ( " :Body $ " , $name ))
{
$this -> status = 'body' ;
// set method
}
elseif ( $this -> status == 'body' )
{
$this -> status = 'method' ;
if ( ereg ( ':' , $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
2001-07-16 08:05:33 +02:00
if ( ereg ( " : " , $name ))
{
2001-08-18 16:37:52 +02:00
$namespace = substr ( $name , 0 , strpos ( $name , ':' ));
$this -> message [ $pos ][ 'namespace' ] = $namespace ;
$this -> default_namespace = $namespace ;
2001-07-16 08:05:33 +02:00
}
else
{
2001-08-18 16:37:52 +02:00
$this -> message [ $pos ][ 'namespace' ] = $this -> default_namespace ;
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// loop through atts, logging ns and type declarations
@ reset ( $attrs );
while ( list ( $key , $value ) = @ each ( $attrs ))
/* foreach($attrs as $key => $value) */
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
// if ns declarations, add to class level array of valid namespaces
if ( ereg ( 'xmlns:' , $key ))
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$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 );
2001-07-16 08:05:33 +02:00
}
}
2001-08-18 16:37:52 +02:00
// set type if available
if ( $type )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$this -> message [ $pos ][ 'type' ] = $type ;
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// debug
//$this->debug("parsed $name start, eval = '".$this->message[$pos]["eval_str"]."'");
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// end-element handler
function end_element ( $parser , $name )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
// 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' ] == '' )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
// 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' ;
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// set eval str start if it has a valid type and is inside the method
if ( $pos >= $this -> root_struct )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$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' ] .= ' )' ;
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// 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' ] == '' )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
// 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' ] . " \" " ;
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// if in the process of making a soap_val, close the parentheses and move on...
if ( $this -> message [ $pos ][ 'inval' ] == 'true' )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$this -> message [ $pos ][ 'inval' ] == 'false' ;
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// if tag we are currently closing is the method wrapper
if ( $pos == $this -> root_struct )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$this -> status = 'body' ;
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
elseif ( ereg ( ':Body' , $name ))
{
$this -> status = 'header' ;
}
elseif ( ereg ( ':Header' , $name ))
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$this -> status = 'envelope' ;
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// 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' ]);
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// element content handler
function character_data ( $parser , $data )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$pos = $this -> depth_array [ $this -> depth ];
$this -> message [ $pos ][ 'cdata' ] .= $data ;
//$this->debug("parsed ".$this->message[$pos]["name"]." cdata, eval = '$this->eval_str'");
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// default handler
function default_handler ( $parser , $data )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
//$this->debug("DEFAULT HANDLER: $data");
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// function to get fault code
function fault ()
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
if ( $this -> fault )
{
return true ;
}
else
{
return false ;
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
// have this return a soap_val object
function get_response ()
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
$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\ " "
)
2001-07-16 08:05:33 +02:00
)
2001-08-18 16:37:52 +02:00
);
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
function debug ( $string )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
if ( $this -> debug_flag )
{
$this -> debug_str .= " $string\n " ;
}
2001-07-16 08:05:33 +02:00
}
2001-08-18 16:37:52 +02:00
function decode_entities ( $text )
2001-07-16 08:05:33 +02:00
{
2001-08-18 16:37:52 +02:00
@ reset ( $this -> entities );
while ( list ( $entity , $encoded ) = @ each ( $this -> entities ))
/* foreach($this->entities as $entity => $encoded) */
{
$text = str_replace ( $encoded , $entity , $text );
}
return $text ;
2001-07-16 08:05:33 +02:00
}
}
?>