1<?php
2	/**
3	* SOAPx4 ("XML-RPC for PHP" and "SOAP for PHP")
4	* @author Dietrich Ayala <dietrich@ganx4.com>
5	* @author Edd Dumbill
6	* @author Victor Zou <victor@gigaideas.com.cn>
7	* @copyright Copyright (C) 1999-2000 Edd Dumbill
8	* @copyright Copyright (C) 2000-2001 Victor Zou
9	* @copyright Copyright (C) 2001 Dietrich Ayala
10	* @copyright Portions Copyright (C) 2004 Free Software Foundation, Inc. http://www.fsf.org/
11	* @package phpgwapi
12	* @subpackage communication
13	* @version $Id: class.wsdl.inc.php 14407 2004-02-10 13:51:20Z ceb $
14	* @internal This project began based on code from the 2 projects below,
15	* @internal and still contains some original code. The licenses of both must be respected.
16	*/
17
18	/**
19	* SOAPx4 ("XML-RPC for PHP" and "SOAP for PHP")
20	*
21	* @package phpgwapi
22	* @subpackage communication
23	* This is a class that loads a wsdl file and makes it's data available to an application
24	* it should provide methods that allow both client and server usage of it
25	* Also should have methods for creating a wsdl file from scratch and
26	* serializing wsdl into valid markup
27	*/
28	class wsdl
29	{
30		// constructor
31		function wsdl($wsdl=False)
32		{
33			// define internal arrays of bindings, ports, operations, messages, etc.
34			$this->complexTypes = array();
35			$this->messages = array();
36			$this->currentMessage;
37			$this->portOperations = array();
38			$this->currentOperation;
39			$this->portTypes = array();
40			$this->currentPortType;
41			$this->bindings = array();
42			$this->currentBinding;
43			// debug switch
44			$this->debug_flag = False;
45			// parser vars
46			$this->parser;
47			$this->position;
48			$this->depth;
49			$this->depth_array = array();
50
51			if($wsdl == "-1")
52			{
53				$wsdl=False;
54			}
55			// Check whether content has been read.
56			if($wsdl)
57			{
58				$wsdl_string = join("",file($wsdl));
59				// Create an XML parser.
60				$this->parser = xml_parser_create();
61				// Set the options for parsing the XML data.
62				//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
63				xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
64				// Set the object for the parser.
65				xml_set_object($this->parser, &$this);
66				// Set the element handlers for the parser.
67				xml_set_element_handler($this->parser, 'start_element','end_element');
68				xml_set_character_data_handler($this->parser,'character_data');
69				//xml_set_default_handler($this->parser, 'default_handler');
70
71				// Parse the XML file.
72				if(!xml_parse($this->parser,$wsdl_string,True))
73				{
74					// Display an error message.
75					$this->debug(sprintf('XML error on line %d: %s',
76						xml_get_current_line_number($this->parser),
77						xml_error_string(xml_get_error_code($this->parser))));
78					$this->fault = True;
79				}
80				xml_parser_free($this->parser);
81			}
82		}
83
84		// start-element handler
85		function start_element($parser, $name, $attrs)
86		{
87			// position in the total number of elements, starting from 0
88			$pos = $this->position++;
89			$depth = $this->depth++;
90			// set self as current value for this depth
91			$this->depth_array[$depth] = $pos;
92
93			// find status, register data
94			switch($this->status)
95			{
96				case 'types':
97				switch($name)
98				{
99					case 'schema':
100						$this->schema = True;
101						break;
102					case 'complexType':
103						$this->currentElement = $attrs['name'];
104						$this->schemaStatus = 'complexType';
105						break;
106					case 'element':
107						$this->complexTypes[$this->currentElement]['elements'][$attrs['name']] = $attrs;
108						break;
109					case 'complexContent':
110						break;
111					case 'restriction':
112						$this->complexTypes[$this->currentElement]['restrictionBase'] = $attrs['base'];
113						break;
114					case 'sequence':
115						$this->complexTypes[$this->currentElement]['order'] = 'sequence';
116						break;
117					case "all":
118						$this->complexTypes[$this->currentElement]['order'] = 'all';
119						break;
120					case 'attribute':
121						if($attrs['ref'])
122						{
123							$this->complexTypes[$this->currentElement]['attrs'][$attrs['ref']] = $attrs;
124						}
125						elseif($attrs['name'])
126						{
127							$this->complexTypes[$this->currentElement]['attrs'][$attrs['name']] = $attrs;
128						}
129						break;
130					}
131					break;
132				case 'message':
133					if($name == 'part')
134					{
135						$this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
136					}
137					break;
138				case 'portType':
139					switch($name)
140					{
141						case 'operation':
142							$this->currentOperation = $attrs['name'];
143							$this->portTypes[$this->currentPortType][$attrs['name']] = $attrs['parameterOrder'];
144						break;
145						default:
146							$this->portOperations[$this->currentOperation][$name]= $attrs;
147							break;
148					}
149					break;
150				case 'binding':
151					switch($name)
152					{
153						case 'soap:binding':
154							$this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding],$attrs);
155							break;
156						case 'operation':
157							$this->currentOperation = $attrs['name'];
158							$this->bindings[$this->currentBinding]['operations'][$attrs['name']] = array();
159							break;
160						case 'soap:operation':
161							$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
162							break;
163						case 'input':
164							$this->opStatus = 'input';
165						case 'soap:body':
166							$this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
167							break;
168						case 'output':
169							$this->opStatus = 'output';
170							break;
171					}
172					break;
173				case 'service':
174					switch($name)
175					{
176						case 'port':
177							$this->currentPort = $attrs['name'];
178							$this->ports[$attrs['name']] = $attrs;
179							break;
180						case 'soap:address':
181							$this->ports[$this->currentPort]['location'] = $attrs['location'];
182							break;
183					}
184					break;
185			}
186			// set status
187			switch($name)
188			{
189				case 'types':
190					$this->status = 'types';
191					break;
192				case 'message':
193					$this->status = 'message';
194					$this->messages[$attrs['name']] = array();
195					$this->currentMessage = $attrs['name'];
196					break;
197				case 'portType':
198					$this->status = 'portType';
199					$this->portTypes[$attrs['name']] = array();
200					$this->currentPortType = $attrs['name'];
201					break;
202				case 'binding':
203					$this->status = 'binding';
204					$this->currentBinding = $attrs['name'];
205					$this->bindings[$attrs['name']]['type'] = $attrs['type'];
206					break;
207				case 'service':
208					$this->status = 'service';
209					break;
210			}
211			// get element prefix
212			if(ereg(":",$name))
213			{
214				$prefix = substr($name,0,strpos($name,':'));
215			}
216		}
217
218		function getEndpoint($portName)
219		{
220			if($endpoint = $this->ports[$portName]['location'])
221			{
222				return $endpoint;
223			}
224			return False;
225		}
226
227		function getPortName($operation)
228		{
229			@reset($this->ports);
230			while(list($port,$portAttrs) = @each($this->ports));
231			/* foreach($this->ports as $port => $portAttrs) */
232			{
233				$binding = substr($portAttrs['binding'],4);
234				@reset($this->bindings[$binding]['operations']);
235				while(list($op,$opAttrs) = @each($this->bindings[$binding]['operations']))
236				/* foreach($this->bindings[$binding]["operations"] as $op => $opAttrs) */
237				{
238					if($op == $operation)
239					{
240						return $port;
241					}
242				}
243			}
244		}
245
246		function getSoapAction($portName,$operation)
247		{
248			if($binding = substr($this->ports[$portName]['binding'],4))
249			{
250				if($soapAction = $this->bindings[$binding]['operations'][$operation]['soapAction'])
251				{
252					return $soapAction;
253				}
254				return False;
255			}
256			return False;
257		}
258
259		function getNamespace($portName,$operation)
260		{
261			if($binding = substr($this->ports[$portName]['binding'],4))
262			{
263				//$this->debug("looking for namespace using binding '$binding', port '$portName', operation '$operation'");
264				if($namespace = $this->bindings[$binding]['operations'][$operation]['input']['namespace'])
265				{
266					return $namespace;
267				}
268				return False;
269			}
270			return False;
271		}
272
273		// end-element handler
274		function end_element($parser, $name)
275		{
276			// position of current element is equal to the last value left in depth_array for my depth
277			$pos = $this->depth_array[$this->depth];
278			// bring depth down a notch
279			$this->depth--;
280		}
281
282		// element content handler
283		function character_data($parser, $data)
284		{
285			$pos = $this->depth_array[$this->depth];
286			$this->message[$pos]['cdata'] .= $data;
287		}
288
289		function debug($string)
290		{
291			if($this->debug_flag)
292			{
293				$this->debug_str .= "$string\n";
294			}
295		}
296	}
297?>
298