<?php /* SOAPx4 by Dietrich Ayala (C) 2001 dietrich@ganx4.com This project began based on code from the 2 projects below, and still contains some original code. The licenses of both must be respected. XML-RPC for PHP originally by Edd Dumbill (C) 1999-2000 SOAP for PHP by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn> this is a class that loads a wsdl file and makes it's data available to an application it should provide methods that allow both client and server usage of it also should have methods for creating a wsdl file from scratch and serializing wsdl into valid markup */ /* $Id$ */ class wsdl { // constructor function wsdl($wsdl=False) { // define internal arrays of bindings, ports, operations, messages, etc. $this->complexTypes = array(); $this->messages = array(); $this->currentMessage; $this->portOperations = array(); $this->currentOperation; $this->portTypes = array(); $this->currentPortType; $this->bindings = array(); $this->currentBinding; // debug switch $this->debug_flag = False; // parser vars $this->parser; $this->position; $this->depth; $this->depth_array = array(); if($wsdl == "-1") { $wsdl=False; } // Check whether content has been read. if($wsdl) { $wsdl_string = join("",file($wsdl)); // Create an XML parser. $this->parser = xml_parser_create(); // 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,$wsdl_string,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; } xml_parser_free($this->parser); } } // start-element handler function start_element($parser, $name, $attrs) { // position in the total number of elements, starting from 0 $pos = $this->position++; $depth = $this->depth++; // set self as current value for this depth $this->depth_array[$depth] = $pos; // find status, register data switch($this->status) { case 'types': switch($name) { case 'schema': $this->schema = True; break; case 'complexType': $this->currentElement = $attrs['name']; $this->schemaStatus = 'complexType'; break; case 'element': $this->complexTypes[$this->currentElement]['elements'][$attrs['name']] = $attrs; break; case 'complexContent': break; case 'restriction': $this->complexTypes[$this->currentElement]['restrictionBase'] = $attrs['base']; break; case 'sequence': $this->complexTypes[$this->currentElement]['order'] = 'sequence'; break; case "all": $this->complexTypes[$this->currentElement]['order'] = 'all'; break; case 'attribute': if($attrs['ref']) { $this->complexTypes[$this->currentElement]['attrs'][$attrs['ref']] = $attrs; } elseif($attrs['name']) { $this->complexTypes[$this->currentElement]['attrs'][$attrs['name']] = $attrs; } break; } break; case 'message': if($name == 'part') { $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; } break; case 'portType': switch($name) { case 'operation': $this->currentOperation = $attrs['name']; $this->portTypes[$this->currentPortType][$attrs['name']] = $attrs['parameterOrder']; break; default: $this->portOperations[$this->currentOperation][$name]= $attrs; break; } break; case 'binding': switch($name) { case 'soap:binding': $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding],$attrs); break; case 'operation': $this->currentOperation = $attrs['name']; $this->bindings[$this->currentBinding]['operations'][$attrs['name']] = array(); break; case 'soap:operation': $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; break; case 'input': $this->opStatus = 'input'; case 'soap:body': $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; break; case 'output': $this->opStatus = 'output'; break; } break; case 'service': switch($name) { case 'port': $this->currentPort = $attrs['name']; $this->ports[$attrs['name']] = $attrs; break; case 'soap:address': $this->ports[$this->currentPort]['location'] = $attrs['location']; break; } break; } // set status switch($name) { case 'types': $this->status = 'types'; break; case 'message': $this->status = 'message'; $this->messages[$attrs['name']] = array(); $this->currentMessage = $attrs['name']; break; case 'portType': $this->status = 'portType'; $this->portTypes[$attrs['name']] = array(); $this->currentPortType = $attrs['name']; break; case 'binding': $this->status = 'binding'; $this->currentBinding = $attrs['name']; $this->bindings[$attrs['name']]['type'] = $attrs['type']; break; case 'service': $this->status = 'service'; break; } // get element prefix if(ereg(":",$name)) { $prefix = substr($name,0,strpos($name,':')); } } function getEndpoint($portName) { if($endpoint = $this->ports[$portName]['location']) { return $endpoint; } return False; } function getPortName($operation) { @reset($this->ports); while(list($port,$portAttrs) = @each($this->ports)); /* foreach($this->ports as $port => $portAttrs) */ { $binding = substr($portAttrs['binding'],4); @reset($this->bindings[$binding]['operations']); while(list($op,$opAttrs) = @each($this->bindings[$binding]['operations'])) /* foreach($this->bindings[$binding]["operations"] as $op => $opAttrs) */ { if($op == $operation) { return $port; } } } } function getSoapAction($portName,$operation) { if($binding = substr($this->ports[$portName]['binding'],4)) { if($soapAction = $this->bindings[$binding]['operations'][$operation]['soapAction']) { return $soapAction; } return False; } return False; } function getNamespace($portName,$operation) { if($binding = substr($this->ports[$portName]['binding'],4)) { //$this->debug("looking for namespace using binding '$binding', port '$portName', operation '$operation'"); if($namespace = $this->bindings[$binding]['operations'][$operation]['input']['namespace']) { return $namespace; } return False; } return False; } // 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--; } // element content handler function character_data($parser, $data) { $pos = $this->depth_array[$this->depth]; $this->message[$pos]['cdata'] .= $data; } function debug($string) { if($this->debug_flag) { $this->debug_str .= "$string\n"; } } } ?>