|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* NuSOAP - Web Services Toolkit for PHP |
|
4
|
|
|
* |
|
5
|
|
|
* @author: Dietrich Ayala |
|
6
|
|
|
*/ |
|
7
|
|
|
|
|
8
|
|
|
/* |
|
9
|
|
|
Copyright (c) 2002 NuSphere Corporation |
|
10
|
|
|
|
|
11
|
|
|
This library is free software; you can redistribute it and/or |
|
12
|
|
|
modify it under the terms of the GNU Lesser General Public |
|
13
|
|
|
License as published by the Free Software Foundation; either |
|
14
|
|
|
version 2.1 of the License, or (at your option) any later version. |
|
15
|
|
|
|
|
16
|
|
|
This library is distributed in the hope that it will be useful, |
|
17
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
19
|
|
|
Lesser General Public License for more details. |
|
20
|
|
|
|
|
21
|
|
|
You should have received a copy of the GNU Lesser General Public |
|
22
|
|
|
License along with this library; if not, write to the Free Software |
|
23
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
24
|
|
|
|
|
25
|
|
|
If you have any questions or comments, please email: |
|
26
|
|
|
|
|
27
|
|
|
Dietrich Ayala |
|
28
|
|
|
[email protected] |
|
29
|
|
|
http://dietrich.ganx4.com/nusoap |
|
30
|
|
|
|
|
31
|
|
|
NuSphere Corporation |
|
32
|
|
|
http://www.nusphere.com |
|
33
|
|
|
|
|
34
|
|
|
*/ |
|
35
|
|
|
|
|
36
|
|
|
/* load classes |
|
37
|
|
|
|
|
38
|
|
|
// necessary classes |
|
39
|
|
|
require_once('class.soapclient.php'); |
|
40
|
|
|
require_once('class.soap_val.php'); |
|
41
|
|
|
require_once('class.soap_parser.php'); |
|
42
|
|
|
require_once('class.soap_fault.php'); |
|
43
|
|
|
|
|
44
|
|
|
// transport classes |
|
45
|
|
|
require_once('class.soap_transport_http.php'); |
|
46
|
|
|
|
|
47
|
|
|
// optional add-on classes |
|
48
|
|
|
require_once('class.xmlschema.php'); |
|
49
|
|
|
require_once('class.wsdl.php'); |
|
50
|
|
|
|
|
51
|
|
|
// server class |
|
52
|
|
|
require_once('class.soap_server.php');*/ |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* |
|
56
|
|
|
* nusoap_base |
|
57
|
|
|
* |
|
58
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
59
|
|
|
* @version v 0.6.3 |
|
60
|
|
|
* @access public |
|
61
|
|
|
*/ |
|
62
|
|
|
class nusoap_base { |
|
63
|
|
|
|
|
64
|
|
|
var $title = 'NuSOAP'; |
|
65
|
|
|
var $version = '0.6.3'; |
|
66
|
|
|
var $error_str = false; |
|
67
|
|
|
var $debug_str = ''; |
|
68
|
|
|
// toggles automatic encoding of special characters |
|
69
|
|
|
var $charencoding = true; |
|
70
|
|
|
|
|
71
|
|
|
/** |
|
72
|
|
|
* set schema version |
|
73
|
|
|
* |
|
74
|
|
|
* @var XMLSchemaVersion |
|
75
|
|
|
* @access public |
|
76
|
|
|
*/ |
|
77
|
|
|
var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; |
|
78
|
|
|
|
|
79
|
|
|
/** |
|
80
|
|
|
* set default encoding |
|
81
|
|
|
* |
|
82
|
|
|
* @var soap_defencoding |
|
83
|
|
|
* @access public |
|
84
|
|
|
*/ |
|
85
|
|
|
//var $soap_defencoding = 'UTF-8'; |
|
86
|
|
|
var $soap_defencoding = 'ISO-8859-1'; |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* load namespace uris into an array of uri => prefix |
|
90
|
|
|
* |
|
91
|
|
|
* @var namespaces |
|
92
|
|
|
* @access public |
|
93
|
|
|
*/ |
|
94
|
|
|
var $namespaces = array( |
|
95
|
|
|
'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', |
|
96
|
|
|
'xsd' => 'http://www.w3.org/2001/XMLSchema', |
|
97
|
|
|
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', |
|
98
|
|
|
'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', |
|
99
|
|
|
'si' => 'http://soapinterop.org/xsd'); |
|
100
|
|
|
/** |
|
101
|
|
|
* load types into typemap array |
|
102
|
|
|
* is this legacy yet? |
|
103
|
|
|
* no, this is used by the xmlschema class to verify type => namespace mappings. |
|
104
|
|
|
* @var typemap |
|
105
|
|
|
* @access public |
|
106
|
|
|
*/ |
|
107
|
|
|
var $typemap = |
|
108
|
|
|
array( |
|
109
|
|
|
'http://www.w3.org/2001/XMLSchema' => |
|
110
|
|
|
array( |
|
111
|
|
|
'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', |
|
112
|
|
|
'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', |
|
113
|
|
|
'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', |
|
114
|
|
|
// derived datatypes |
|
115
|
|
|
'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', |
|
116
|
|
|
'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', |
|
117
|
|
|
'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', |
|
118
|
|
|
'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), |
|
119
|
|
|
'http://www.w3.org/1999/XMLSchema' => |
|
120
|
|
|
array( |
|
121
|
|
|
'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', |
|
122
|
|
|
'float'=>'double','dateTime'=>'string', |
|
123
|
|
|
'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), |
|
124
|
|
|
'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), |
|
125
|
|
|
'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), |
|
126
|
|
|
'http://xml.apache.org/xml-soap' => array('Map') |
|
127
|
|
|
); |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* entities to convert |
|
131
|
|
|
* |
|
132
|
|
|
* @var xmlEntities |
|
133
|
|
|
* @access public |
|
134
|
|
|
*/ |
|
135
|
|
|
var $xmlEntities = array('quot' => '"','amp' => '&', |
|
136
|
|
|
'lt' => '<','gt' => '>','apos' => "'"); |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* adds debug data to the class level debug string |
|
140
|
|
|
* |
|
141
|
|
|
* @param string $string debug data |
|
142
|
|
|
* @access private |
|
143
|
|
|
*/ |
|
144
|
|
|
function debug($string){ |
|
145
|
|
|
$this->debug_str .= get_class($this).": $string\n"; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* returns error string if present |
|
150
|
|
|
* |
|
151
|
|
|
* @return boolean $string error string |
|
152
|
|
|
* @access public |
|
153
|
|
|
*/ |
|
154
|
|
|
function getError(){ |
|
155
|
|
|
if($this->error_str != ''){ |
|
156
|
|
|
return $this->error_str; |
|
157
|
|
|
} |
|
158
|
|
|
return false; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* sets error string |
|
163
|
|
|
* |
|
164
|
|
|
* @return boolean $string error string |
|
165
|
|
|
* @access private |
|
166
|
|
|
*/ |
|
167
|
|
|
function setError($str){ |
|
168
|
|
|
$this->error_str = $str; |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
/** |
|
172
|
|
|
* serializes PHP values in accordance w/ section 5. Type information is |
|
173
|
|
|
* not serialized if $use == 'literal'. |
|
174
|
|
|
* |
|
175
|
|
|
* @return string |
|
176
|
|
|
* @access public |
|
177
|
|
|
*/ |
|
178
|
|
|
function serialize_val($val,$name=false,$type=false,$name_ns=false, |
|
179
|
|
|
$type_ns=false,$attributes=false,$use='encoded') { |
|
180
|
|
|
if(is_object($val) && strtolower(get_class($val)) == 'soapval'){ |
|
181
|
|
|
return $val->serialize($use); |
|
182
|
|
|
} |
|
183
|
|
|
$this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use"); |
|
184
|
|
|
// if no name, use item |
|
185
|
|
|
$name = (!$name|| is_numeric($name)) ? 'soapVal' : $name; |
|
186
|
|
|
// if name has ns, add ns prefix to name |
|
187
|
|
|
$xmlns = ''; |
|
188
|
|
|
if($name_ns){ |
|
189
|
|
|
$prefix = 'nu'.rand(1000,9999); |
|
190
|
|
|
$name = $prefix.':'.$name; |
|
191
|
|
|
$xmlns .= " xmlns:$prefix=\"$name_ns\""; |
|
192
|
|
|
} |
|
193
|
|
|
// if type is prefixed, create type prefix |
|
194
|
|
|
if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ |
|
195
|
|
|
// need to fix this. shouldn't default to xsd if no ns specified |
|
196
|
|
|
// w/o checking against typemap |
|
197
|
|
|
$type_prefix = 'xsd'; |
|
198
|
|
|
} elseif($type_ns){ |
|
199
|
|
|
$type_prefix = 'ns'.rand(1000,9999); |
|
200
|
|
|
$xmlns .= " xmlns:$type_prefix=\"$type_ns\""; |
|
201
|
|
|
} |
|
202
|
|
|
// serialize attributes if present |
|
203
|
|
|
if($attributes){ |
|
204
|
|
|
foreach($attributes as $k => $v){ |
|
|
|
|
|
|
205
|
|
|
$atts .= " $k=\"$v\""; |
|
206
|
|
|
} |
|
207
|
|
|
} |
|
208
|
|
|
// serialize if an xsd built-in primitive type |
|
209
|
|
|
if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ |
|
210
|
|
|
if ($use == 'literal') { |
|
211
|
|
|
return "<$name$xmlns>$val</$name>"; |
|
212
|
|
|
} else { |
|
213
|
|
|
return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>"; |
|
214
|
|
|
} |
|
215
|
|
|
} |
|
216
|
|
|
// detect type and serialize |
|
217
|
|
|
$xml = ''; |
|
218
|
|
|
$atts = ''; |
|
219
|
|
|
switch(true) { |
|
220
|
|
|
case ($type == '' && is_null($val)): |
|
221
|
|
|
if ($use == 'literal') { |
|
222
|
|
|
// TODO: depends on nillable |
|
223
|
|
|
$xml .= "<$name$xmlns/>"; |
|
224
|
|
|
} else { |
|
225
|
|
|
$xml .= "<$name$xmlns xsi:type=\"xsd:nil\"/>"; |
|
226
|
|
|
} |
|
227
|
|
|
break; |
|
228
|
|
|
case (is_bool($val) || $type == 'boolean'): |
|
229
|
|
|
if(!$val){ |
|
230
|
|
|
$val = 0; |
|
231
|
|
|
} |
|
232
|
|
|
if ($use == 'literal') { |
|
233
|
|
|
$xml .= "<$name$xmlns $atts>$val</$name>"; |
|
234
|
|
|
} else { |
|
235
|
|
|
$xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; |
|
236
|
|
|
} |
|
237
|
|
|
break; |
|
238
|
|
|
case (is_int($val) || is_long($val) || $type == 'int'): |
|
239
|
|
|
if ($use == 'literal') { |
|
240
|
|
|
$xml .= "<$name$xmlns $atts>$val</$name>"; |
|
241
|
|
|
} else { |
|
242
|
|
|
$xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; |
|
243
|
|
|
} |
|
244
|
|
|
break; |
|
245
|
|
|
case (is_float($val)|| is_double($val) || $type == 'float'): |
|
246
|
|
|
if ($use == 'literal') { |
|
247
|
|
|
$xml .= "<$name$xmlns $atts>$val</$name>"; |
|
248
|
|
|
} else { |
|
249
|
|
|
$xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; |
|
250
|
|
|
} |
|
251
|
|
|
break; |
|
252
|
|
|
case (is_string($val) || $type == 'string'): |
|
253
|
|
|
if($this->charencoding){ |
|
254
|
|
|
$val = htmlspecialchars($val, ENT_QUOTES); |
|
255
|
|
|
} |
|
256
|
|
|
if ($use == 'literal') { |
|
257
|
|
|
$xml .= "<$name$xmlns $atts>$val</$name>"; |
|
258
|
|
|
} else { |
|
259
|
|
|
$xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; |
|
260
|
|
|
} |
|
261
|
|
|
break; |
|
262
|
|
|
case is_object($val): |
|
263
|
|
|
$name = strtolower(get_class($val)); |
|
264
|
|
|
foreach(get_object_vars($val) as $k => $v){ |
|
265
|
|
|
$pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); |
|
266
|
|
|
} |
|
267
|
|
|
$xml .= '<'.$name.'>'.$pXml.'</'.$name.'>'; |
|
268
|
|
|
break; |
|
269
|
|
|
break; |
|
|
|
|
|
|
270
|
|
|
case (is_array($val) || $type): |
|
271
|
|
|
// detect if struct or array |
|
272
|
|
|
$keyList = array_keys($val); |
|
273
|
|
|
$valueType = 'arraySimple'; |
|
274
|
|
|
foreach($keyList as $keyListValue){ |
|
275
|
|
|
if(!is_int($keyListValue)){ |
|
276
|
|
|
$valueType = 'arrayStruct'; |
|
277
|
|
|
break; |
|
278
|
|
|
} |
|
279
|
|
|
} |
|
280
|
|
|
if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ |
|
281
|
|
|
$i = 0; |
|
282
|
|
|
if(is_array($val) && count($val)> 0){ |
|
283
|
|
|
foreach($val as $v){ |
|
284
|
|
|
if(is_object($v) && strtolower(get_class($v)) == 'soapval'){ |
|
285
|
|
|
$tt = $v->type; |
|
286
|
|
|
} else { |
|
287
|
|
|
$tt = gettype($v); |
|
288
|
|
|
} |
|
289
|
|
|
$array_types[$tt] = 1; |
|
290
|
|
|
$xml .= $this->serialize_val($v,'item',false,false,false,false,$use); |
|
291
|
|
|
if(is_array($v) && is_numeric(key($v))){ |
|
292
|
|
|
$i += sizeof($v); |
|
293
|
|
|
} else { |
|
294
|
|
|
++$i; |
|
295
|
|
|
} |
|
296
|
|
|
} |
|
297
|
|
|
if(count($array_types) > 1){ |
|
298
|
|
|
$array_typename = 'xsd:ur-type'; |
|
299
|
|
|
} elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { |
|
300
|
|
|
$array_typename = 'xsd:'.$tt; |
|
301
|
|
|
} elseif($tt == 'array' || $tt == 'Array'){ |
|
302
|
|
|
$array_typename = 'SOAP-ENC:Array'; |
|
303
|
|
|
} else { |
|
304
|
|
|
$array_typename = $tt; |
|
305
|
|
|
} |
|
306
|
|
|
if(isset($array_types['array'])){ |
|
307
|
|
|
$array_type = $i.",".$i; |
|
308
|
|
|
} else { |
|
309
|
|
|
$array_type = $i; |
|
310
|
|
|
} |
|
311
|
|
|
if ($use == 'literal') { |
|
312
|
|
|
$xml = "<$name $atts>".$xml."</$name>"; |
|
313
|
|
|
} else { |
|
314
|
|
|
$xml = "<$name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"$atts>".$xml."</$name>"; |
|
315
|
|
|
} |
|
316
|
|
|
// empty array |
|
317
|
|
|
} else { |
|
318
|
|
|
if ($use == 'literal') { |
|
319
|
|
|
$xml = "<$name $atts>".$xml."</$name>";; |
|
320
|
|
|
} else { |
|
321
|
|
|
$xml = "<$name xsi:type=\"SOAP-ENC:Array\" $atts>".$xml."</$name>";; |
|
322
|
|
|
} |
|
323
|
|
|
} |
|
324
|
|
|
} else { |
|
325
|
|
|
// got a struct |
|
326
|
|
|
if(isset($type) && isset($type_prefix)){ |
|
327
|
|
|
$type_str = " xsi:type=\"$type_prefix:$type\""; |
|
328
|
|
|
} else { |
|
329
|
|
|
$type_str = ''; |
|
330
|
|
|
} |
|
331
|
|
|
if ($use == 'literal') { |
|
332
|
|
|
$xml .= "<$name$xmlns $atts>"; |
|
333
|
|
|
} else { |
|
334
|
|
|
$xml .= "<$name$xmlns$type_str$atts>"; |
|
335
|
|
|
} |
|
336
|
|
|
foreach($val as $k => $v){ |
|
337
|
|
|
$xml .= $this->serialize_val($v,$k,false,false,false,false,$use); |
|
338
|
|
|
} |
|
339
|
|
|
$xml .= "</$name>"; |
|
340
|
|
|
} |
|
341
|
|
|
break; |
|
342
|
|
|
default: |
|
343
|
|
|
$xml .= 'not detected, got '.gettype($val).' for '.$val; |
|
344
|
|
|
break; |
|
345
|
|
|
} |
|
346
|
|
|
return $xml; |
|
347
|
|
|
} |
|
348
|
|
|
|
|
349
|
|
|
/** |
|
350
|
|
|
* serialize message |
|
351
|
|
|
* |
|
352
|
|
|
* @param string body |
|
353
|
|
|
* @param string headers |
|
354
|
|
|
* @param array namespaces |
|
355
|
|
|
* @param string style |
|
356
|
|
|
* @return string message |
|
357
|
|
|
* @access public |
|
358
|
|
|
*/ |
|
359
|
|
|
function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc'){ |
|
360
|
|
|
// serialize namespaces |
|
361
|
|
|
$ns_string = ''; |
|
362
|
|
|
foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ |
|
363
|
|
|
$ns_string .= " xmlns:$k=\"$v\""; |
|
364
|
|
|
} |
|
365
|
|
|
if($style == 'rpc') { |
|
366
|
|
|
$ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string; |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
// serialize headers |
|
370
|
|
|
if($headers){ |
|
371
|
|
|
$headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; |
|
372
|
|
|
} |
|
373
|
|
|
// serialize envelope |
|
374
|
|
|
return |
|
375
|
|
|
'<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". |
|
376
|
|
|
'<SOAP-ENV:Envelope'.$ns_string.">". |
|
377
|
|
|
$headers. |
|
378
|
|
|
"<SOAP-ENV:Body>". |
|
379
|
|
|
$body. |
|
380
|
|
|
"</SOAP-ENV:Body>". |
|
381
|
|
|
"</SOAP-ENV:Envelope>"; |
|
382
|
|
|
} |
|
383
|
|
|
|
|
384
|
|
|
function formatDump($str){ |
|
385
|
|
|
$str = htmlspecialchars($str); |
|
386
|
|
|
return nl2br($str); |
|
387
|
|
|
} |
|
388
|
|
|
|
|
389
|
|
|
/** |
|
390
|
|
|
* returns the local part of a prefixed string |
|
391
|
|
|
* returns the original string, if not prefixed |
|
392
|
|
|
* |
|
393
|
|
|
* @param string |
|
394
|
|
|
* @return string |
|
395
|
|
|
* @access public |
|
396
|
|
|
*/ |
|
397
|
|
|
function getLocalPart($str){ |
|
398
|
|
|
if($sstr = strrchr($str,':')){ |
|
399
|
|
|
// get unqualified name |
|
400
|
|
|
return substr( $sstr, 1 ); |
|
401
|
|
|
} else { |
|
402
|
|
|
return $str; |
|
403
|
|
|
} |
|
404
|
|
|
} |
|
405
|
|
|
|
|
406
|
|
|
/** |
|
407
|
|
|
* returns the prefix part of a prefixed string |
|
408
|
|
|
* returns false, if not prefixed |
|
409
|
|
|
* |
|
410
|
|
|
* @param string |
|
411
|
|
|
* @return mixed |
|
412
|
|
|
* @access public |
|
413
|
|
|
*/ |
|
414
|
|
|
function getPrefix($str){ |
|
415
|
|
|
if($pos = strrpos($str,':')){ |
|
416
|
|
|
// get prefix |
|
417
|
|
|
return substr($str,0,$pos); |
|
418
|
|
|
} |
|
419
|
|
|
return false; |
|
420
|
|
|
} |
|
421
|
|
|
|
|
422
|
|
|
function varDump($data) { |
|
423
|
|
|
ob_start(); |
|
424
|
|
|
var_dump($data); |
|
|
|
|
|
|
425
|
|
|
$ret_val = ob_get_contents(); |
|
426
|
|
|
ob_end_clean(); |
|
427
|
|
|
return $ret_val; |
|
428
|
|
|
} |
|
429
|
|
|
} |
|
430
|
|
|
|
|
431
|
|
|
// XML Schema Datatype Helper Functions |
|
432
|
|
|
|
|
433
|
|
|
//xsd:dateTime helpers |
|
434
|
|
|
|
|
435
|
|
|
/** |
|
436
|
|
|
* convert unix timestamp to ISO 8601 compliant date string |
|
437
|
|
|
* |
|
438
|
|
|
* @param string $timestamp Unix time stamp |
|
439
|
|
|
* @access public |
|
440
|
|
|
*/ |
|
441
|
|
|
function timestamp_to_iso8601($timestamp,$utc=true){ |
|
442
|
|
|
$datestr = date('Y-m-d\TH:i:sO',$timestamp); |
|
443
|
|
|
if($utc){ |
|
444
|
|
|
$eregStr = |
|
445
|
|
|
'([0-9]{4})-'. // centuries & years CCYY- |
|
446
|
|
|
'([0-9]{2})-'. // months MM- |
|
447
|
|
|
'([0-9]{2})'. // days DD |
|
448
|
|
|
'T'. // separator T |
|
449
|
|
|
'([0-9]{2}):'. // hours hh: |
|
450
|
|
|
'([0-9]{2}):'. // minutes mm: |
|
451
|
|
|
'([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... |
|
452
|
|
|
'(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's |
|
453
|
|
|
|
|
454
|
|
|
if(ereg($eregStr,$datestr,$regs)){ |
|
455
|
|
|
return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); |
|
456
|
|
|
} |
|
457
|
|
|
return false; |
|
458
|
|
|
} else { |
|
459
|
|
|
return $datestr; |
|
460
|
|
|
} |
|
461
|
|
|
} |
|
462
|
|
|
|
|
463
|
|
|
/** |
|
464
|
|
|
* convert ISO 8601 compliant date string to unix timestamp |
|
465
|
|
|
* |
|
466
|
|
|
* @param string $datestr ISO 8601 compliant date string |
|
467
|
|
|
* @access public |
|
468
|
|
|
*/ |
|
469
|
|
|
function iso8601_to_timestamp($datestr){ |
|
470
|
|
|
$eregStr = |
|
471
|
|
|
'([0-9]{4})-'. // centuries & years CCYY- |
|
472
|
|
|
'([0-9]{2})-'. // months MM- |
|
473
|
|
|
'([0-9]{2})'. // days DD |
|
474
|
|
|
'T'. // separator T |
|
475
|
|
|
'([0-9]{2}):'. // hours hh: |
|
476
|
|
|
'([0-9]{2}):'. // minutes mm: |
|
477
|
|
|
'([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... |
|
478
|
|
|
'(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's |
|
479
|
|
|
if(ereg($eregStr,$datestr,$regs)){ |
|
480
|
|
|
// not utc |
|
481
|
|
|
if($regs[8] != 'Z'){ |
|
482
|
|
|
$op = substr($regs[8],0,1); |
|
483
|
|
|
$h = substr($regs[8],1,2); |
|
484
|
|
|
$m = substr($regs[8],strlen($regs[8])-2,2); |
|
485
|
|
|
if($op == '-'){ |
|
486
|
|
|
$regs[4] = $regs[4] + $h; |
|
487
|
|
|
$regs[5] = $regs[5] + $m; |
|
488
|
|
|
} elseif($op == '+'){ |
|
489
|
|
|
$regs[4] = $regs[4] - $h; |
|
490
|
|
|
$regs[5] = $regs[5] - $m; |
|
491
|
|
|
} |
|
492
|
|
|
} |
|
493
|
|
|
return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); |
|
494
|
|
|
} else { |
|
495
|
|
|
return false; |
|
496
|
|
|
} |
|
497
|
|
|
} |
|
498
|
|
|
|
|
499
|
|
|
?><?php |
|
500
|
|
|
|
|
501
|
|
|
/** |
|
502
|
|
|
* soap_fault class, allows for creation of faults |
|
503
|
|
|
* mainly used for returning faults from deployed functions |
|
504
|
|
|
* in a server instance. |
|
505
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
506
|
|
|
* @version v 0.6.3 |
|
507
|
|
|
* @access public |
|
508
|
|
|
*/ |
|
509
|
|
|
class soap_fault extends nusoap_base { |
|
510
|
|
|
|
|
511
|
|
|
var $faultcode; |
|
512
|
|
|
var $faultactor; |
|
513
|
|
|
var $faultstring; |
|
514
|
|
|
var $faultdetail; |
|
515
|
|
|
|
|
516
|
|
|
/** |
|
517
|
|
|
* constructor |
|
518
|
|
|
* |
|
519
|
|
|
* @param string $faultcode (client | server) |
|
520
|
|
|
* @param string $faultactor only used when msg routed between multiple actors |
|
521
|
|
|
* @param string $faultstring human readable error message |
|
522
|
|
|
* @param string $faultdetail |
|
523
|
|
|
*/ |
|
524
|
|
|
function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ |
|
525
|
|
|
$this->faultcode = $faultcode; |
|
526
|
|
|
$this->faultactor = $faultactor; |
|
527
|
|
|
$this->faultstring = $faultstring; |
|
528
|
|
|
$this->faultdetail = $faultdetail; |
|
529
|
|
|
} |
|
530
|
|
|
|
|
531
|
|
|
/** |
|
532
|
|
|
* serialize a fault |
|
533
|
|
|
* |
|
534
|
|
|
* @access public |
|
535
|
|
|
*/ |
|
536
|
|
|
function serialize(){ |
|
537
|
|
|
$ns_string = ''; |
|
538
|
|
|
foreach($this->namespaces as $k => $v){ |
|
539
|
|
|
$ns_string .= "\n xmlns:$k=\"$v\""; |
|
540
|
|
|
} |
|
541
|
|
|
$return_msg = |
|
542
|
|
|
'<?xml version="1.0"?'.">\n". |
|
543
|
|
|
'<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". |
|
544
|
|
|
'<SOAP-ENV:Body>'. |
|
545
|
|
|
'<SOAP-ENV:Fault>'. |
|
546
|
|
|
'<faultcode>'.$this->faultcode.'</faultcode>'. |
|
547
|
|
|
'<faultactor>'.$this->faultactor.'</faultactor>'. |
|
548
|
|
|
'<faultstring>'.$this->faultstring.'</faultstring>'. |
|
549
|
|
|
'<detail>'.$this->serialize_val($this->faultdetail).'</detail>'. |
|
550
|
|
|
'</SOAP-ENV:Fault>'. |
|
551
|
|
|
'</SOAP-ENV:Body>'. |
|
552
|
|
|
'</SOAP-ENV:Envelope>'; |
|
553
|
|
|
return $return_msg; |
|
554
|
|
|
} |
|
555
|
|
|
} |
|
556
|
|
|
|
|
557
|
|
|
?><?php |
|
558
|
|
|
|
|
559
|
|
|
/** |
|
560
|
|
|
* parses an XML Schema, allows access to it's data, other utility methods |
|
561
|
|
|
* no validation... yet. |
|
562
|
|
|
* very experimental and limited. As is discussed on XML-DEV, I'm one of the people |
|
563
|
|
|
* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty |
|
564
|
|
|
* tutorials I refer to :) |
|
565
|
|
|
* |
|
566
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
567
|
|
|
* @version v 0.6.3 |
|
568
|
|
|
* @access public |
|
569
|
|
|
*/ |
|
570
|
|
|
class XMLSchema extends nusoap_base { |
|
571
|
|
|
|
|
572
|
|
|
// files |
|
573
|
|
|
var $schema = ''; |
|
574
|
|
|
var $xml = ''; |
|
575
|
|
|
// define internal arrays of bindings, ports, operations, messages, etc. |
|
576
|
|
|
var $complexTypes = array(); |
|
577
|
|
|
// target namespace |
|
578
|
|
|
var $schemaTargetNamespace = ''; |
|
579
|
|
|
// parser vars |
|
580
|
|
|
var $parser; |
|
581
|
|
|
var $position; |
|
582
|
|
|
var $depth = 0; |
|
583
|
|
|
var $depth_array = array(); |
|
584
|
|
|
|
|
585
|
|
|
/** |
|
586
|
|
|
* constructor |
|
587
|
|
|
* |
|
588
|
|
|
* @param string $schema schema document URI |
|
589
|
|
|
* @param string $xml xml document URI |
|
590
|
|
|
* @access public |
|
591
|
|
|
*/ |
|
592
|
|
|
function XMLSchema($schema='',$xml=''){ |
|
593
|
|
|
|
|
594
|
|
|
$this->debug('xmlschema class instantiated, inside constructor'); |
|
595
|
|
|
// files |
|
596
|
|
|
$this->schema = $schema; |
|
597
|
|
|
$this->xml = $xml; |
|
598
|
|
|
|
|
599
|
|
|
// parse schema file |
|
600
|
|
|
if($schema != ''){ |
|
601
|
|
|
$this->debug('initial schema file: '.$schema); |
|
602
|
|
|
$this->parseFile($schema); |
|
|
|
|
|
|
603
|
|
|
} |
|
604
|
|
|
|
|
605
|
|
|
// parse xml file |
|
606
|
|
|
if($xml != ''){ |
|
607
|
|
|
$this->debug('initial xml file: '.$xml); |
|
608
|
|
|
$this->parseFile($xml); |
|
|
|
|
|
|
609
|
|
|
} |
|
610
|
|
|
|
|
611
|
|
|
} |
|
612
|
|
|
|
|
613
|
|
|
/** |
|
614
|
|
|
* parse an XML file |
|
615
|
|
|
* |
|
616
|
|
|
* @param string $xml, path/URL to XML file |
|
|
|
|
|
|
617
|
|
|
* @param string $type, (schema | xml) |
|
|
|
|
|
|
618
|
|
|
* @return boolean |
|
619
|
|
|
* @access public |
|
620
|
|
|
*/ |
|
621
|
|
|
function parseFile($xml,$type){ |
|
622
|
|
|
// parse xml file |
|
623
|
|
|
if($xml != ""){ |
|
624
|
|
|
$this->debug('parsing $xml'); |
|
625
|
|
|
$xmlStr = @join("",@file($xml)); |
|
626
|
|
|
if($xmlStr == ""){ |
|
627
|
|
|
$this->setError('No file at the specified URL: '.$xml); |
|
628
|
|
|
return false; |
|
629
|
|
|
} else { |
|
630
|
|
|
$this->parseString($xmlStr,$type); |
|
631
|
|
|
return true; |
|
632
|
|
|
} |
|
633
|
|
|
} |
|
634
|
|
|
return false; |
|
635
|
|
|
} |
|
636
|
|
|
|
|
637
|
|
|
/** |
|
638
|
|
|
* parse an XML string |
|
639
|
|
|
* |
|
640
|
|
|
* @param string $xml path or URL |
|
641
|
|
|
* @param string $type, (schema|xml) |
|
|
|
|
|
|
642
|
|
|
* @access private |
|
643
|
|
|
*/ |
|
644
|
|
|
function parseString($xml,$type){ |
|
645
|
|
|
// parse xml string |
|
646
|
|
|
if($xml != ""){ |
|
647
|
|
|
|
|
648
|
|
|
// Create an XML parser. |
|
649
|
|
|
$this->parser = xml_parser_create(); |
|
650
|
|
|
// Set the options for parsing the XML data. |
|
651
|
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
|
652
|
|
|
|
|
653
|
|
|
// Set the object for the parser. |
|
654
|
|
|
xml_set_object($this->parser, $this); |
|
655
|
|
|
|
|
656
|
|
|
// Set the element handlers for the parser. |
|
657
|
|
|
if($type == "schema"){ |
|
658
|
|
|
xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); |
|
659
|
|
|
xml_set_character_data_handler($this->parser,'schemaCharacterData'); |
|
660
|
|
|
} elseif($type == "xml"){ |
|
661
|
|
|
xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); |
|
662
|
|
|
xml_set_character_data_handler($this->parser,'xmlCharacterData'); |
|
663
|
|
|
} |
|
664
|
|
|
|
|
665
|
|
|
// Parse the XML file. |
|
666
|
|
|
if(!xml_parse($this->parser,$xml,true)){ |
|
667
|
|
|
// Display an error message. |
|
668
|
|
|
$errstr = sprintf('XML error on line %d: %s', |
|
669
|
|
|
xml_get_current_line_number($this->parser), |
|
670
|
|
|
xml_error_string(xml_get_error_code($this->parser)) |
|
671
|
|
|
); |
|
672
|
|
|
$this->debug('XML parse error: '.$errstr); |
|
673
|
|
|
$this->setError('Parser error: '.$errstr); |
|
674
|
|
|
} |
|
675
|
|
|
|
|
676
|
|
|
xml_parser_free($this->parser); |
|
677
|
|
|
} else{ |
|
678
|
|
|
$this->debug('no xml passed to parseString()!!'); |
|
679
|
|
|
$this->setError('no xml passed to parseString()!!'); |
|
680
|
|
|
} |
|
681
|
|
|
} |
|
682
|
|
|
|
|
683
|
|
|
/** |
|
684
|
|
|
* start-element handler |
|
685
|
|
|
* |
|
686
|
|
|
* @param string $parser XML parser object |
|
687
|
|
|
* @param string $name element name |
|
688
|
|
|
* @param string $attrs associative array of attributes |
|
689
|
|
|
* @access private |
|
690
|
|
|
*/ |
|
691
|
|
|
function schemaStartElement($parser, $name, $attrs) { |
|
692
|
|
|
|
|
693
|
|
|
// position in the total number of elements, starting from 0 |
|
694
|
|
|
$pos = $this->position++; |
|
695
|
|
|
$depth = $this->depth++; |
|
696
|
|
|
// set self as current value for this depth |
|
697
|
|
|
$this->depth_array[$depth] = $pos; |
|
698
|
|
|
|
|
699
|
|
|
// get element prefix |
|
700
|
|
|
if($prefix = $this->getPrefix($name)){ |
|
701
|
|
|
// get unqualified name |
|
702
|
|
|
$name = $this->getLocalPart($name); |
|
703
|
|
|
} else { |
|
704
|
|
|
$prefix = ''; |
|
705
|
|
|
} |
|
706
|
|
|
|
|
707
|
|
|
// loop thru attributes, expanding, and registering namespace declarations |
|
708
|
|
|
if(count($attrs) > 0){ |
|
709
|
|
|
foreach($attrs as $k => $v){ |
|
|
|
|
|
|
710
|
|
|
// if ns declarations, add to class level array of valid namespaces |
|
711
|
|
|
if(ereg("^xmlns",$k)){ |
|
712
|
|
|
//$this->xdebug("$k: $v"); |
|
713
|
|
|
//$this->xdebug('ns_prefix: '.$this->getPrefix($k)); |
|
714
|
|
|
if($ns_prefix = substr(strrchr($k,':'),1)){ |
|
715
|
|
|
$this->namespaces[$ns_prefix] = $v; |
|
716
|
|
|
} else { |
|
717
|
|
|
$this->namespaces['ns'.(count($this->namespaces)+1)] = $v; |
|
718
|
|
|
} |
|
719
|
|
|
if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){ |
|
720
|
|
|
$this->XMLSchemaVersion = $v; |
|
721
|
|
|
$this->namespaces['xsi'] = $v.'-instance'; |
|
722
|
|
|
} |
|
723
|
|
|
} |
|
724
|
|
|
} |
|
725
|
|
|
foreach($attrs as $k => $v) { |
|
|
|
|
|
|
726
|
|
|
// expand each attribute |
|
727
|
|
|
$k = strpos($k,':') ? $this->expandQname($k) : $k; |
|
728
|
|
|
$v = strpos($v,':') ? $this->expandQname($v) : $v; |
|
729
|
|
|
$eAttrs[$k] = $v; |
|
730
|
|
|
} |
|
731
|
|
|
$attrs = $eAttrs; |
|
732
|
|
|
} else { |
|
733
|
|
|
$attrs = array(); |
|
734
|
|
|
} |
|
735
|
|
|
// find status, register data |
|
736
|
|
|
switch($name) { |
|
737
|
|
|
case ('all'|'choice'|'sequence'): |
|
738
|
|
|
//$this->complexTypes[$this->currentComplexType]['compositor'] = 'all'; |
|
739
|
|
|
$this->complexTypes[$this->currentComplexType]['compositor'] = $name; |
|
740
|
|
|
if($name == 'all') { |
|
741
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
|
742
|
|
|
} |
|
743
|
|
|
break; |
|
744
|
|
|
case 'attribute': |
|
745
|
|
|
//$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); |
|
746
|
|
|
if(isset($attrs['name'])){ |
|
747
|
|
|
$this->attributes[$attrs['name']] = $attrs; |
|
748
|
|
|
$aname = $attrs['name']; |
|
749
|
|
|
} elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ |
|
750
|
|
|
$aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; |
|
751
|
|
|
} elseif(isset($attrs['ref'])){ |
|
752
|
|
|
$aname = $attrs['ref']; |
|
753
|
|
|
$this->attributes[$attrs['ref']] = $attrs; |
|
754
|
|
|
} |
|
755
|
|
|
|
|
756
|
|
|
if(isset($this->currentComplexType)){ |
|
757
|
|
|
$this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; |
|
758
|
|
|
} elseif(isset($this->currentElement)){ |
|
759
|
|
|
$this->elements[$this->currentElement]['attrs'][$aname] = $attrs; |
|
760
|
|
|
} |
|
761
|
|
|
// arrayType attribute |
|
762
|
|
|
if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ |
|
763
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
|
764
|
|
|
$prefix = $this->getPrefix($aname); |
|
765
|
|
|
if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ |
|
766
|
|
|
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; |
|
767
|
|
|
} else { |
|
768
|
|
|
$v = ''; |
|
769
|
|
|
} |
|
770
|
|
|
if(strpos($v,'[,]')){ |
|
771
|
|
|
$this->complexTypes[$this->currentComplexType]['multidimensional'] = true; |
|
772
|
|
|
} |
|
773
|
|
|
$v = substr($v,0,strpos($v,'[')); // clip the [] |
|
774
|
|
|
if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ |
|
775
|
|
|
$v = $this->XMLSchemaVersion.':'.$v; |
|
776
|
|
|
} |
|
777
|
|
|
$this->complexTypes[$this->currentComplexType]['arrayType'] = $v; |
|
778
|
|
|
} |
|
779
|
|
|
break; |
|
780
|
|
|
case 'complexType': |
|
781
|
|
|
if(isset($attrs['name'])){ |
|
782
|
|
|
$this->currentElement = false; |
|
783
|
|
|
$this->currentComplexType = $attrs['name']; |
|
784
|
|
|
$this->complexTypes[$this->currentComplexType] = $attrs; |
|
785
|
|
|
$this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; |
|
786
|
|
|
if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ |
|
787
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
|
788
|
|
|
} else { |
|
789
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
|
790
|
|
|
} |
|
791
|
|
|
$this->xdebug('processing complexType '.$attrs['name']); |
|
792
|
|
|
} |
|
793
|
|
|
break; |
|
794
|
|
|
case 'element': |
|
795
|
|
|
if(isset($attrs['type'])){ |
|
796
|
|
|
$this->xdebug("processing element ".$attrs['name']); |
|
797
|
|
|
$this->currentElement = $attrs['name']; |
|
798
|
|
|
$this->elements[ $attrs['name'] ] = $attrs; |
|
799
|
|
|
$this->elements[ $attrs['name'] ]['typeClass'] = 'element'; |
|
800
|
|
|
$ename = $attrs['name']; |
|
801
|
|
|
} elseif(isset($attrs['ref'])){ |
|
802
|
|
|
$ename = $attrs['ref']; |
|
803
|
|
|
} else { |
|
804
|
|
|
$this->xdebug('adding complexType '.$attrs['name']); |
|
805
|
|
|
$this->currentComplexType = $attrs['name']; |
|
806
|
|
|
$this->complexTypes[ $attrs['name'] ] = $attrs; |
|
807
|
|
|
$this->complexTypes[ $attrs['name'] ]['element'] = 1; |
|
808
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
|
809
|
|
|
} |
|
810
|
|
|
if(isset($ename) && $this->currentComplexType){ |
|
811
|
|
|
$this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; |
|
812
|
|
|
} |
|
813
|
|
|
break; |
|
814
|
|
|
case 'restriction': |
|
815
|
|
|
$this->xdebug("in restriction for ct: $this->currentComplexType and ce: $this->currentElement"); |
|
816
|
|
|
if($this->currentElement){ |
|
817
|
|
|
$this->elements[$this->currentElement]['type'] = $attrs['base']; |
|
818
|
|
|
} elseif($this->currentComplexType){ |
|
819
|
|
|
$this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; |
|
820
|
|
|
if(strstr($attrs['base'],':') == ':Array'){ |
|
821
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
|
822
|
|
|
} |
|
823
|
|
|
} |
|
824
|
|
|
break; |
|
825
|
|
|
case 'schema': |
|
826
|
|
|
$this->schema = $attrs; |
|
827
|
|
|
$this->schema['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); |
|
828
|
|
|
break; |
|
829
|
|
|
case 'simpleType': |
|
830
|
|
|
$this->currentElement = $attrs['name']; |
|
831
|
|
|
$this->elements[ $attrs['name'] ] = $attrs; |
|
832
|
|
|
$this->elements[ $attrs['name'] ]['typeClass'] = 'element'; |
|
833
|
|
|
break; |
|
834
|
|
|
} |
|
835
|
|
|
} |
|
836
|
|
|
|
|
837
|
|
|
/** |
|
838
|
|
|
* end-element handler |
|
839
|
|
|
* |
|
840
|
|
|
* @param string $parser XML parser object |
|
841
|
|
|
* @param string $name element name |
|
842
|
|
|
* @access private |
|
843
|
|
|
*/ |
|
844
|
|
|
function schemaEndElement($parser, $name) { |
|
845
|
|
|
// position of current element is equal to the last value left in depth_array for my depth |
|
846
|
|
|
if(isset($this->depth_array[$this->depth])){ |
|
847
|
|
|
$pos = $this->depth_array[$this->depth]; |
|
848
|
|
|
} |
|
849
|
|
|
// bring depth down a notch |
|
850
|
|
|
$this->depth--; |
|
851
|
|
|
// move on... |
|
852
|
|
|
if($name == 'complexType'){ |
|
853
|
|
|
$this->currentComplexType = false; |
|
854
|
|
|
$this->currentElement = false; |
|
855
|
|
|
} |
|
856
|
|
|
if($name == 'element'){ |
|
857
|
|
|
$this->currentElement = false; |
|
858
|
|
|
} |
|
859
|
|
|
} |
|
860
|
|
|
|
|
861
|
|
|
/** |
|
862
|
|
|
* element content handler |
|
863
|
|
|
* |
|
864
|
|
|
* @param string $parser XML parser object |
|
865
|
|
|
* @param string $data element content |
|
866
|
|
|
* @access private |
|
867
|
|
|
*/ |
|
868
|
|
|
function schemaCharacterData($parser, $data){ |
|
869
|
|
|
$pos = $this->depth_array[$this->depth]; |
|
870
|
|
|
$this->message[$pos]['cdata'] .= $data; |
|
871
|
|
|
} |
|
872
|
|
|
|
|
873
|
|
|
/** |
|
874
|
|
|
* serialize the schema |
|
875
|
|
|
* |
|
876
|
|
|
* @access public |
|
877
|
|
|
*/ |
|
878
|
|
|
function serializeSchema(){ |
|
879
|
|
|
|
|
880
|
|
|
$schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); |
|
881
|
|
|
$xml = ''; |
|
882
|
|
|
// complex types |
|
883
|
|
|
foreach($this->complexTypes as $typeName => $attrs){ |
|
884
|
|
|
$contentStr = ''; |
|
885
|
|
|
// serialize child elements |
|
886
|
|
|
if(count($attrs['elements']) > 0){ |
|
887
|
|
|
foreach($attrs['elements'] as $element => $eParts){ |
|
888
|
|
|
if(isset($eParts['ref'])){ |
|
889
|
|
|
$contentStr .= "<element ref=\"$element\"/>"; |
|
890
|
|
|
} else { |
|
891
|
|
|
$contentStr .= "<element name=\"$element\" type=\"$eParts[type]\"/>"; |
|
892
|
|
|
} |
|
893
|
|
|
} |
|
894
|
|
|
} |
|
895
|
|
|
// attributes |
|
896
|
|
|
if(count($attrs['attrs']) >= 1){ |
|
897
|
|
|
foreach($attrs['attrs'] as $attr => $aParts){ |
|
898
|
|
|
$contentStr .= '<attribute ref="'.$aParts['ref'].'"'; |
|
899
|
|
|
if(isset($aParts['wsdl:arrayType'])){ |
|
900
|
|
|
$contentStr .= ' wsdl:arrayType="'.$aParts['wsdl:arrayType'].'"'; |
|
901
|
|
|
} |
|
902
|
|
|
$contentStr .= '/>'; |
|
903
|
|
|
} |
|
904
|
|
|
} |
|
905
|
|
|
// if restriction |
|
906
|
|
|
if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ |
|
907
|
|
|
$contentStr = "<$schemaPrefix:restriction base=\"".$attrs['restrictionBase']."\">".$contentStr."</$schemaPrefix:restriction>"; |
|
908
|
|
|
} |
|
909
|
|
|
// "all" compositor obviates complex/simple content |
|
910
|
|
|
if(isset($attrs['compositor']) && $attrs['compositor'] == 'all'){ |
|
911
|
|
|
$contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>"; |
|
912
|
|
|
} |
|
913
|
|
|
// complex or simple content |
|
914
|
|
|
elseif( count($attrs['elements']) > 0 || count($attrs['attrs']) > 0){ |
|
915
|
|
|
$contentStr = "<$schemaPrefix:complexContent>".$contentStr."</$schemaPrefix:complexContent>"; |
|
916
|
|
|
} |
|
917
|
|
|
// compositors |
|
918
|
|
|
if(isset($attrs['compositor']) && $attrs['compositor'] != '' && $attrs['compositor'] != 'all'){ |
|
919
|
|
|
$contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>"; |
|
920
|
|
|
} |
|
921
|
|
|
// finalize complex type |
|
922
|
|
|
if($contentStr != ''){ |
|
923
|
|
|
$contentStr = "<$schemaPrefix:complexType name=\"$typeName\">".$contentStr."</$schemaPrefix:complexType>"; |
|
924
|
|
|
} else { |
|
925
|
|
|
$contentStr = "<$schemaPrefix:complexType name=\"$typeName\"/>"; |
|
926
|
|
|
} |
|
927
|
|
|
$xml .= $contentStr; |
|
928
|
|
|
} |
|
929
|
|
|
// elements |
|
930
|
|
|
if(isset($this->elements) && count($this->elements) > 0){ |
|
931
|
|
|
foreach($this->elements as $element => $eParts){ |
|
932
|
|
|
$xml .= "<$schemaPrefix:element name=\"$element\" type=\"".$eParts['type']."\"/>"; |
|
933
|
|
|
} |
|
934
|
|
|
} |
|
935
|
|
|
// attributes |
|
936
|
|
|
if(isset($this->attributes) && count($this->attributes) > 0){ |
|
937
|
|
|
foreach($this->attributes as $attr => $aParts){ |
|
938
|
|
|
$xml .= "<$schemaPrefix:attribute name=\"$attr\" type=\"".$aParts['type']."\"/>"; |
|
939
|
|
|
} |
|
940
|
|
|
} |
|
941
|
|
|
// finish 'er up |
|
942
|
|
|
$xml = "<$schemaPrefix:schema xmlns=\"$this->XMLSchemaVersion\" targetNamespace=\"$this->schemaTargetNamespace\">".$xml."</$schemaPrefix:schema>"; |
|
943
|
|
|
return $xml; |
|
944
|
|
|
} |
|
945
|
|
|
|
|
946
|
|
|
/** |
|
947
|
|
|
* expands a qualified name |
|
948
|
|
|
* |
|
949
|
|
|
* @param string $string qname |
|
|
|
|
|
|
950
|
|
|
* @return string expanded qname |
|
951
|
|
|
* @access private |
|
952
|
|
|
*/ |
|
953
|
|
|
function expandQname($qname){ |
|
954
|
|
|
// get element prefix |
|
955
|
|
|
if(strpos($qname,':') && !ereg('^http://',$qname)){ |
|
956
|
|
|
// get unqualified name |
|
957
|
|
|
$name = substr(strstr($qname,':'),1); |
|
958
|
|
|
// get ns prefix |
|
959
|
|
|
$prefix = substr($qname,0,strpos($qname,':')); |
|
960
|
|
|
if(isset($this->namespaces[$prefix])){ |
|
961
|
|
|
return $this->namespaces[$prefix].':'.$name; |
|
962
|
|
|
} else { |
|
963
|
|
|
return $qname; |
|
964
|
|
|
} |
|
965
|
|
|
} else { |
|
966
|
|
|
return $qname; |
|
967
|
|
|
} |
|
968
|
|
|
} |
|
969
|
|
|
|
|
970
|
|
|
/** |
|
971
|
|
|
* adds debug data to the clas level debug string |
|
972
|
|
|
* |
|
973
|
|
|
* @param string $string debug data |
|
974
|
|
|
* @access private |
|
975
|
|
|
*/ |
|
976
|
|
|
function xdebug($string){ |
|
977
|
|
|
$this->debug(' xmlschema: '.$string); |
|
978
|
|
|
} |
|
979
|
|
|
|
|
980
|
|
|
/** |
|
981
|
|
|
* get the PHP type of a user defined type in the schema |
|
982
|
|
|
* PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays |
|
983
|
|
|
* returns false if no type exists, or not w/ the given namespace |
|
984
|
|
|
* else returns a string that is either a native php type, or 'struct' |
|
985
|
|
|
* |
|
986
|
|
|
* @param string $type, name of defined type |
|
|
|
|
|
|
987
|
|
|
* @param string $ns, namespace of type |
|
|
|
|
|
|
988
|
|
|
* @return mixed |
|
989
|
|
|
* @access public |
|
990
|
|
|
*/ |
|
991
|
|
|
function getPHPType($type,$ns){ |
|
992
|
|
|
global $typemap; |
|
993
|
|
|
if(isset($typemap[$ns][$type])){ |
|
994
|
|
|
//print "found type '$type' and ns $ns in typemap<br>"; |
|
995
|
|
|
return $typemap[$ns][$type]; |
|
996
|
|
|
} elseif(isset($this->complexTypes[$type])){ |
|
997
|
|
|
//print "getting type '$type' and ns $ns from complexTypes array<br>"; |
|
998
|
|
|
return $this->complexTypes[$type]['phpType']; |
|
999
|
|
|
} |
|
1000
|
|
|
return false; |
|
1001
|
|
|
} |
|
1002
|
|
|
|
|
1003
|
|
|
/** |
|
1004
|
|
|
* returns the local part of a prefixed string |
|
1005
|
|
|
* returns the original string, if not prefixed |
|
1006
|
|
|
* |
|
1007
|
|
|
* @param string |
|
1008
|
|
|
* @return string |
|
1009
|
|
|
* @access public |
|
1010
|
|
|
*/ |
|
1011
|
|
|
function getLocalPart($str){ |
|
1012
|
|
|
if($sstr = strrchr($str,':')){ |
|
1013
|
|
|
// get unqualified name |
|
1014
|
|
|
return substr( $sstr, 1 ); |
|
1015
|
|
|
} else { |
|
1016
|
|
|
return $str; |
|
1017
|
|
|
} |
|
1018
|
|
|
} |
|
1019
|
|
|
|
|
1020
|
|
|
/** |
|
1021
|
|
|
* returns the prefix part of a prefixed string |
|
1022
|
|
|
* returns false, if not prefixed |
|
1023
|
|
|
* |
|
1024
|
|
|
* @param string |
|
1025
|
|
|
* @return mixed |
|
1026
|
|
|
* @access public |
|
1027
|
|
|
*/ |
|
1028
|
|
|
function getPrefix($str){ |
|
1029
|
|
|
if($pos = strrpos($str,':')){ |
|
1030
|
|
|
// get prefix |
|
1031
|
|
|
return substr($str,0,$pos); |
|
1032
|
|
|
} |
|
1033
|
|
|
return false; |
|
1034
|
|
|
} |
|
1035
|
|
|
|
|
1036
|
|
|
/** |
|
1037
|
|
|
* pass it a prefix, it returns a namespace |
|
1038
|
|
|
* returns false if no namespace registered with the given prefix |
|
1039
|
|
|
* |
|
1040
|
|
|
* @param string |
|
1041
|
|
|
* @return mixed |
|
1042
|
|
|
* @access public |
|
1043
|
|
|
*/ |
|
1044
|
|
|
function getNamespaceFromPrefix($prefix){ |
|
1045
|
|
|
if(isset($this->namespaces[$prefix])){ |
|
1046
|
|
|
return $this->namespaces[$prefix]; |
|
1047
|
|
|
} |
|
1048
|
|
|
//$this->setError("No namespace registered for prefix '$prefix'"); |
|
1049
|
|
|
return false; |
|
1050
|
|
|
} |
|
1051
|
|
|
|
|
1052
|
|
|
/** |
|
1053
|
|
|
* returns the prefix for a given namespace (or prefix) |
|
1054
|
|
|
* or false if no prefixes registered for the given namespace |
|
1055
|
|
|
* |
|
1056
|
|
|
* @param string |
|
1057
|
|
|
* @return mixed |
|
1058
|
|
|
* @access public |
|
1059
|
|
|
*/ |
|
1060
|
|
|
function getPrefixFromNamespace($ns){ |
|
1061
|
|
|
foreach($this->namespaces as $p => $n){ |
|
1062
|
|
|
if($ns == $n || $ns == $p){ |
|
1063
|
|
|
$this->usedNamespaces[$p] = $n; |
|
1064
|
|
|
return $p; |
|
1065
|
|
|
} |
|
1066
|
|
|
} |
|
1067
|
|
|
return false; |
|
1068
|
|
|
} |
|
1069
|
|
|
|
|
1070
|
|
|
/** |
|
1071
|
|
|
* returns an array of information about a given type |
|
1072
|
|
|
* returns false if no type exists by the given name |
|
1073
|
|
|
* |
|
1074
|
|
|
* typeDef = array( |
|
1075
|
|
|
* 'elements' => array(), // refs to elements array |
|
1076
|
|
|
* 'restrictionBase' => '', |
|
1077
|
|
|
* 'phpType' => '', |
|
1078
|
|
|
* 'order' => '(sequence|all)', |
|
1079
|
|
|
* 'attrs' => array() // refs to attributes array |
|
1080
|
|
|
* ) |
|
1081
|
|
|
* |
|
1082
|
|
|
* @param string |
|
1083
|
|
|
* @return mixed |
|
1084
|
|
|
* @access public |
|
1085
|
|
|
*/ |
|
1086
|
|
|
function getTypeDef($type){ |
|
1087
|
|
|
if(isset($this->complexTypes[$type])){ |
|
1088
|
|
|
return $this->complexTypes[$type]; |
|
1089
|
|
|
} elseif(isset($this->elements[$type])){ |
|
1090
|
|
|
return $this->elements[$type]; |
|
1091
|
|
|
} elseif(isset($this->attributes[$type])){ |
|
1092
|
|
|
return $this->attributes[$type]; |
|
1093
|
|
|
} |
|
1094
|
|
|
return false; |
|
1095
|
|
|
} |
|
1096
|
|
|
|
|
1097
|
|
|
/** |
|
1098
|
|
|
* returns a sample serialization of a given type, or false if no type by the given name |
|
1099
|
|
|
* |
|
1100
|
|
|
* @param string $type, name of type |
|
|
|
|
|
|
1101
|
|
|
* @return mixed |
|
1102
|
|
|
* @access public |
|
1103
|
|
|
*/ |
|
1104
|
|
|
function serializeTypeDef($type){ |
|
1105
|
|
|
//print "in sTD() for type $type<br>"; |
|
1106
|
|
|
if($typeDef = $this->getTypeDef($type)){ |
|
1107
|
|
|
$str .= '<'.$type; |
|
|
|
|
|
|
1108
|
|
|
if(is_array($typeDef['attrs'])){ |
|
1109
|
|
|
foreach($attrs as $attName => $data){ |
|
|
|
|
|
|
1110
|
|
|
$str .= " $attName=\"{type = ".$data['type']."}\""; |
|
1111
|
|
|
} |
|
1112
|
|
|
} |
|
1113
|
|
|
$str .= " xmlns=\"".$this->schema['targetNamespace']."\""; |
|
1114
|
|
|
if(count($typeDef['elements']) > 0){ |
|
1115
|
|
|
$str .= ">"; |
|
1116
|
|
|
foreach($typeDef['elements'] as $element => $eData){ |
|
1117
|
|
|
$str .= $this->serializeTypeDef($element); |
|
1118
|
|
|
} |
|
1119
|
|
|
$str .= "</$type>"; |
|
1120
|
|
|
} elseif($typeDef['typeClass'] == 'element') { |
|
1121
|
|
|
$str .= "></$type>"; |
|
1122
|
|
|
} else { |
|
1123
|
|
|
$str .= "/>"; |
|
1124
|
|
|
} |
|
1125
|
|
|
return $str; |
|
1126
|
|
|
} |
|
1127
|
|
|
return false; |
|
1128
|
|
|
} |
|
1129
|
|
|
|
|
1130
|
|
|
/** |
|
1131
|
|
|
* returns HTML form elements that allow a user |
|
1132
|
|
|
* to enter values for creating an instance of the given type. |
|
1133
|
|
|
* |
|
1134
|
|
|
* @param string $name, name for type instance |
|
|
|
|
|
|
1135
|
|
|
* @param string $type, name of type |
|
|
|
|
|
|
1136
|
|
|
* @return string |
|
1137
|
|
|
* @access public |
|
1138
|
|
|
*/ |
|
1139
|
|
|
function typeToForm($name,$type){ |
|
1140
|
|
|
// get typedef |
|
1141
|
|
|
if($typeDef = $this->getTypeDef($type)){ |
|
1142
|
|
|
// if struct |
|
1143
|
|
|
if($typeDef['phpType'] == 'struct'){ |
|
1144
|
|
|
$buffer .= '<table>'; |
|
|
|
|
|
|
1145
|
|
|
foreach($typeDef['elements'] as $child => $childDef){ |
|
1146
|
|
|
$buffer .= "<tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>". |
|
1147
|
|
|
"<td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; |
|
1148
|
|
|
} |
|
1149
|
|
|
$buffer .= '</table>'; |
|
1150
|
|
|
// if array |
|
1151
|
|
|
} elseif($typeDef['phpType'] == 'array'){ |
|
1152
|
|
|
$buffer .= '<table>'; |
|
1153
|
|
|
for($i=0;$i < 3; $i++){ |
|
1154
|
|
|
$buffer .= "<tr><td align='right'>array item (type: $typeDef[arrayType]):</td>". |
|
1155
|
|
|
"<td><input type='text' name='parameters[".$name."][]'></td></tr>"; |
|
1156
|
|
|
} |
|
1157
|
|
|
$buffer .= '</table>'; |
|
1158
|
|
|
// if scalar |
|
1159
|
|
|
} else { |
|
1160
|
|
|
$buffer .= "<input type='text' name='parameters[$name]'>"; |
|
1161
|
|
|
} |
|
1162
|
|
|
} else { |
|
1163
|
|
|
$buffer .= "<input type='text' name='parameters[$name]'>"; |
|
1164
|
|
|
} |
|
1165
|
|
|
return $buffer; |
|
1166
|
|
|
} |
|
1167
|
|
|
|
|
1168
|
|
|
/** |
|
1169
|
|
|
* adds an XML Schema complex type to the WSDL types |
|
1170
|
|
|
* |
|
1171
|
|
|
* example: array |
|
1172
|
|
|
* |
|
1173
|
|
|
* addType( |
|
1174
|
|
|
* 'ArrayOfstring', |
|
1175
|
|
|
* 'complexType', |
|
1176
|
|
|
* 'array', |
|
1177
|
|
|
* '', |
|
1178
|
|
|
* 'SOAP-ENC:Array', |
|
1179
|
|
|
* array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), |
|
1180
|
|
|
* 'xsd:string' |
|
1181
|
|
|
* ); |
|
1182
|
|
|
* |
|
1183
|
|
|
* example: PHP associative array ( SOAP Struct ) |
|
1184
|
|
|
* |
|
1185
|
|
|
* addType( |
|
1186
|
|
|
* 'SOAPStruct', |
|
1187
|
|
|
* 'complexType', |
|
1188
|
|
|
* 'struct', |
|
1189
|
|
|
* 'all', |
|
1190
|
|
|
* array('myVar'=> array('name'=>'myVar','type'=>'string') |
|
1191
|
|
|
* ); |
|
1192
|
|
|
* |
|
1193
|
|
|
* @param name |
|
1194
|
|
|
* @param typeClass (complexType|simpleType|attribute) |
|
1195
|
|
|
* @param phpType: currently supported are array and struct (php assoc array) |
|
1196
|
|
|
* @param compositor (all|sequence|choice) |
|
1197
|
|
|
* @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) |
|
1198
|
|
|
* @param elements = array ( name = array(name=>'',type=>'') ) |
|
1199
|
|
|
* @param attrs = array( |
|
1200
|
|
|
* array( |
|
1201
|
|
|
* 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", |
|
1202
|
|
|
* "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" |
|
1203
|
|
|
* ) |
|
1204
|
|
|
* ) |
|
1205
|
|
|
* @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) |
|
1206
|
|
|
* |
|
1207
|
|
|
*/ |
|
1208
|
|
|
function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ |
|
1209
|
|
|
$this->complexTypes[$name] = array( |
|
1210
|
|
|
'name' => $name, |
|
1211
|
|
|
'typeClass' => $typeClass, |
|
1212
|
|
|
'phpType' => $phpType, |
|
1213
|
|
|
'compositor'=> $compositor, |
|
1214
|
|
|
'restrictionBase' => $restrictionBase, |
|
1215
|
|
|
'elements' => $elements, |
|
1216
|
|
|
'attrs' => $attrs, |
|
1217
|
|
|
'arrayType' => $arrayType |
|
1218
|
|
|
); |
|
1219
|
|
|
} |
|
1220
|
|
|
} |
|
1221
|
|
|
|
|
1222
|
|
|
?><?php |
|
1223
|
|
|
|
|
1224
|
|
|
/** |
|
1225
|
|
|
* for creating serializable abstractions of native PHP types |
|
1226
|
|
|
* NOTE: this is only really used when WSDL is not available. |
|
1227
|
|
|
* |
|
1228
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
1229
|
|
|
* @version v 0.6.3 |
|
1230
|
|
|
* @access public |
|
1231
|
|
|
*/ |
|
1232
|
|
|
class soapval extends nusoap_base { |
|
1233
|
|
|
/** |
|
1234
|
|
|
* constructor |
|
1235
|
|
|
* |
|
1236
|
|
|
* @param string $name optional name |
|
1237
|
|
|
* @param string $type optional type name |
|
1238
|
|
|
* @param mixed $value optional value |
|
1239
|
|
|
* @param string $namespace optional namespace of value |
|
|
|
|
|
|
1240
|
|
|
* @param string $type_namespace optional namespace of type |
|
|
|
|
|
|
1241
|
|
|
* @param array $attributes associative array of attributes to add to element serialization |
|
1242
|
|
|
* @access public |
|
1243
|
|
|
*/ |
|
1244
|
|
|
function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { |
|
1245
|
|
|
$this->name = $name; |
|
1246
|
|
|
$this->value = $value; |
|
1247
|
|
|
$this->type = $type; |
|
1248
|
|
|
$this->element_ns = $element_ns; |
|
1249
|
|
|
$this->type_ns = $type_ns; |
|
1250
|
|
|
$this->attributes = $attributes; |
|
1251
|
|
|
} |
|
1252
|
|
|
|
|
1253
|
|
|
/** |
|
1254
|
|
|
* return serialized value |
|
1255
|
|
|
* |
|
1256
|
|
|
* @return string XML data |
|
1257
|
|
|
* @access private |
|
1258
|
|
|
*/ |
|
1259
|
|
|
function serialize($use='encoded') { |
|
1260
|
|
|
return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use); |
|
1261
|
|
|
} |
|
1262
|
|
|
|
|
1263
|
|
|
/** |
|
1264
|
|
|
* decodes a soapval object into a PHP native type |
|
1265
|
|
|
* |
|
1266
|
|
|
* @param object $soapval optional SOAPx4 soapval object, else uses self |
|
|
|
|
|
|
1267
|
|
|
* @return mixed |
|
1268
|
|
|
* @access public |
|
1269
|
|
|
*/ |
|
1270
|
|
|
function decode(){ |
|
1271
|
|
|
return $this->value; |
|
1272
|
|
|
} |
|
1273
|
|
|
} |
|
1274
|
|
|
|
|
1275
|
|
|
?><?php |
|
1276
|
|
|
|
|
1277
|
|
|
/** |
|
1278
|
|
|
* transport class for sending/receiving data via HTTP and HTTPS |
|
1279
|
|
|
* NOTE: PHP must be compiled with the CURL extension for HTTPS support |
|
1280
|
|
|
* |
|
1281
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
1282
|
|
|
* @version v 0.6.3 |
|
1283
|
|
|
* @access public |
|
1284
|
|
|
*/ |
|
1285
|
|
|
class soap_transport_http extends nusoap_base { |
|
1286
|
|
|
|
|
1287
|
|
|
var $username = ''; |
|
1288
|
|
|
var $password = ''; |
|
1289
|
|
|
var $url = ''; |
|
1290
|
|
|
var $proxyhost = ''; |
|
1291
|
|
|
var $proxyport = ''; |
|
1292
|
|
|
var $scheme = ''; |
|
1293
|
|
|
var $request_method = 'POST'; |
|
1294
|
|
|
var $protocol_version = '1.0'; |
|
1295
|
|
|
var $encoding = ''; |
|
1296
|
|
|
var $outgoing_headers = array(); |
|
1297
|
|
|
var $incoming_headers = array(); |
|
1298
|
|
|
var $outgoing_payload = ''; |
|
1299
|
|
|
var $incoming_payload = ''; |
|
1300
|
|
|
var $useSOAPAction = true; |
|
1301
|
|
|
|
|
1302
|
|
|
/** |
|
1303
|
|
|
* constructor |
|
1304
|
|
|
*/ |
|
1305
|
|
|
function soap_transport_http($url){ |
|
1306
|
|
|
$this->url = $url; |
|
1307
|
|
|
$u = parse_url($url); |
|
1308
|
|
|
foreach($u as $k => $v){ |
|
|
|
|
|
|
1309
|
|
|
$this->debug("$k = $v"); |
|
1310
|
|
|
$this->$k = $v; |
|
1311
|
|
|
} |
|
1312
|
|
|
if(isset($u['query']) && $u['query'] != ''){ |
|
1313
|
|
|
$this->path .= '?' . $u['query']; |
|
1314
|
|
|
} |
|
1315
|
|
|
if(!isset($u['port']) && $u['scheme'] == 'http'){ |
|
1316
|
|
|
$this->port = 80; |
|
1317
|
|
|
} |
|
1318
|
|
|
} |
|
1319
|
|
|
|
|
1320
|
|
|
function connect($timeout){ |
|
1321
|
|
|
|
|
1322
|
|
|
// proxy |
|
1323
|
|
|
if($this->proxyhost != '' && $this->proxyport != ''){ |
|
1324
|
|
|
$host = $this->proxyhost; |
|
1325
|
|
|
$port = $this->proxyport; |
|
1326
|
|
|
$this->debug("using http proxy: $host, $port"); |
|
1327
|
|
|
} else { |
|
1328
|
|
|
$host = $this->host; |
|
1329
|
|
|
$port = $this->port; |
|
1330
|
|
|
} |
|
1331
|
|
|
// ssl |
|
1332
|
|
|
if($this->scheme == 'https'){ |
|
1333
|
|
|
$host = 'ssl://'.$host; |
|
1334
|
|
|
$port = 443; |
|
1335
|
|
|
} |
|
1336
|
|
|
|
|
1337
|
|
|
$this->debug("connection params: $host, $port"); |
|
1338
|
|
|
// timeout |
|
1339
|
|
|
if($timeout > 0){ |
|
1340
|
|
|
$fp = fsockopen($host, $port, $this->errno, $this->error_str, $timeout); |
|
1341
|
|
|
} else { |
|
1342
|
|
|
$fp = fsockopen($host, $port, $this->errno, $this->error_str); |
|
1343
|
|
|
} |
|
1344
|
|
|
|
|
1345
|
|
|
// test pointer |
|
1346
|
|
|
if(!$fp) { |
|
1347
|
|
|
$this->debug('Couldn\'t open socket connection to server '.$this->url.', Error: '.$this->error_str); |
|
1348
|
|
|
$this->setError('Couldn\'t open socket connection to server: '.$this->url.', Error: '.$this->error_str); |
|
1349
|
|
|
return false; |
|
1350
|
|
|
} |
|
1351
|
|
|
return $fp; |
|
1352
|
|
|
} |
|
1353
|
|
|
|
|
1354
|
|
|
/** |
|
1355
|
|
|
* send the SOAP message via HTTP |
|
1356
|
|
|
* |
|
1357
|
|
|
* @param string $data message data |
|
1358
|
|
|
* @param integer $timeout set timeout in seconds |
|
1359
|
|
|
* @return string data |
|
1360
|
|
|
* @access public |
|
1361
|
|
|
*/ |
|
1362
|
|
|
function send($data, $timeout=0) { |
|
1363
|
|
|
$this->debug('entered send() with data of length: '.strlen($data)); |
|
1364
|
|
|
// get connnection |
|
1365
|
|
|
if(!$fp = $this->connect($timeout)){ |
|
1366
|
|
|
return false; |
|
1367
|
|
|
} |
|
1368
|
|
|
$this->debug('socket connected'); |
|
1369
|
|
|
|
|
1370
|
|
|
// start building outgoing payload: |
|
1371
|
|
|
// swap url for path if going through a proxy |
|
1372
|
|
|
if($this->proxyhost != '' && $this->proxyport != ''){ |
|
1373
|
|
|
$this->outgoing_payload = "$this->request_method $this->url ".strtoupper($this->scheme)."/$this->protocol_version\r\n"; |
|
1374
|
|
|
} else { |
|
1375
|
|
|
$this->outgoing_payload = "$this->request_method $this->path ".strtoupper($this->scheme)."/$this->protocol_version\r\n"; |
|
1376
|
|
|
} |
|
1377
|
|
|
// make payload |
|
1378
|
|
|
$this->outgoing_payload .= |
|
1379
|
|
|
"User-Agent: $this->title/$this->version\r\n". |
|
1380
|
|
|
"Host: ".$this->host."\r\n"; |
|
1381
|
|
|
// http auth |
|
1382
|
|
|
$credentials = ''; |
|
1383
|
|
|
if($this->username != '') { |
|
1384
|
|
|
$this->debug('setting http auth credentials'); |
|
1385
|
|
|
$this->outgoing_payload .= 'Authorization: Basic '.base64_encode("$this->username:$this->password")."\r\n"; |
|
1386
|
|
|
} |
|
1387
|
|
|
// set content type |
|
1388
|
|
|
$this->outgoing_payload .= 'Content-Type: text/xml; charset='.$this->soap_defencoding."\r\nContent-Length: ".strlen($data)."\r\n"; |
|
1389
|
|
|
// http encoding |
|
1390
|
|
|
if($this->encoding != '' && function_exists('gzdeflate')){ |
|
1391
|
|
|
$this->outgoing_payload .= "Accept-Encoding: $this->encoding\r\n". |
|
1392
|
|
|
"Connection: close\r\n"; |
|
1393
|
|
|
set_magic_quotes_runtime(0); |
|
1394
|
|
|
} |
|
1395
|
|
|
// set soapaction |
|
1396
|
|
|
if($this->useSOAPAction){ |
|
1397
|
|
|
$this->outgoing_payload .= "SOAPAction: \"$this->soapaction\""."\r\n"; |
|
1398
|
|
|
} |
|
1399
|
|
|
$this->outgoing_payload .= "\r\n"; |
|
1400
|
|
|
// add data |
|
1401
|
|
|
$this->outgoing_payload .= $data; |
|
1402
|
|
|
|
|
1403
|
|
|
// send payload |
|
1404
|
|
|
if(!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { |
|
1405
|
|
|
$this->setError('couldn\'t write message data to socket'); |
|
1406
|
|
|
$this->debug('Write error'); |
|
1407
|
|
|
} |
|
1408
|
|
|
$this->debug('wrote data to socket'); |
|
1409
|
|
|
|
|
1410
|
|
|
// get response |
|
1411
|
|
|
$this->incoming_payload = ''; |
|
1412
|
|
|
//$strlen = 0; |
|
1413
|
|
|
while( $data = fread($fp, 32768) ){ |
|
1414
|
|
|
$this->incoming_payload .= $data; |
|
1415
|
|
|
//$strlen += strlen($data); |
|
1416
|
|
|
} |
|
1417
|
|
|
$this->debug('received '.strlen($this->incoming_payload).' bytes of data from server'); |
|
1418
|
|
|
|
|
1419
|
|
|
// close filepointer |
|
1420
|
|
|
fclose($fp); |
|
1421
|
|
|
$this->debug('closed socket'); |
|
1422
|
|
|
|
|
1423
|
|
|
// connection was closed unexpectedly |
|
1424
|
|
|
if($this->incoming_payload == ''){ |
|
1425
|
|
|
$this->setError('no response from server'); |
|
1426
|
|
|
return false; |
|
1427
|
|
|
} |
|
1428
|
|
|
|
|
1429
|
|
|
$this->debug('received incoming payload: '.strlen($this->incoming_payload)); |
|
1430
|
|
|
$data = $this->incoming_payload."\r\n\r\n\r\n\r\n"; |
|
1431
|
|
|
|
|
1432
|
|
|
// remove 100 header |
|
1433
|
|
|
if(ereg('^HTTP/1.1 100',$data)){ |
|
1434
|
|
|
if($pos = strpos($data,"\r\n\r\n") ){ |
|
1435
|
|
|
$data = ltrim(substr($data,$pos)); |
|
1436
|
|
|
} elseif($pos = strpos($data,"\n\n") ){ |
|
1437
|
|
|
$data = ltrim(substr($data,$pos)); |
|
1438
|
|
|
} |
|
1439
|
|
|
}// |
|
1440
|
|
|
|
|
1441
|
|
|
// separate content from HTTP headers |
|
1442
|
|
|
if( $pos = strpos($data,"\r\n\r\n") ){ |
|
1443
|
|
|
$lb = "\r\n"; |
|
1444
|
|
|
} elseif( $pos = strpos($data,"\n\n") ){ |
|
1445
|
|
|
$lb = "\n"; |
|
1446
|
|
|
} else { |
|
1447
|
|
|
$this->setError('no proper separation of headers and document'); |
|
1448
|
|
|
return false; |
|
1449
|
|
|
} |
|
1450
|
|
|
$header_data = trim(substr($data,0,$pos)); |
|
1451
|
|
|
$header_array = explode($lb,$header_data); |
|
1452
|
|
|
$data = ltrim(substr($data,$pos)); |
|
1453
|
|
|
$this->debug('found proper separation of headers and document'); |
|
1454
|
|
|
$this->debug('cleaned data, stringlen: '.strlen($data)); |
|
1455
|
|
|
// clean headers |
|
1456
|
|
|
foreach($header_array as $header_line){ |
|
1457
|
|
|
$arr = explode(':',$header_line); |
|
1458
|
|
|
if(count($arr) >= 2){ |
|
1459
|
|
|
$headers[trim($arr[0])] = trim($arr[1]); |
|
1460
|
|
|
} |
|
1461
|
|
|
} |
|
1462
|
|
|
//print "headers: <pre>$header_data</pre><br>"; |
|
1463
|
|
|
//print "data: <pre>$data</pre><br>"; |
|
1464
|
|
|
|
|
1465
|
|
|
// decode transfer-encoding |
|
1466
|
|
|
if(isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] == 'chunked'){ |
|
1467
|
|
|
//$timer->setMarker('starting to decode chunked content'); |
|
1468
|
|
|
if(!$data = $this->decodeChunked($data)){ |
|
1469
|
|
|
$this->setError('Decoding of chunked data failed'); |
|
1470
|
|
|
return false; |
|
1471
|
|
|
} |
|
1472
|
|
|
//$timer->setMarker('finished decoding of chunked content'); |
|
1473
|
|
|
//print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; |
|
1474
|
|
|
} |
|
1475
|
|
|
|
|
1476
|
|
|
// decode content-encoding |
|
1477
|
|
|
if(isset($headers['Content-Encoding']) && $headers['Content-Encoding'] != ''){ |
|
1478
|
|
|
if($headers['Content-Encoding'] == 'deflate' || $headers['Content-Encoding'] == 'gzip'){ |
|
1479
|
|
|
// if decoding works, use it. else assume data wasn't gzencoded |
|
1480
|
|
|
if(function_exists('gzinflate')){ |
|
1481
|
|
|
//$timer->setMarker('starting decoding of gzip/deflated content'); |
|
1482
|
|
|
if($headers['Content-Encoding'] == 'deflate' && $degzdata = @gzinflate($data)){ |
|
1483
|
|
|
$data = $degzdata; |
|
1484
|
|
|
} elseif($headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){ |
|
1485
|
|
|
$data = $degzdata; |
|
1486
|
|
|
} else { |
|
1487
|
|
|
$this->setError('Errors occurred when trying to decode the data'); |
|
1488
|
|
|
} |
|
1489
|
|
|
//$timer->setMarker('finished decoding of gzip/deflated content'); |
|
1490
|
|
|
//print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; |
|
1491
|
|
|
} else { |
|
1492
|
|
|
$this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); |
|
1493
|
|
|
} |
|
1494
|
|
|
} |
|
1495
|
|
|
} |
|
1496
|
|
|
|
|
1497
|
|
|
if(strlen($data) == 0){ |
|
1498
|
|
|
$this->debug('no data after headers!'); |
|
1499
|
|
|
$this->setError('no data present after HTTP headers'); |
|
1500
|
|
|
return false; |
|
1501
|
|
|
} |
|
1502
|
|
|
$this->debug('end of send()'); |
|
1503
|
|
|
return $data; |
|
1504
|
|
|
} |
|
1505
|
|
|
|
|
1506
|
|
|
|
|
1507
|
|
|
/** |
|
1508
|
|
|
* send the SOAP message via HTTPS 1.0 using CURL |
|
1509
|
|
|
* |
|
1510
|
|
|
* @param string $msg message data |
|
|
|
|
|
|
1511
|
|
|
* @param integer $timeout set timeout in seconds |
|
1512
|
|
|
* @return string data |
|
1513
|
|
|
* @access public |
|
1514
|
|
|
*/ |
|
1515
|
|
|
function sendHTTPS($data, $timeout=0) { |
|
1516
|
|
|
//global $t; |
|
1517
|
|
|
//$t->setMarker('inside sendHTTPS()'); |
|
1518
|
|
|
$this->debug('entered sendHTTPS() with data of length: '.strlen($data)); |
|
1519
|
|
|
// init CURL |
|
1520
|
|
|
$ch = curl_init(); |
|
1521
|
|
|
//$t->setMarker('got curl handle'); |
|
1522
|
|
|
// set proxy |
|
1523
|
|
|
if($this->proxyhost && $this->proxyport){ |
|
1524
|
|
|
$host = $this->proxyhost; |
|
1525
|
|
|
$port = $this->proxyport; |
|
1526
|
|
|
} else { |
|
1527
|
|
|
$host = $this->host; |
|
1528
|
|
|
$port = $this->port; |
|
1529
|
|
|
} |
|
1530
|
|
|
// set url |
|
1531
|
|
|
$hostURL = ($port != '') ? "https://$host:$port" : "https://$host"; |
|
1532
|
|
|
// add path |
|
1533
|
|
|
$hostURL .= $this->path; |
|
1534
|
|
|
curl_setopt($ch, CURLOPT_URL, $hostURL); |
|
1535
|
|
|
// set other options |
|
1536
|
|
|
curl_setopt($ch, CURLOPT_HEADER, 1); |
|
1537
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
|
1538
|
|
|
// encode |
|
1539
|
|
|
if(function_exists('gzinflate')){ |
|
1540
|
|
|
curl_setopt($ch, CURLOPT_ENCODING, 'deflate'); |
|
1541
|
|
|
} |
|
1542
|
|
|
// persistent connection |
|
1543
|
|
|
//curl_setopt($ch, CURL_HTTP_VERSION_1_1, true); |
|
1544
|
|
|
|
|
1545
|
|
|
// set timeout |
|
1546
|
|
|
if($timeout != 0){ |
|
1547
|
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); |
|
1548
|
|
|
} |
|
1549
|
|
|
|
|
1550
|
|
|
$credentials = ''; |
|
1551
|
|
|
if($this->username != '') { |
|
1552
|
|
|
$credentials = 'Authorization: Basic '.base64_encode("$this->username:$this->password").'\r\n'; |
|
1553
|
|
|
} |
|
1554
|
|
|
|
|
1555
|
|
|
if($this->encoding != ''){ |
|
1556
|
|
|
if(function_exists('gzdeflate')){ |
|
1557
|
|
|
$encoding_headers = "Accept-Encoding: $this->encoding\r\n". |
|
1558
|
|
|
"Connection: close\r\n"; |
|
1559
|
|
|
set_magic_quotes_runtime(0); |
|
1560
|
|
|
} |
|
1561
|
|
|
} |
|
1562
|
|
|
|
|
1563
|
|
|
if($this->proxyhost && $this->proxyport){ |
|
1564
|
|
|
$this->outgoing_payload = "POST $this->url HTTP/$this->protocol_version\r\n"; |
|
1565
|
|
|
} else { |
|
1566
|
|
|
$this->outgoing_payload = "POST $this->path HTTP/$this->protocol_version\r\n"; |
|
1567
|
|
|
} |
|
1568
|
|
|
|
|
1569
|
|
|
$this->outgoing_payload .= |
|
1570
|
|
|
"User-Agent: $this->title v$this->version\r\n". |
|
1571
|
|
|
"Host: ".$this->host."\r\n". |
|
1572
|
|
|
$encoding_headers. |
|
1573
|
|
|
$credentials. |
|
1574
|
|
|
"Content-Type: text/xml; charset=\"$this->soap_defencoding\"\r\n". |
|
1575
|
|
|
"Content-Length: ".strlen($data)."\r\n". |
|
1576
|
|
|
"SOAPAction: \"$this->soapaction\""."\r\n\r\n". |
|
1577
|
|
|
$data; |
|
1578
|
|
|
|
|
1579
|
|
|
// set payload |
|
1580
|
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); |
|
1581
|
|
|
//$t->setMarker('set curl options, executing...'); |
|
1582
|
|
|
// send and receive |
|
1583
|
|
|
$this->incoming_payload = curl_exec($ch); |
|
1584
|
|
|
//$t->setMarker('executed transfer'); |
|
1585
|
|
|
$data = $this->incoming_payload; |
|
1586
|
|
|
|
|
1587
|
|
|
$cErr = curl_error($ch); |
|
1588
|
|
|
|
|
1589
|
|
|
if($cErr != ''){ |
|
1590
|
|
|
$err = 'cURL ERROR: '.curl_errno($ch).': '.$cErr.'<br>'; |
|
1591
|
|
|
foreach(curl_getinfo($ch) as $k => $v){ |
|
1592
|
|
|
$err .= "$k: $v<br>"; |
|
1593
|
|
|
} |
|
1594
|
|
|
$this->setError($err); |
|
1595
|
|
|
curl_close($ch); |
|
1596
|
|
|
return false; |
|
1597
|
|
|
} else { |
|
1598
|
|
|
//echo '<pre>'; |
|
1599
|
|
|
//var_dump(curl_getinfo($ch)); |
|
1600
|
|
|
//echo '</pre>'; |
|
1601
|
|
|
} |
|
1602
|
|
|
// close curl |
|
1603
|
|
|
curl_close($ch); |
|
1604
|
|
|
//$t->setMarker('closed curl'); |
|
1605
|
|
|
|
|
1606
|
|
|
// remove 100 header |
|
1607
|
|
|
if(ereg('^HTTP/1.1 100',$data)){ |
|
1608
|
|
|
if($pos = strpos($data,"\r\n\r\n") ){ |
|
1609
|
|
|
$data = ltrim(substr($data,$pos)); |
|
1610
|
|
|
} elseif($pos = strpos($data,"\n\n") ){ |
|
1611
|
|
|
$data = ltrim(substr($data,$pos)); |
|
1612
|
|
|
} |
|
1613
|
|
|
}// |
|
1614
|
|
|
|
|
1615
|
|
|
// separate content from HTTP headers |
|
1616
|
|
|
if( $pos = strpos($data,"\r\n\r\n") ){ |
|
1617
|
|
|
$lb = "\r\n"; |
|
1618
|
|
|
} elseif( $pos = strpos($data,"\n\n") ){ |
|
1619
|
|
|
$lb = "\n"; |
|
1620
|
|
|
} else { |
|
1621
|
|
|
$this->setError('no proper separation of headers and document'); |
|
1622
|
|
|
return false; |
|
1623
|
|
|
} |
|
1624
|
|
|
$header_data = trim(substr($data,0,$pos)); |
|
1625
|
|
|
$header_array = explode($lb,$header_data); |
|
1626
|
|
|
$data = ltrim(substr($data,$pos)); |
|
1627
|
|
|
$this->debug('found proper separation of headers and document'); |
|
1628
|
|
|
$this->debug('cleaned data, stringlen: '.strlen($data)); |
|
1629
|
|
|
// clean headers |
|
1630
|
|
|
foreach($header_array as $header_line){ |
|
1631
|
|
|
$arr = explode(':',$header_line); |
|
1632
|
|
|
$headers[trim($arr[0])] = trim($arr[1]); |
|
1633
|
|
|
} |
|
1634
|
|
|
if(strlen($data) == 0){ |
|
1635
|
|
|
$this->debug('no data after headers!'); |
|
1636
|
|
|
$this->setError('no data present after HTTP headers.'); |
|
1637
|
|
|
return false; |
|
1638
|
|
|
} |
|
1639
|
|
|
|
|
1640
|
|
|
// decode transfer-encoding |
|
1641
|
|
|
if($headers['Transfer-Encoding'] == 'chunked'){ |
|
1642
|
|
|
if(!$data = $this->decodeChunked($data)){ |
|
1643
|
|
|
$this->setError('Decoding of chunked data failed'); |
|
1644
|
|
|
return false; |
|
1645
|
|
|
} |
|
1646
|
|
|
} |
|
1647
|
|
|
// decode content-encoding |
|
1648
|
|
|
if($headers['Content-Encoding'] != ''){ |
|
1649
|
|
|
if($headers['Content-Encoding'] == 'deflate' || $headers['Content-Encoding'] == 'gzip'){ |
|
1650
|
|
|
// if decoding works, use it. else assume data wasn't gzencoded |
|
1651
|
|
|
if(function_exists('gzinflate')){ |
|
1652
|
|
|
if($headers['Content-Encoding'] == 'deflate' && $degzdata = @gzinflate($data)){ |
|
1653
|
|
|
$data = $degzdata; |
|
1654
|
|
|
} elseif($headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){ |
|
1655
|
|
|
$data = $degzdata; |
|
1656
|
|
|
} else { |
|
1657
|
|
|
$this->setError('Errors occurred when trying to decode the data'); |
|
1658
|
|
|
} |
|
1659
|
|
|
} else { |
|
1660
|
|
|
$this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); |
|
1661
|
|
|
} |
|
1662
|
|
|
} |
|
1663
|
|
|
} |
|
1664
|
|
|
// set decoded payload |
|
1665
|
|
|
$this->incoming_payload = $header_data."\r\n\r\n".$data; |
|
1666
|
|
|
return $data; |
|
1667
|
|
|
} |
|
1668
|
|
|
|
|
1669
|
|
|
/** |
|
1670
|
|
|
* if authenticating, set user credentials here |
|
1671
|
|
|
* |
|
1672
|
|
|
* @param string $user |
|
|
|
|
|
|
1673
|
|
|
* @param string $pass |
|
|
|
|
|
|
1674
|
|
|
* @access public |
|
1675
|
|
|
*/ |
|
1676
|
|
|
function setCredentials($username, $password) { |
|
1677
|
|
|
$this->username = $username; |
|
1678
|
|
|
$this->password = $password; |
|
1679
|
|
|
} |
|
1680
|
|
|
|
|
1681
|
|
|
/** |
|
1682
|
|
|
* set the soapaction value |
|
1683
|
|
|
* |
|
1684
|
|
|
* @param string $soapaction |
|
1685
|
|
|
* @access public |
|
1686
|
|
|
*/ |
|
1687
|
|
|
function setSOAPAction($soapaction) { |
|
1688
|
|
|
$this->soapaction = $soapaction; |
|
1689
|
|
|
} |
|
1690
|
|
|
|
|
1691
|
|
|
/** |
|
1692
|
|
|
* use http encoding |
|
1693
|
|
|
* |
|
1694
|
|
|
* @param string $enc encoding style. supported values: gzip, deflate, or both |
|
1695
|
|
|
* @access public |
|
1696
|
|
|
*/ |
|
1697
|
|
|
function setEncoding($enc='gzip, deflate'){ |
|
1698
|
|
|
$this->encoding = $enc; |
|
1699
|
|
|
$this->protocol_version = '1.1'; |
|
1700
|
|
|
} |
|
1701
|
|
|
|
|
1702
|
|
|
/** |
|
1703
|
|
|
* set proxy info here |
|
1704
|
|
|
* |
|
1705
|
|
|
* @param string $proxyhost |
|
1706
|
|
|
* @param string $proxyport |
|
1707
|
|
|
* @access public |
|
1708
|
|
|
*/ |
|
1709
|
|
|
function setProxy($proxyhost, $proxyport) { |
|
1710
|
|
|
$this->proxyhost = $proxyhost; |
|
1711
|
|
|
$this->proxyport = $proxyport; |
|
1712
|
|
|
} |
|
1713
|
|
|
|
|
1714
|
|
|
/** |
|
1715
|
|
|
* decode a string that is encoded w/ "chunked' transfer encoding |
|
1716
|
|
|
* as defined in RFC2068 19.4.6 |
|
1717
|
|
|
* |
|
1718
|
|
|
* @param string $buffer |
|
1719
|
|
|
* @returns string |
|
1720
|
|
|
* @access public |
|
1721
|
|
|
*/ |
|
1722
|
|
|
function decodeChunked($buffer){ |
|
1723
|
|
|
// length := 0 |
|
1724
|
|
|
$length = 0; |
|
1725
|
|
|
$new = ''; |
|
1726
|
|
|
|
|
1727
|
|
|
// read chunk-size, chunk-extension (if any) and CRLF |
|
1728
|
|
|
// get the position of the linebreak |
|
1729
|
|
|
$chunkend = strpos($buffer,"\r\n") + 2; |
|
1730
|
|
|
$temp = substr($buffer,0,$chunkend); |
|
1731
|
|
|
$chunk_size = hexdec( trim($temp) ); |
|
1732
|
|
|
$chunkstart = $chunkend; |
|
1733
|
|
|
// while (chunk-size > 0) { |
|
1734
|
|
|
while ($chunk_size > 0) { |
|
1735
|
|
|
|
|
1736
|
|
|
$chunkend = strpos( $buffer, "\r\n", $chunkstart + $chunk_size); |
|
1737
|
|
|
|
|
1738
|
|
|
// Just in case we got a broken connection |
|
1739
|
|
|
if ($chunkend == FALSE) { |
|
|
|
|
|
|
1740
|
|
|
$chunk = substr($buffer,$chunkstart); |
|
1741
|
|
|
// append chunk-data to entity-body |
|
1742
|
|
|
$new .= $chunk; |
|
1743
|
|
|
$length += strlen($chunk); |
|
1744
|
|
|
break; |
|
1745
|
|
|
} |
|
1746
|
|
|
|
|
1747
|
|
|
// read chunk-data and CRLF |
|
1748
|
|
|
$chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); |
|
1749
|
|
|
// append chunk-data to entity-body |
|
1750
|
|
|
$new .= $chunk; |
|
1751
|
|
|
// length := length + chunk-size |
|
1752
|
|
|
$length += strlen($chunk); |
|
1753
|
|
|
// read chunk-size and CRLF |
|
1754
|
|
|
$chunkstart = $chunkend + 2; |
|
1755
|
|
|
|
|
1756
|
|
|
$chunkend = strpos($buffer,"\r\n",$chunkstart)+2; |
|
1757
|
|
|
if ($chunkend == FALSE) { |
|
|
|
|
|
|
1758
|
|
|
break; //Just in case we got a broken connection |
|
1759
|
|
|
} |
|
1760
|
|
|
$temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); |
|
1761
|
|
|
$chunk_size = hexdec( trim($temp) ); |
|
1762
|
|
|
$chunkstart = $chunkend; |
|
1763
|
|
|
} |
|
1764
|
|
|
// Update headers |
|
1765
|
|
|
//$this->Header['content-length'] = $length; |
|
1766
|
|
|
//unset($this->Header['transfer-encoding']); |
|
1767
|
|
|
return $new; |
|
1768
|
|
|
} |
|
1769
|
|
|
|
|
1770
|
|
|
} |
|
1771
|
|
|
|
|
1772
|
|
|
?><?php |
|
1773
|
|
|
|
|
1774
|
|
|
/** |
|
1775
|
|
|
* |
|
1776
|
|
|
* soap_server allows the user to create a SOAP server |
|
1777
|
|
|
* that is capable of receiving messages and returning responses |
|
1778
|
|
|
* |
|
1779
|
|
|
* NOTE: WSDL functionality is experimental |
|
1780
|
|
|
* |
|
1781
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
1782
|
|
|
* @version v 0.6.3 |
|
1783
|
|
|
* @access public |
|
1784
|
|
|
*/ |
|
1785
|
|
|
class soap_server extends nusoap_base { |
|
1786
|
|
|
|
|
1787
|
|
|
var $service = ''; // service name |
|
1788
|
|
|
var $operations = array(); // assoc array of operations => opData |
|
1789
|
|
|
var $responseHeaders = false; |
|
1790
|
|
|
var $headers = ''; |
|
1791
|
|
|
var $request = ''; |
|
1792
|
|
|
var $charset_encoding = 'UTF-8'; |
|
1793
|
|
|
var $fault = false; |
|
1794
|
|
|
var $result = 'successful'; |
|
1795
|
|
|
var $wsdl = false; |
|
1796
|
|
|
var $externalWSDLURL = false; |
|
1797
|
|
|
var $debug_flag = true; |
|
1798
|
|
|
|
|
1799
|
|
|
/** |
|
1800
|
|
|
* constructor |
|
1801
|
|
|
* the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. |
|
1802
|
|
|
* |
|
1803
|
|
|
* @param string $wsdl path or URL to a WSDL file |
|
1804
|
|
|
* @access public |
|
1805
|
|
|
*/ |
|
1806
|
|
|
function soap_server($wsdl=false){ |
|
1807
|
|
|
|
|
1808
|
|
|
// turn on debugging? |
|
1809
|
|
|
global $debug; |
|
1810
|
|
|
if(isset($debug)){ |
|
1811
|
|
|
$this->debug_flag = 1; |
|
|
|
|
|
|
1812
|
|
|
} |
|
1813
|
|
|
|
|
1814
|
|
|
// wsdl |
|
1815
|
|
|
if($wsdl){ |
|
|
|
|
|
|
1816
|
|
|
$this->wsdl = new wsdl($wsdl); |
|
1817
|
|
|
$this->externalWSDLURL = $wsdl; |
|
|
|
|
|
|
1818
|
|
|
if($err = $this->wsdl->getError()){ |
|
1819
|
|
|
die('WSDL ERROR: '.$err); |
|
|
|
|
|
|
1820
|
|
|
} |
|
1821
|
|
|
} |
|
1822
|
|
|
} |
|
1823
|
|
|
|
|
1824
|
|
|
/** |
|
1825
|
|
|
* processes request and returns response |
|
1826
|
|
|
* |
|
1827
|
|
|
* @param string $data usually is the value of $HTTP_RAW_POST_DATA |
|
1828
|
|
|
* @access public |
|
1829
|
|
|
*/ |
|
1830
|
|
|
function service($data){ |
|
1831
|
|
|
// print wsdl |
|
1832
|
|
|
global $QUERY_STRING, $HTTP_SERVER_VARS; |
|
1833
|
|
|
if(isset($HTTP_SERVER_VARS['QUERY_STRING'])){ |
|
1834
|
|
|
$qs = $HTTP_SERVER_VARS['QUERY_STRING']; |
|
1835
|
|
|
} elseif(isset($GLOBALS['QUERY_STRING'])){ |
|
1836
|
|
|
$qs = $GLOBALS['QUERY_STRING']; |
|
1837
|
|
|
} elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){ |
|
1838
|
|
|
$qs = $QUERY_STRING; |
|
1839
|
|
|
} |
|
1840
|
|
|
// gen wsdl |
|
1841
|
|
|
if(isset($qs) && ereg('wsdl', $qs) ){ |
|
1842
|
|
|
if($this->externalWSDLURL){ |
|
1843
|
|
|
header('Location: '.$this->externalWSDLURL); |
|
1844
|
|
|
exit(); |
|
|
|
|
|
|
1845
|
|
|
} else { |
|
1846
|
|
|
header("Content-Type: text/xml\r\n"); |
|
1847
|
|
|
print $this->wsdl->serialize(); |
|
1848
|
|
|
exit(); |
|
|
|
|
|
|
1849
|
|
|
} |
|
1850
|
|
|
} |
|
1851
|
|
|
|
|
1852
|
|
|
// print web interface |
|
1853
|
|
|
if($data == '' && $this->wsdl){ |
|
1854
|
|
|
print $this->webDescription(); |
|
1855
|
|
|
} else { |
|
1856
|
|
|
|
|
1857
|
|
|
// $response is the serialized response message |
|
1858
|
|
|
$response = $this->parse_request($data); |
|
1859
|
|
|
$this->debug('server sending...'); |
|
1860
|
|
|
$payload = $response; |
|
1861
|
|
|
// add debug data if in debug mode |
|
1862
|
|
|
if(isset($this->debug_flag) && $this->debug_flag == 1){ |
|
1863
|
|
|
$payload .= "<!--\n".str_replace('--','- -',$this->debug_str)."\n-->"; |
|
1864
|
|
|
} |
|
1865
|
|
|
// print headers |
|
1866
|
|
|
if($this->fault){ |
|
1867
|
|
|
$header[] = "HTTP/1.0 500 Internal Server Error\r\n"; |
|
1868
|
|
|
$header[] = "Status: 500 Internal Server Error\r\n"; |
|
1869
|
|
|
} else { |
|
1870
|
|
|
$header[] = "Status: 200 OK\r\n"; |
|
1871
|
|
|
} |
|
1872
|
|
|
$header[] = "Server: $this->title Server v$this->version\r\n"; |
|
1873
|
|
|
$header[] = "Connection: Close\r\n"; |
|
1874
|
|
|
$header[] = "Content-Type: text/xml; charset=$this->charset_encoding\r\n"; |
|
1875
|
|
|
$header[] = "Content-Length: ".strlen($payload)."\r\n\r\n"; |
|
1876
|
|
|
reset($header); |
|
1877
|
|
|
foreach($header as $hdr){ |
|
1878
|
|
|
header($hdr); |
|
1879
|
|
|
} |
|
1880
|
|
|
$this->response = join("\r\n",$header).$payload; |
|
1881
|
|
|
print $payload; |
|
1882
|
|
|
} |
|
1883
|
|
|
} |
|
1884
|
|
|
|
|
1885
|
|
|
/** |
|
1886
|
|
|
* parses request and posts response |
|
1887
|
|
|
* |
|
1888
|
|
|
* @param string $data XML string |
|
1889
|
|
|
* @return string XML response msg |
|
1890
|
|
|
* @access private |
|
1891
|
|
|
*/ |
|
1892
|
|
|
function parse_request($data='') { |
|
1893
|
|
|
if (!isset($_SERVER)) |
|
1894
|
|
|
$_SERVER =& $GLOBALS['HTTP_SERVER_VARS']; |
|
1895
|
|
|
$this->debug('entering parseRequest() on '.date('H:i Y-m-d')); |
|
1896
|
|
|
$dump = ''; |
|
1897
|
|
|
// get headers |
|
1898
|
|
|
if(function_exists('getallheaders')){ |
|
1899
|
|
|
$this->headers = getallheaders(); |
|
1900
|
|
|
foreach($this->headers as $k=>$v){ |
|
1901
|
|
|
$dump .= "$k: $v\r\n"; |
|
1902
|
|
|
$this->debug("$k: $v"); |
|
1903
|
|
|
} |
|
1904
|
|
|
// get SOAPAction header |
|
1905
|
|
|
if(isset($this->headers['SOAPAction'])){ |
|
1906
|
|
|
$this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']); |
|
1907
|
|
|
} |
|
1908
|
|
|
// get the character encoding of the incoming request |
|
1909
|
|
|
if(strpos($this->headers['Content-Type'],'=')){ |
|
1910
|
|
|
$enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1)); |
|
1911
|
|
|
if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ |
|
1912
|
|
|
$this->xml_encoding = $enc; |
|
1913
|
|
|
} else { |
|
1914
|
|
|
$this->xml_encoding = 'us-ascii'; |
|
1915
|
|
|
} |
|
1916
|
|
|
} |
|
1917
|
|
|
$this->debug('got encoding: '.$this->charset_encoding); |
|
1918
|
|
|
} elseif(is_array($_SERVER)){ |
|
1919
|
|
|
$this->headers['User-Agent'] = $_SERVER['HTTP_USER_AGENT']; |
|
1920
|
|
|
$this->SOAPAction = isset($_SERVER['SOAPAction']) ? $_SERVER['SOAPAction'] : ''; |
|
1921
|
|
|
} |
|
1922
|
|
|
$this->request = $dump."\r\n\r\n".$data; |
|
1923
|
|
|
// parse response, get soap parser obj |
|
1924
|
|
|
$parser = new soap_parser($data,$this->charset_encoding); |
|
1925
|
|
|
// if fault occurred during message parsing |
|
1926
|
|
|
if($err = $parser->getError()){ |
|
1927
|
|
|
// parser debug |
|
1928
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
|
1929
|
|
|
$this->result = 'fault: error in msg parsing: '.$err; |
|
1930
|
|
|
$this->fault('Server',"error in msg parsing:\n".$err); |
|
1931
|
|
|
// return soapresp |
|
1932
|
|
|
return $this->fault->serialize(); |
|
1933
|
|
|
// else successfully parsed request into soapval object |
|
1934
|
|
|
} else { |
|
1935
|
|
|
// get/set methodname |
|
1936
|
|
|
$this->methodname = $parser->root_struct_name; |
|
1937
|
|
|
$this->debug('method name: '.$this->methodname); |
|
1938
|
|
|
// does method exist? |
|
1939
|
|
|
if(!function_exists($this->methodname)){ |
|
1940
|
|
|
// "method not found" fault here |
|
1941
|
|
|
$this->debug("method '$this->methodname' not found!"); |
|
1942
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
|
1943
|
|
|
$this->result = 'fault: method not found'; |
|
1944
|
|
|
$this->fault('Server',"method '$this->methodname' not defined in service '$this->service'"); |
|
1945
|
|
|
return $this->fault->serialize(); |
|
1946
|
|
|
} |
|
1947
|
|
|
if($this->wsdl){ |
|
1948
|
|
|
if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){ |
|
1949
|
|
|
//if( |
|
1950
|
|
|
$this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service"); |
|
1951
|
|
|
return $this->fault->serialize(); |
|
1952
|
|
|
} |
|
1953
|
|
|
} |
|
1954
|
|
|
$this->debug("method '$this->methodname' exists"); |
|
1955
|
|
|
// evaluate message, getting back parameters |
|
1956
|
|
|
$this->debug('calling parser->get_response()'); |
|
1957
|
|
|
$request_data = $parser->get_response(); |
|
1958
|
|
|
// parser debug |
|
1959
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
|
1960
|
|
|
// verify that request parameters match the method's signature |
|
1961
|
|
|
if($this->verify_method($this->methodname,$request_data)){ |
|
1962
|
|
|
// if there are parameters to pass |
|
1963
|
|
|
$this->debug('params var dump '.$this->varDump($request_data)); |
|
1964
|
|
|
if($request_data){ |
|
1965
|
|
|
$this->debug("calling '$this->methodname' with params"); |
|
1966
|
|
|
if (! function_exists('call_user_func_array')) { |
|
1967
|
|
|
$this->debug('calling method using eval()'); |
|
1968
|
|
|
$funcCall = $this->methodname.'('; |
|
1969
|
|
|
foreach($request_data as $param) { |
|
1970
|
|
|
$funcCall .= "\"$param\","; |
|
1971
|
|
|
} |
|
1972
|
|
|
$funcCall = substr($funcCall, 0, -1).')'; |
|
1973
|
|
|
$this->debug('function call:<br>'.$funcCall); |
|
1974
|
|
|
@eval("\$method_response = $funcCall;"); |
|
|
|
|
|
|
1975
|
|
|
} else { |
|
1976
|
|
|
$this->debug('calling method using call_user_func_array()'); |
|
1977
|
|
|
$method_response = call_user_func_array("$this->methodname",$request_data); |
|
1978
|
|
|
} |
|
1979
|
|
|
$this->debug('response var dump'.$this->varDump($method_response)); |
|
1980
|
|
|
} else { |
|
1981
|
|
|
// call method w/ no parameters |
|
1982
|
|
|
$this->debug("calling $this->methodname w/ no params"); |
|
1983
|
|
|
$m = $this->methodname; |
|
1984
|
|
|
$method_response = @$m(); |
|
1985
|
|
|
} |
|
1986
|
|
|
$this->debug("done calling method: $this->methodname, received $method_response of type".gettype($method_response)); |
|
1987
|
|
|
// if we got nothing back. this might be ok (echoVoid) |
|
1988
|
|
|
if(isset($method_response) && $method_response != '' || is_bool($method_response)) { |
|
1989
|
|
|
// if fault |
|
1990
|
|
|
if(strtolower(get_class($method_response)) == 'soap_fault'){ |
|
1991
|
|
|
$this->debug('got a fault object from method'); |
|
1992
|
|
|
$this->fault = $method_response; |
|
1993
|
|
|
return $method_response->serialize(); |
|
1994
|
|
|
// if return val is soapval object |
|
1995
|
|
|
} elseif(strtolower(get_class($method_response)) == 'soapval'){ |
|
1996
|
|
|
$this->debug('got a soapval object from method'); |
|
1997
|
|
|
$return_val = $method_response->serialize(); |
|
1998
|
|
|
// returned other |
|
1999
|
|
|
} else { |
|
2000
|
|
|
$this->debug('got a(n) '.gettype($method_response).' from method'); |
|
2001
|
|
|
$this->debug('serializing return value'); |
|
2002
|
|
|
if($this->wsdl){ |
|
2003
|
|
|
// weak attempt at supporting multiple output params |
|
2004
|
|
|
if(sizeof($this->opData['output']['parts']) > 1){ |
|
2005
|
|
|
$opParams = $method_response; |
|
2006
|
|
|
} else { |
|
2007
|
|
|
$opParams = array($method_response); |
|
2008
|
|
|
} |
|
2009
|
|
|
$return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); |
|
2010
|
|
|
} else { |
|
2011
|
|
|
$return_val = $this->serialize_val($method_response); |
|
2012
|
|
|
} |
|
2013
|
|
|
} |
|
2014
|
|
|
$this->debug('return val:'.$this->varDump($return_val)); |
|
2015
|
|
|
} else { |
|
2016
|
|
|
$return_val = ''; |
|
2017
|
|
|
$this->debug('got no response from method'); |
|
2018
|
|
|
} |
|
2019
|
|
|
$this->debug('serializing response'); |
|
2020
|
|
|
$payload = '<'.$this->methodname."Response>".$return_val.'</'.$this->methodname."Response>"; |
|
2021
|
|
|
$this->result = 'successful'; |
|
2022
|
|
|
if($this->wsdl){ |
|
2023
|
|
|
//if($this->debug_flag){ |
|
2024
|
|
|
$this->debug("WSDL debug data:\n".$this->wsdl->debug_str); |
|
2025
|
|
|
// } |
|
2026
|
|
|
// Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. |
|
2027
|
|
|
return $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style']); |
|
2028
|
|
|
} else { |
|
2029
|
|
|
return $this->serializeEnvelope($payload,$this->responseHeaders); |
|
2030
|
|
|
} |
|
2031
|
|
|
} else { |
|
2032
|
|
|
// debug |
|
2033
|
|
|
$this->debug('ERROR: request not verified against method signature'); |
|
2034
|
|
|
$this->result = 'fault: request failed validation against method signature'; |
|
2035
|
|
|
// return fault |
|
2036
|
|
|
$this->fault('Server',"Operation '$this->methodname' not defined in service."); |
|
2037
|
|
|
return $this->fault->serialize(); |
|
2038
|
|
|
} |
|
2039
|
|
|
} |
|
2040
|
|
|
} |
|
2041
|
|
|
|
|
2042
|
|
|
/** |
|
2043
|
|
|
* takes the value that was created by parsing the request |
|
2044
|
|
|
* and compares to the method's signature, if available. |
|
2045
|
|
|
* |
|
2046
|
|
|
* @param mixed |
|
2047
|
|
|
* @return boolean |
|
2048
|
|
|
* @access private |
|
2049
|
|
|
*/ |
|
2050
|
|
|
function verify_method($operation,$request){ |
|
2051
|
|
|
if(isset($this->wsdl) && is_object($this->wsdl)){ |
|
2052
|
|
|
if($this->wsdl->getOperationData($operation)){ |
|
2053
|
|
|
return true; |
|
2054
|
|
|
} |
|
2055
|
|
|
} elseif(isset($this->operations[$operation])){ |
|
2056
|
|
|
return true; |
|
2057
|
|
|
} |
|
2058
|
|
|
return false; |
|
2059
|
|
|
} |
|
2060
|
|
|
|
|
2061
|
|
|
/** |
|
2062
|
|
|
* add a method to the dispatch map |
|
2063
|
|
|
* |
|
2064
|
|
|
* @param string $methodname |
|
2065
|
|
|
* @param string $in array of input values |
|
2066
|
|
|
* @param string $out array of output values |
|
2067
|
|
|
* @access public |
|
2068
|
|
|
*/ |
|
2069
|
|
|
function add_to_map($methodname,$in,$out){ |
|
2070
|
|
|
$this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); |
|
2071
|
|
|
} |
|
2072
|
|
|
|
|
2073
|
|
|
/** |
|
2074
|
|
|
* register a service with the server |
|
2075
|
|
|
* |
|
2076
|
|
|
* @param string $methodname |
|
|
|
|
|
|
2077
|
|
|
* @param string $in assoc array of input values: key = param name, value = param type |
|
2078
|
|
|
* @param string $out assoc array of output values: key = param name, value = param type |
|
2079
|
|
|
* @param string $namespace |
|
2080
|
|
|
* @param string $soapaction |
|
2081
|
|
|
* @param string $style (rpc|literal) |
|
2082
|
|
|
* @access public |
|
2083
|
|
|
*/ |
|
2084
|
|
|
function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false){ |
|
2085
|
|
|
if($this->externalWSDLURL){ |
|
2086
|
|
|
die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); |
|
|
|
|
|
|
2087
|
|
|
} |
|
2088
|
|
|
if(false == $in) { |
|
|
|
|
|
|
2089
|
|
|
} |
|
2090
|
|
|
if(false == $out) { |
|
|
|
|
|
|
2091
|
|
|
} |
|
2092
|
|
|
if(false == $namespace) { |
|
|
|
|
|
|
2093
|
|
|
} |
|
2094
|
|
|
if(false == $soapaction) { |
|
|
|
|
|
|
2095
|
|
|
global $SERVER_NAME, $SCRIPT_NAME; |
|
2096
|
|
|
$soapaction = "http://$SERVER_NAME$SCRIPT_NAME"; |
|
2097
|
|
|
} |
|
2098
|
|
|
if(false == $style) { |
|
|
|
|
|
|
2099
|
|
|
$style = "rpc"; |
|
2100
|
|
|
} |
|
2101
|
|
|
if(false == $use) { |
|
|
|
|
|
|
2102
|
|
|
$use = "encoded"; |
|
2103
|
|
|
} |
|
2104
|
|
|
|
|
2105
|
|
|
$this->operations[] = array($name => array()); |
|
2106
|
|
|
$this->operations[$name] = array( |
|
2107
|
|
|
'name' => $name, |
|
2108
|
|
|
'in' => $in, |
|
2109
|
|
|
'out' => $out, |
|
2110
|
|
|
'namespace' => $namespace, |
|
2111
|
|
|
'soapaction' => $soapaction, |
|
2112
|
|
|
'style' => $style); |
|
2113
|
|
|
if($this->wsdl){ |
|
2114
|
|
|
$this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use); |
|
2115
|
|
|
} |
|
2116
|
|
|
return true; |
|
2117
|
|
|
} |
|
2118
|
|
|
|
|
2119
|
|
|
/** |
|
2120
|
|
|
* create a fault. this also acts as a flag to the server that a fault has occured. |
|
2121
|
|
|
* |
|
2122
|
|
|
* @param string faultcode |
|
2123
|
|
|
* @param string faultactor |
|
2124
|
|
|
* @param string faultstring |
|
2125
|
|
|
* @param string faultdetail |
|
2126
|
|
|
* @access public |
|
2127
|
|
|
*/ |
|
2128
|
|
|
function fault($faultcode,$faultactor,$faultstring='',$faultdetail=''){ |
|
2129
|
|
|
$this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail); |
|
2130
|
|
|
} |
|
2131
|
|
|
|
|
2132
|
|
|
/** |
|
2133
|
|
|
* prints html description of services |
|
2134
|
|
|
* |
|
2135
|
|
|
* @access private |
|
2136
|
|
|
*/ |
|
2137
|
|
|
function webDescription(){ |
|
2138
|
|
|
$b = ' |
|
2139
|
|
|
<html><head><title>NuSOAP: '.$this->wsdl->serviceName.'</title> |
|
2140
|
|
|
<style type="text/css"> |
|
2141
|
|
|
body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } |
|
2142
|
|
|
p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } |
|
2143
|
|
|
pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} |
|
2144
|
|
|
ul { margin-top: 10px; margin-left: 20px; } |
|
2145
|
|
|
li { list-style-type: none; margin-top: 10px; color: #000000; } |
|
2146
|
|
|
.content{ |
|
2147
|
|
|
margin-left: 0px; padding-bottom: 2em; } |
|
2148
|
|
|
.nav { |
|
2149
|
|
|
padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; |
|
2150
|
|
|
margin-top: 10px; margin-left: 0px; color: #000000; |
|
2151
|
|
|
background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } |
|
2152
|
|
|
.title { |
|
2153
|
|
|
font-family: arial; font-size: 26px; color: #ffffff; |
|
2154
|
|
|
background-color: #999999; width: 105%; margin-left: 0px; |
|
2155
|
|
|
padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} |
|
2156
|
|
|
.hidden { |
|
2157
|
|
|
position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; |
|
2158
|
|
|
font-family: arial; overflow: hidden; width: 600; |
|
2159
|
|
|
padding: 20px; font-size: 10px; background-color: #999999; |
|
2160
|
|
|
layer-background-color:#FFFFFF; } |
|
2161
|
|
|
a,a:active { color: charcoal; font-weight: bold; } |
|
2162
|
|
|
a:visited { color: #666666; font-weight: bold; } |
|
2163
|
|
|
a:hover { color: cc3300; font-weight: bold; } |
|
2164
|
|
|
</style> |
|
2165
|
|
|
<script language="JavaScript" type="text/javascript"> |
|
2166
|
|
|
<!-- |
|
2167
|
|
|
// POP-UP CAPTIONS... |
|
2168
|
|
|
function lib_bwcheck(){ //Browsercheck (needed) |
|
2169
|
|
|
this.ver=navigator.appVersion |
|
2170
|
|
|
this.agent=navigator.userAgent |
|
2171
|
|
|
this.dom=document.getElementById?1:0 |
|
2172
|
|
|
this.opera5=this.agent.indexOf("Opera 5")>-1 |
|
2173
|
|
|
this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; |
|
2174
|
|
|
this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; |
|
2175
|
|
|
this.ie4=(document.all && !this.dom && !this.opera5)?1:0; |
|
2176
|
|
|
this.ie=this.ie4||this.ie5||this.ie6 |
|
2177
|
|
|
this.mac=this.agent.indexOf("Mac")>-1 |
|
2178
|
|
|
this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; |
|
2179
|
|
|
this.ns4=(document.layers && !this.dom)?1:0; |
|
2180
|
|
|
this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) |
|
2181
|
|
|
return this |
|
2182
|
|
|
} |
|
2183
|
|
|
var bw = new lib_bwcheck() |
|
2184
|
|
|
//Makes crossbrowser object. |
|
2185
|
|
|
function makeObj(obj){ |
|
2186
|
|
|
this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; |
|
2187
|
|
|
if(!this.evnt) return false |
|
2188
|
|
|
this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; |
|
2189
|
|
|
this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; |
|
2190
|
|
|
this.writeIt=b_writeIt; |
|
2191
|
|
|
return this |
|
2192
|
|
|
} |
|
2193
|
|
|
// A unit of measure that will be added when setting the position of a layer. |
|
2194
|
|
|
//var px = bw.ns4||window.opera?"":"px"; |
|
2195
|
|
|
function b_writeIt(text){ |
|
2196
|
|
|
if (bw.ns4){this.wref.write(text);this.wref.close()} |
|
2197
|
|
|
else this.wref.innerHTML = text |
|
2198
|
|
|
} |
|
2199
|
|
|
//Shows the messages |
|
2200
|
|
|
var oDesc; |
|
2201
|
|
|
function popup(divid){ |
|
2202
|
|
|
if(oDesc = new makeObj(divid)){ |
|
2203
|
|
|
oDesc.css.visibility = "visible" |
|
2204
|
|
|
} |
|
2205
|
|
|
} |
|
2206
|
|
|
function popout(){ // Hides message |
|
2207
|
|
|
if(oDesc) oDesc.css.visibility = "hidden" |
|
2208
|
|
|
} |
|
2209
|
|
|
//--> |
|
2210
|
|
|
</script> |
|
2211
|
|
|
</head> |
|
2212
|
|
|
<body> |
|
2213
|
|
|
<div class=content> |
|
2214
|
|
|
<br><br> |
|
2215
|
|
|
<div class=title>'.$this->wsdl->serviceName.'</div> |
|
2216
|
|
|
<div class=nav> |
|
2217
|
|
|
<p>View the <a href="?wsdl">WSDL</a> for the service. |
|
2218
|
|
|
Click on an operation name to view it's details.</p> |
|
2219
|
|
|
<ul>'; |
|
2220
|
|
|
foreach($this->wsdl->getOperations() as $op => $data){ |
|
2221
|
|
|
$b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>"; |
|
2222
|
|
|
// create hidden div |
|
2223
|
|
|
$b .= "<div id='$op' class='hidden'> |
|
2224
|
|
|
<a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; |
|
2225
|
|
|
foreach($data as $donnie => $marie){ // loop through opdata |
|
2226
|
|
|
if($donnie == 'input' || $donnie == 'output'){ // show input/output data |
|
2227
|
|
|
$b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; |
|
2228
|
|
|
foreach($marie as $captain => $tenille){ // loop through data |
|
2229
|
|
|
if($captain == 'parts'){ // loop thru parts |
|
2230
|
|
|
$b .= " $captain:<br>"; |
|
2231
|
|
|
//if(is_array($tenille)){ |
|
2232
|
|
|
foreach($tenille as $joanie => $chachi){ |
|
2233
|
|
|
$b .= " $joanie: $chachi<br>"; |
|
2234
|
|
|
} |
|
2235
|
|
|
//} |
|
2236
|
|
|
} else { |
|
2237
|
|
|
$b .= " $captain: $tenille<br>"; |
|
2238
|
|
|
} |
|
2239
|
|
|
} |
|
2240
|
|
|
} else { |
|
2241
|
|
|
$b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; |
|
2242
|
|
|
} |
|
2243
|
|
|
} |
|
2244
|
|
|
$b .= '</div>'; |
|
2245
|
|
|
} |
|
2246
|
|
|
$b .= ' |
|
2247
|
|
|
<ul> |
|
2248
|
|
|
</div> |
|
2249
|
|
|
</div></body></html>'; |
|
2250
|
|
|
return $b; |
|
2251
|
|
|
} |
|
2252
|
|
|
|
|
2253
|
|
|
/** |
|
2254
|
|
|
* sets up wsdl object |
|
2255
|
|
|
* this acts as a flag to enable internal WSDL generation |
|
2256
|
|
|
* NOTE: NOT FUNCTIONAL |
|
2257
|
|
|
* |
|
2258
|
|
|
* @param string $serviceName, name of the service |
|
|
|
|
|
|
2259
|
|
|
* @param string $namespace, tns namespace |
|
|
|
|
|
|
2260
|
|
|
*/ |
|
2261
|
|
|
function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http') { |
|
2262
|
|
|
if (!isset($_SERVER)) |
|
2263
|
|
|
$_SERVER =& $GLOBALS['HTTP_SERVER_VARS']; |
|
2264
|
|
|
$SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME']; |
|
2265
|
|
|
$SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME']; |
|
2266
|
|
|
if(false == $namespace) { |
|
|
|
|
|
|
2267
|
|
|
$namespace = "http://$SERVER_NAME/soap/$serviceName"; |
|
2268
|
|
|
} |
|
2269
|
|
|
|
|
2270
|
|
|
if(false == $endpoint) { |
|
|
|
|
|
|
2271
|
|
|
$endpoint = "http://$SERVER_NAME$SCRIPT_NAME"; |
|
2272
|
|
|
} |
|
2273
|
|
|
|
|
2274
|
|
|
$this->wsdl = new wsdl; |
|
2275
|
|
|
$this->wsdl->serviceName = $serviceName; |
|
|
|
|
|
|
2276
|
|
|
$this->wsdl->endpoint = $endpoint; |
|
2277
|
|
|
$this->wsdl->namespaces['tns'] = $namespace; |
|
2278
|
|
|
$this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; |
|
2279
|
|
|
$this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; |
|
2280
|
|
|
$this->wsdl->bindings[$serviceName.'Binding'] = array( |
|
2281
|
|
|
'name'=>$serviceName.'Binding', |
|
2282
|
|
|
'style'=>$style, |
|
2283
|
|
|
'transport'=>$transport, |
|
2284
|
|
|
'portType'=>$serviceName.'PortType'); |
|
2285
|
|
|
$this->wsdl->ports[$serviceName.'Port'] = array( |
|
2286
|
|
|
'binding'=>$serviceName.'Binding', |
|
2287
|
|
|
'location'=>$endpoint, |
|
2288
|
|
|
'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); |
|
2289
|
|
|
} |
|
2290
|
|
|
} |
|
2291
|
|
|
|
|
2292
|
|
|
?><?php |
|
2293
|
|
|
|
|
2294
|
|
|
/** |
|
2295
|
|
|
* parses a WSDL file, allows access to it's data, other utility methods |
|
2296
|
|
|
* |
|
2297
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
2298
|
|
|
* @version v 0.6.3 |
|
2299
|
|
|
* @access public |
|
2300
|
|
|
*/ |
|
2301
|
|
|
class wsdl extends XMLSchema { |
|
2302
|
|
|
var $wsdl; |
|
2303
|
|
|
// define internal arrays of bindings, ports, operations, messages, etc. |
|
2304
|
|
|
var $message = array(); |
|
2305
|
|
|
var $complexTypes = array(); |
|
2306
|
|
|
var $messages = array(); |
|
2307
|
|
|
var $currentMessage; |
|
2308
|
|
|
var $currentOperation; |
|
2309
|
|
|
var $portTypes = array(); |
|
2310
|
|
|
var $currentPortType; |
|
2311
|
|
|
var $bindings = array(); |
|
2312
|
|
|
var $currentBinding; |
|
2313
|
|
|
var $ports = array(); |
|
2314
|
|
|
var $currentPort; |
|
2315
|
|
|
var $opData = array(); |
|
2316
|
|
|
var $status = ''; |
|
2317
|
|
|
var $documentation = false; |
|
2318
|
|
|
var $endpoint = ''; |
|
2319
|
|
|
// array of wsdl docs to import |
|
2320
|
|
|
var $import = array(); |
|
2321
|
|
|
// parser vars |
|
2322
|
|
|
var $parser; |
|
2323
|
|
|
var $position = 0; |
|
2324
|
|
|
var $depth = 0; |
|
2325
|
|
|
var $depth_array = array(); |
|
2326
|
|
|
var $usedNamespaces = array(); |
|
2327
|
|
|
// for getting wsdl |
|
2328
|
|
|
var $proxyhost = ''; |
|
2329
|
|
|
var $proxyport = ''; |
|
2330
|
|
|
|
|
2331
|
|
|
/** |
|
2332
|
|
|
* constructor |
|
2333
|
|
|
* |
|
2334
|
|
|
* @param string $wsdl WSDL document URL |
|
2335
|
|
|
* @access public |
|
2336
|
|
|
*/ |
|
2337
|
|
|
function wsdl($wsdl = '',$proxyhost=false,$proxyport=false){ |
|
2338
|
|
|
$this->wsdl = $wsdl; |
|
2339
|
|
|
$this->proxyhost = $proxyhost; |
|
|
|
|
|
|
2340
|
|
|
$this->proxyport = $proxyport; |
|
|
|
|
|
|
2341
|
|
|
|
|
2342
|
|
|
// parse wsdl file |
|
2343
|
|
|
if ($wsdl != "") { |
|
2344
|
|
|
$this->debug('initial wsdl file: ' . $wsdl); |
|
2345
|
|
|
$this->parseWSDL($wsdl); |
|
2346
|
|
|
} |
|
2347
|
|
|
// imports |
|
2348
|
|
|
if (sizeof($this->import) > 0) { |
|
2349
|
|
|
foreach($this->import as $ns => $url) { |
|
2350
|
|
|
$this->debug('importing wsdl from ' . $url); |
|
2351
|
|
|
$this->parseWSDL($url); |
|
2352
|
|
|
} |
|
2353
|
|
|
} |
|
2354
|
|
|
} |
|
2355
|
|
|
|
|
2356
|
|
|
/** |
|
2357
|
|
|
* parses the wsdl document |
|
2358
|
|
|
* |
|
2359
|
|
|
* @param string $wsdl path or URL |
|
2360
|
|
|
* @access private |
|
2361
|
|
|
*/ |
|
2362
|
|
|
function parseWSDL($wsdl = '') |
|
2363
|
|
|
{ |
|
2364
|
|
|
if ($wsdl == '') { |
|
2365
|
|
|
$this->debug('no wsdl passed to parseWSDL()!!'); |
|
2366
|
|
|
$this->setError('no wsdl passed to parseWSDL()!!'); |
|
2367
|
|
|
return false; |
|
2368
|
|
|
} |
|
2369
|
|
|
|
|
2370
|
|
|
$this->debug('getting ' . $wsdl); |
|
2371
|
|
|
|
|
2372
|
|
|
// parse $wsdl for url format |
|
2373
|
|
|
$wsdl_props = parse_url($wsdl); |
|
2374
|
|
|
|
|
2375
|
|
|
if (isset($wsdl_props['host'])) { |
|
2376
|
|
|
|
|
2377
|
|
|
// get wsdl |
|
2378
|
|
|
$tr = new soap_transport_http($wsdl); |
|
2379
|
|
|
$tr->request_method = 'GET'; |
|
2380
|
|
|
$tr->useSOAPAction = false; |
|
2381
|
|
|
if($this->proxyhost && $this->proxyport){ |
|
2382
|
|
|
$tr->setProxy($this->proxyhost,$this->proxyport); |
|
2383
|
|
|
} |
|
2384
|
|
|
if (isset($wsdl_props['user'])) { |
|
2385
|
|
|
$tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']); |
|
2386
|
|
|
} |
|
2387
|
|
|
$wsdl_string = $tr->send(''); |
|
2388
|
|
|
// catch errors |
|
2389
|
|
|
if($err = $tr->getError() ){ |
|
2390
|
|
|
$this->debug('HTTP ERROR: '.$err); |
|
2391
|
|
|
$this->setError('HTTP ERROR: '.$err); |
|
2392
|
|
|
return false; |
|
2393
|
|
|
} |
|
2394
|
|
|
unset($tr); |
|
2395
|
|
|
/* $wsdl seems to be a valid url, not a file path, do an fsockopen/HTTP GET |
|
2396
|
|
|
$fsockopen_timeout = 30; |
|
2397
|
|
|
// check if a port value is supplied in url |
|
2398
|
|
|
if (isset($wsdl_props['port'])) { |
|
2399
|
|
|
// yes |
|
2400
|
|
|
$wsdl_url_port = $wsdl_props['port']; |
|
2401
|
|
|
} else { |
|
2402
|
|
|
// no, assign port number, based on url protocol (scheme) |
|
2403
|
|
|
switch ($wsdl_props['scheme']) { |
|
2404
|
|
|
case ('https') : |
|
2405
|
|
|
case ('ssl') : |
|
2406
|
|
|
case ('tls') : |
|
2407
|
|
|
$wsdl_url_port = 443; |
|
2408
|
|
|
break; |
|
2409
|
|
|
case ('http') : |
|
2410
|
|
|
default : |
|
2411
|
|
|
$wsdl_url_port = 80; |
|
2412
|
|
|
} |
|
2413
|
|
|
} |
|
2414
|
|
|
// FIXME: should implement SSL/TLS support here if CURL is available |
|
2415
|
|
|
if ($fp = fsockopen($wsdl_props['host'], $wsdl_url_port, $fsockopen_errnum, $fsockopen_errstr, $fsockopen_timeout)) { |
|
2416
|
|
|
// perform HTTP GET for WSDL file |
|
2417
|
|
|
// 10.9.02 - added poulter fix for doing this properly |
|
2418
|
|
|
$sHeader = "GET " . $wsdl_props['path']; |
|
2419
|
|
|
if (isset($wsdl_props['query'])) { |
|
2420
|
|
|
$sHeader .= "?" . $wsdl_props['query']; |
|
2421
|
|
|
} |
|
2422
|
|
|
$sHeader .= " HTTP/1.0\r\n"; |
|
2423
|
|
|
|
|
2424
|
|
|
if (isset($wsdl_props['user'])) { |
|
2425
|
|
|
$base64auth = base64_encode($wsdl_props['user'] . ":" . $wsdl_props['pass']); |
|
2426
|
|
|
$sHeader .= "Authorization: Basic $base64auth\r\n"; |
|
2427
|
|
|
} |
|
2428
|
|
|
$sHeader .= "Host: " . $wsdl_props['host'] . ( isset($wsdl_props['port']) ? ":".$wsdl_props['port'] : "" ) . "\r\n\r\n"; |
|
2429
|
|
|
fputs($fp, $sHeader); |
|
2430
|
|
|
|
|
2431
|
|
|
while (fgets($fp, 1024) != "\r\n") { |
|
2432
|
|
|
// do nothing, just read/skip past HTTP headers |
|
2433
|
|
|
// FIXME: should actually detect HTTP response code, and act accordingly if error |
|
2434
|
|
|
// HTTP headers end with extra CRLF before content body |
|
2435
|
|
|
} |
|
2436
|
|
|
// read in WSDL just like regular fopen() |
|
2437
|
|
|
$wsdl_string = ''; |
|
2438
|
|
|
while ($data = fread($fp, 32768)) { |
|
2439
|
|
|
$wsdl_string .= $data; |
|
2440
|
|
|
} |
|
2441
|
|
|
fclose($fp); |
|
2442
|
|
|
} else { |
|
2443
|
|
|
$this->setError('bad path to WSDL file.'); |
|
2444
|
|
|
return false; |
|
2445
|
|
|
} |
|
2446
|
|
|
*/ |
|
2447
|
|
|
} else { |
|
2448
|
|
|
// $wsdl seems to be a non-url file path, do the regular fopen |
|
2449
|
|
|
if ($fp = @fopen($wsdl, 'r')) { |
|
2450
|
|
|
$wsdl_string = ''; |
|
2451
|
|
|
while ($data = fread($fp, 32768)) { |
|
2452
|
|
|
$wsdl_string .= $data; |
|
2453
|
|
|
} |
|
2454
|
|
|
fclose($fp); |
|
2455
|
|
|
} else { |
|
2456
|
|
|
$this->setError('bad path to WSDL file.'); |
|
2457
|
|
|
return false; |
|
2458
|
|
|
} |
|
2459
|
|
|
} |
|
2460
|
|
|
// end new code added |
|
2461
|
|
|
// Create an XML parser. |
|
2462
|
|
|
$this->parser = xml_parser_create(); |
|
2463
|
|
|
// Set the options for parsing the XML data. |
|
2464
|
|
|
// xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); |
|
2465
|
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
|
2466
|
|
|
// Set the object for the parser. |
|
2467
|
|
|
xml_set_object($this->parser, $this); |
|
2468
|
|
|
// Set the element handlers for the parser. |
|
2469
|
|
|
xml_set_element_handler($this->parser, 'start_element', 'end_element'); |
|
2470
|
|
|
xml_set_character_data_handler($this->parser, 'character_data'); |
|
2471
|
|
|
// Parse the XML file. |
|
2472
|
|
|
if (!xml_parse($this->parser, $wsdl_string, true)) { |
|
2473
|
|
|
// Display an error message. |
|
2474
|
|
|
$errstr = sprintf( |
|
2475
|
|
|
'XML error on line %d: %s', |
|
2476
|
|
|
xml_get_current_line_number($this->parser), |
|
2477
|
|
|
xml_error_string(xml_get_error_code($this->parser)) |
|
2478
|
|
|
); |
|
2479
|
|
|
$this->debug('XML parse error: ' . $errstr); |
|
2480
|
|
|
$this->setError('Parser error: ' . $errstr); |
|
2481
|
|
|
return false; |
|
2482
|
|
|
} |
|
2483
|
|
|
// free the parser |
|
2484
|
|
|
xml_parser_free($this->parser); |
|
2485
|
|
|
// catch wsdl parse errors |
|
2486
|
|
|
if($this->getError()){ |
|
2487
|
|
|
return false; |
|
2488
|
|
|
} |
|
2489
|
|
|
// add new data to operation data |
|
2490
|
|
|
foreach($this->bindings as $binding => $bindingData) { |
|
2491
|
|
|
if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { |
|
2492
|
|
|
foreach($bindingData['operations'] as $operation => $data) { |
|
2493
|
|
|
$this->debug('post-parse data gathering for ' . $operation); |
|
2494
|
|
|
$this->bindings[$binding]['operations'][$operation]['input'] = |
|
2495
|
|
|
isset($this->bindings[$binding]['operations'][$operation]['input']) ? |
|
2496
|
|
|
array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : |
|
2497
|
|
|
$this->portTypes[ $bindingData['portType'] ][$operation]['input']; |
|
2498
|
|
|
$this->bindings[$binding]['operations'][$operation]['output'] = |
|
2499
|
|
|
isset($this->bindings[$binding]['operations'][$operation]['output']) ? |
|
2500
|
|
|
array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : |
|
2501
|
|
|
$this->portTypes[ $bindingData['portType'] ][$operation]['output']; |
|
2502
|
|
|
if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ |
|
2503
|
|
|
$this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; |
|
2504
|
|
|
} |
|
2505
|
|
|
if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ |
|
2506
|
|
|
$this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; |
|
2507
|
|
|
} |
|
2508
|
|
|
if (isset($bindingData['style'])) { |
|
2509
|
|
|
$this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; |
|
2510
|
|
|
} |
|
2511
|
|
|
$this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; |
|
2512
|
|
|
$this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; |
|
2513
|
|
|
$this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; |
|
2514
|
|
|
} |
|
2515
|
|
|
} |
|
2516
|
|
|
} |
|
2517
|
|
|
return true; |
|
2518
|
|
|
} |
|
2519
|
|
|
|
|
2520
|
|
|
/** |
|
2521
|
|
|
* start-element handler |
|
2522
|
|
|
* |
|
2523
|
|
|
* @param string $parser XML parser object |
|
2524
|
|
|
* @param string $name element name |
|
2525
|
|
|
* @param string $attrs associative array of attributes |
|
2526
|
|
|
* @access private |
|
2527
|
|
|
*/ |
|
2528
|
|
|
function start_element($parser, $name, $attrs) |
|
2529
|
|
|
{ |
|
2530
|
|
|
if ($this->status == 'schema' || ereg('schema$', $name)) { |
|
2531
|
|
|
// $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); |
|
2532
|
|
|
$this->status = 'schema'; |
|
2533
|
|
|
$this->schemaStartElement($parser, $name, $attrs); |
|
2534
|
|
|
} else { |
|
2535
|
|
|
// position in the total number of elements, starting from 0 |
|
2536
|
|
|
$pos = $this->position++; |
|
2537
|
|
|
$depth = $this->depth++; |
|
2538
|
|
|
// set self as current value for this depth |
|
2539
|
|
|
$this->depth_array[$depth] = $pos; |
|
2540
|
|
|
$this->message[$pos] = array('cdata' => ''); |
|
2541
|
|
|
// get element prefix |
|
2542
|
|
|
if (ereg(':', $name)) { |
|
2543
|
|
|
// get ns prefix |
|
2544
|
|
|
$prefix = substr($name, 0, strpos($name, ':')); |
|
2545
|
|
|
// get ns |
|
2546
|
|
|
$namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; |
|
2547
|
|
|
// get unqualified name |
|
2548
|
|
|
$name = substr(strstr($name, ':'), 1); |
|
2549
|
|
|
} |
|
2550
|
|
|
|
|
2551
|
|
|
if (count($attrs) > 0) { |
|
2552
|
|
|
foreach($attrs as $k => $v) { |
|
|
|
|
|
|
2553
|
|
|
// if ns declarations, add to class level array of valid namespaces |
|
2554
|
|
|
if (ereg("^xmlns", $k)) { |
|
2555
|
|
|
if ($ns_prefix = substr(strrchr($k, ':'), 1)) { |
|
2556
|
|
|
$this->namespaces[$ns_prefix] = $v; |
|
2557
|
|
|
} else { |
|
2558
|
|
|
$this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; |
|
2559
|
|
|
} |
|
2560
|
|
|
if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema') { |
|
2561
|
|
|
$this->XMLSchemaVersion = $v; |
|
2562
|
|
|
$this->namespaces['xsi'] = $v . '-instance'; |
|
2563
|
|
|
} |
|
2564
|
|
|
} // |
|
2565
|
|
|
// expand each attribute |
|
2566
|
|
|
$k = strpos($k, ':') ? $this->expandQname($k) : $k; |
|
2567
|
|
|
if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { |
|
2568
|
|
|
$v = strpos($v, ':') ? $this->expandQname($v) : $v; |
|
2569
|
|
|
} |
|
2570
|
|
|
$eAttrs[$k] = $v; |
|
2571
|
|
|
} |
|
2572
|
|
|
$attrs = $eAttrs; |
|
2573
|
|
|
} else { |
|
2574
|
|
|
$attrs = array(); |
|
2575
|
|
|
} |
|
2576
|
|
|
// find status, register data |
|
2577
|
|
|
switch ($this->status) { |
|
2578
|
|
|
case 'message': |
|
2579
|
|
|
if ($name == 'part') { |
|
2580
|
|
|
if (isset($attrs['type'])) { |
|
2581
|
|
|
$this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs)); |
|
2582
|
|
|
$this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; |
|
2583
|
|
|
} |
|
2584
|
|
|
if (isset($attrs['element'])) { |
|
2585
|
|
|
$this->messages[$this->currentMessage][$attrs['name']] = $attrs['element']; |
|
2586
|
|
|
} |
|
2587
|
|
|
} |
|
2588
|
|
|
break; |
|
2589
|
|
|
case 'portType': |
|
2590
|
|
|
switch ($name) { |
|
2591
|
|
|
case 'operation': |
|
2592
|
|
|
$this->currentPortOperation = $attrs['name']; |
|
2593
|
|
|
$this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); |
|
2594
|
|
|
if (isset($attrs['parameterOrder'])) { |
|
2595
|
|
|
$this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; |
|
2596
|
|
|
} |
|
2597
|
|
|
break; |
|
2598
|
|
|
case 'documentation': |
|
2599
|
|
|
$this->documentation = true; |
|
2600
|
|
|
break; |
|
2601
|
|
|
// merge input/output data |
|
2602
|
|
|
default: |
|
2603
|
|
|
$m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; |
|
2604
|
|
|
$this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; |
|
2605
|
|
|
break; |
|
2606
|
|
|
} |
|
2607
|
|
|
break; |
|
2608
|
|
|
case 'binding': |
|
2609
|
|
|
switch ($name) { |
|
2610
|
|
|
case 'binding': |
|
2611
|
|
|
// get ns prefix |
|
2612
|
|
|
if (isset($attrs['style'])) { |
|
2613
|
|
|
$this->bindings[$this->currentBinding]['prefix'] = $prefix; |
|
2614
|
|
|
} |
|
2615
|
|
|
$this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); |
|
2616
|
|
|
break; |
|
2617
|
|
|
case 'header': |
|
2618
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; |
|
2619
|
|
|
break; |
|
2620
|
|
|
case 'operation': |
|
2621
|
|
|
if (isset($attrs['soapAction'])) { |
|
2622
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; |
|
2623
|
|
|
} |
|
2624
|
|
|
if (isset($attrs['style'])) { |
|
2625
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; |
|
2626
|
|
|
} |
|
2627
|
|
|
if (isset($attrs['name'])) { |
|
2628
|
|
|
$this->currentOperation = $attrs['name']; |
|
2629
|
|
|
$this->debug("current binding operation: $this->currentOperation"); |
|
2630
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; |
|
2631
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; |
|
2632
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; |
|
2633
|
|
|
} |
|
2634
|
|
|
break; |
|
2635
|
|
|
case 'input': |
|
2636
|
|
|
$this->opStatus = 'input'; |
|
2637
|
|
|
break; |
|
2638
|
|
|
case 'output': |
|
2639
|
|
|
$this->opStatus = 'output'; |
|
2640
|
|
|
break; |
|
2641
|
|
|
case 'body': |
|
2642
|
|
|
if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { |
|
2643
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); |
|
2644
|
|
|
} else { |
|
2645
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; |
|
2646
|
|
|
} |
|
2647
|
|
|
break; |
|
2648
|
|
|
} |
|
2649
|
|
|
break; |
|
2650
|
|
|
case 'service': |
|
2651
|
|
|
switch ($name) { |
|
2652
|
|
|
case 'port': |
|
2653
|
|
|
$this->currentPort = $attrs['name']; |
|
2654
|
|
|
$this->debug('current port: ' . $this->currentPort); |
|
2655
|
|
|
$this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); |
|
2656
|
|
|
|
|
2657
|
|
|
break; |
|
2658
|
|
|
case 'address': |
|
2659
|
|
|
$this->ports[$this->currentPort]['location'] = $attrs['location']; |
|
2660
|
|
|
$this->ports[$this->currentPort]['bindingType'] = $namespace; |
|
2661
|
|
|
$this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; |
|
2662
|
|
|
$this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; |
|
2663
|
|
|
break; |
|
2664
|
|
|
} |
|
2665
|
|
|
break; |
|
2666
|
|
|
} |
|
2667
|
|
|
// set status |
|
2668
|
|
|
switch ($name) { |
|
2669
|
|
|
case "import": |
|
2670
|
|
|
if (isset($attrs['location'])) { |
|
2671
|
|
|
$this->import[$attrs['namespace']] = $attrs['location']; |
|
2672
|
|
|
} |
|
2673
|
|
|
break; |
|
2674
|
|
|
case 'types': |
|
2675
|
|
|
$this->status = 'schema'; |
|
2676
|
|
|
break; |
|
2677
|
|
|
case 'message': |
|
2678
|
|
|
$this->status = 'message'; |
|
2679
|
|
|
$this->messages[$attrs['name']] = array(); |
|
2680
|
|
|
$this->currentMessage = $attrs['name']; |
|
2681
|
|
|
break; |
|
2682
|
|
|
case 'portType': |
|
2683
|
|
|
$this->status = 'portType'; |
|
2684
|
|
|
$this->portTypes[$attrs['name']] = array(); |
|
2685
|
|
|
$this->currentPortType = $attrs['name']; |
|
2686
|
|
|
break; |
|
2687
|
|
|
case "binding": |
|
2688
|
|
|
if (isset($attrs['name'])) { |
|
2689
|
|
|
// get binding name |
|
2690
|
|
|
if (strpos($attrs['name'], ':')) { |
|
2691
|
|
|
$this->currentBinding = $this->getLocalPart($attrs['name']); |
|
2692
|
|
|
} else { |
|
2693
|
|
|
$this->currentBinding = $attrs['name']; |
|
2694
|
|
|
} |
|
2695
|
|
|
$this->status = 'binding'; |
|
2696
|
|
|
$this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); |
|
2697
|
|
|
$this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); |
|
2698
|
|
|
} |
|
2699
|
|
|
break; |
|
2700
|
|
|
case 'service': |
|
2701
|
|
|
$this->serviceName = $attrs['name']; |
|
2702
|
|
|
$this->status = 'service'; |
|
2703
|
|
|
$this->debug('current service: ' . $this->serviceName); |
|
2704
|
|
|
break; |
|
2705
|
|
|
case 'definitions': |
|
2706
|
|
|
foreach ($attrs as $name => $value) { |
|
2707
|
|
|
$this->wsdl_info[$name] = $value; |
|
2708
|
|
|
} |
|
2709
|
|
|
break; |
|
2710
|
|
|
} |
|
2711
|
|
|
} |
|
2712
|
|
|
} |
|
2713
|
|
|
|
|
2714
|
|
|
/** |
|
2715
|
|
|
* end-element handler |
|
2716
|
|
|
* |
|
2717
|
|
|
* @param string $parser XML parser object |
|
2718
|
|
|
* @param string $name element name |
|
2719
|
|
|
* @access private |
|
2720
|
|
|
*/ |
|
2721
|
|
|
function end_element($parser, $name){ |
|
2722
|
|
|
// unset schema status |
|
2723
|
|
|
if (ereg('types$', $name) || ereg('schema$', $name)) { |
|
2724
|
|
|
$this->status = ""; |
|
2725
|
|
|
} |
|
2726
|
|
|
if ($this->status == 'schema') { |
|
2727
|
|
|
$this->schemaEndElement($parser, $name); |
|
2728
|
|
|
} else { |
|
2729
|
|
|
// bring depth down a notch |
|
2730
|
|
|
$this->depth--; |
|
2731
|
|
|
} |
|
2732
|
|
|
// end documentation |
|
2733
|
|
|
if ($this->documentation) { |
|
2734
|
|
|
$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; |
|
2735
|
|
|
$this->documentation = false; |
|
2736
|
|
|
} |
|
2737
|
|
|
} |
|
2738
|
|
|
|
|
2739
|
|
|
/** |
|
2740
|
|
|
* element content handler |
|
2741
|
|
|
* |
|
2742
|
|
|
* @param string $parser XML parser object |
|
2743
|
|
|
* @param string $data element content |
|
2744
|
|
|
* @access private |
|
2745
|
|
|
*/ |
|
2746
|
|
|
function character_data($parser, $data) |
|
2747
|
|
|
{ |
|
2748
|
|
|
$pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; |
|
2749
|
|
|
if (isset($this->message[$pos]['cdata'])) { |
|
2750
|
|
|
$this->message[$pos]['cdata'] .= $data; |
|
2751
|
|
|
} |
|
2752
|
|
|
if ($this->documentation) { |
|
2753
|
|
|
$this->documentation .= $data; |
|
2754
|
|
|
} |
|
2755
|
|
|
} |
|
2756
|
|
|
|
|
2757
|
|
|
function getBindingData($binding) |
|
2758
|
|
|
{ |
|
2759
|
|
|
if (is_array($this->bindings[$binding])) { |
|
2760
|
|
|
return $this->bindings[$binding]; |
|
2761
|
|
|
} |
|
2762
|
|
|
} |
|
2763
|
|
|
|
|
2764
|
|
|
/** |
|
2765
|
|
|
* returns an assoc array of operation names => operation data |
|
2766
|
|
|
* NOTE: currently only supports multiple services of differing binding types |
|
2767
|
|
|
* This method needs some work |
|
2768
|
|
|
* |
|
2769
|
|
|
* @param string $bindingType eg: soap, smtp, dime (only soap is currently supported) |
|
2770
|
|
|
* @return array |
|
2771
|
|
|
* @access public |
|
2772
|
|
|
*/ |
|
2773
|
|
|
function getOperations($bindingType = 'soap') |
|
2774
|
|
|
{ |
|
2775
|
|
|
if ($bindingType == 'soap') { |
|
2776
|
|
|
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; |
|
2777
|
|
|
} |
|
2778
|
|
|
// loop thru ports |
|
2779
|
|
|
foreach($this->ports as $port => $portData) { |
|
2780
|
|
|
// binding type of port matches parameter |
|
2781
|
|
|
if ($portData['bindingType'] == $bindingType) { |
|
2782
|
|
|
// get binding |
|
2783
|
|
|
return $this->bindings[ $portData['binding'] ]['operations']; |
|
2784
|
|
|
} |
|
2785
|
|
|
} |
|
2786
|
|
|
return array(); |
|
2787
|
|
|
} |
|
2788
|
|
|
|
|
2789
|
|
|
/** |
|
2790
|
|
|
* returns an associative array of data necessary for calling an operation |
|
2791
|
|
|
* |
|
2792
|
|
|
* @param string $operation , name of operation |
|
2793
|
|
|
* @param string $bindingType , type of binding eg: soap |
|
2794
|
|
|
* @return array |
|
2795
|
|
|
* @access public |
|
2796
|
|
|
*/ |
|
2797
|
|
|
function getOperationData($operation, $bindingType = 'soap') |
|
2798
|
|
|
{ |
|
2799
|
|
|
if ($bindingType == 'soap') { |
|
2800
|
|
|
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; |
|
2801
|
|
|
} |
|
2802
|
|
|
// loop thru ports |
|
2803
|
|
|
foreach($this->ports as $port => $portData) { |
|
2804
|
|
|
// binding type of port matches parameter |
|
2805
|
|
|
if ($portData['bindingType'] == $bindingType) { |
|
2806
|
|
|
// get binding |
|
2807
|
|
|
//foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { |
|
2808
|
|
|
foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { |
|
2809
|
|
|
if ($operation == $bOperation) { |
|
2810
|
|
|
$opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; |
|
2811
|
|
|
return $opData; |
|
2812
|
|
|
} |
|
2813
|
|
|
} |
|
2814
|
|
|
} |
|
2815
|
|
|
} |
|
2816
|
|
|
} |
|
2817
|
|
|
|
|
2818
|
|
|
/** |
|
2819
|
|
|
* serialize the parsed wsdl |
|
2820
|
|
|
* |
|
2821
|
|
|
* @return string , serialization of WSDL |
|
2822
|
|
|
* @access public |
|
2823
|
|
|
*/ |
|
2824
|
|
|
function serialize() |
|
2825
|
|
|
{ |
|
2826
|
|
|
$xml = '<?xml version="1.0"?><definitions'; |
|
2827
|
|
|
foreach($this->namespaces as $k => $v) { |
|
2828
|
|
|
$xml .= " xmlns:$k=\"$v\""; |
|
2829
|
|
|
} |
|
2830
|
|
|
// 10.9.02 - add poulter fix for wsdl and tns declarations |
|
2831
|
|
|
if (isset($this->namespaces['wsdl'])) { |
|
2832
|
|
|
$xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; |
|
2833
|
|
|
} |
|
2834
|
|
|
if (isset($this->namespaces['tns'])) { |
|
2835
|
|
|
$xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; |
|
2836
|
|
|
} |
|
2837
|
|
|
$xml .= '>'; |
|
2838
|
|
|
// imports |
|
2839
|
|
|
if (sizeof($this->import) > 0) { |
|
2840
|
|
|
foreach($this->import as $ns => $url) { |
|
2841
|
|
|
$xml .= '<import location="' . $url . '" namespace="' . $ns . '" />'; |
|
2842
|
|
|
} |
|
2843
|
|
|
} |
|
2844
|
|
|
// types |
|
2845
|
|
|
if (count($this->complexTypes)>=1) { |
|
2846
|
|
|
$xml .= '<types>'; |
|
2847
|
|
|
$xml .= $this->serializeSchema(); |
|
2848
|
|
|
$xml .= '</types>'; |
|
2849
|
|
|
} |
|
2850
|
|
|
// messages |
|
2851
|
|
|
if (count($this->messages) >= 1) { |
|
2852
|
|
|
foreach($this->messages as $msgName => $msgParts) { |
|
2853
|
|
|
$xml .= '<message name="' . $msgName . '">'; |
|
2854
|
|
|
foreach($msgParts as $partName => $partType) { |
|
2855
|
|
|
// print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; |
|
2856
|
|
|
if (strpos($partType, ':')) { |
|
2857
|
|
|
$typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); |
|
2858
|
|
|
} elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { |
|
2859
|
|
|
// print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; |
|
2860
|
|
|
$typePrefix = 'xsd'; |
|
2861
|
|
|
} else { |
|
2862
|
|
|
foreach($this->typemap as $ns => $types) { |
|
2863
|
|
|
if (isset($types[$partType])) { |
|
2864
|
|
|
$typePrefix = $this->getPrefixFromNamespace($ns); |
|
2865
|
|
|
} |
|
2866
|
|
|
} |
|
2867
|
|
|
if (!isset($typePrefix)) { |
|
2868
|
|
|
die("$partType has no namespace!"); |
|
|
|
|
|
|
2869
|
|
|
} |
|
2870
|
|
|
} |
|
2871
|
|
|
$xml .= '<part name="' . $partName . '" type="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />'; |
|
2872
|
|
|
} |
|
2873
|
|
|
$xml .= '</message>'; |
|
2874
|
|
|
} |
|
2875
|
|
|
} |
|
2876
|
|
|
// bindings & porttypes |
|
2877
|
|
|
if (count($this->bindings) >= 1) { |
|
2878
|
|
|
$binding_xml = ''; |
|
2879
|
|
|
$portType_xml = ''; |
|
2880
|
|
|
foreach($this->bindings as $bindingName => $attrs) { |
|
2881
|
|
|
$binding_xml .= '<binding name="' . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; |
|
2882
|
|
|
$binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; |
|
2883
|
|
|
$portType_xml .= '<portType name="' . $attrs['portType'] . '">'; |
|
2884
|
|
|
foreach($attrs['operations'] as $opName => $opParts) { |
|
2885
|
|
|
$binding_xml .= '<operation name="' . $opName . '">'; |
|
2886
|
|
|
$binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $attrs['style'] . '"/>'; |
|
2887
|
|
|
$binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '" encodingStyle="' . $opParts['input']['encodingStyle'] . '"/></input>'; |
|
2888
|
|
|
$binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '" encodingStyle="' . $opParts['output']['encodingStyle'] . '"/></output>'; |
|
2889
|
|
|
$binding_xml .= '</operation>'; |
|
2890
|
|
|
$portType_xml .= '<operation name="' . $opParts['name'] . '"'; |
|
2891
|
|
|
if (isset($opParts['parameterOrder'])) { |
|
2892
|
|
|
$portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; |
|
2893
|
|
|
} |
|
2894
|
|
|
$portType_xml .= '>'; |
|
2895
|
|
|
$portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>'; |
|
2896
|
|
|
$portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>'; |
|
2897
|
|
|
$portType_xml .= '</operation>'; |
|
2898
|
|
|
} |
|
2899
|
|
|
$portType_xml .= '</portType>'; |
|
2900
|
|
|
$binding_xml .= '</binding>'; |
|
2901
|
|
|
} |
|
2902
|
|
|
$xml .= $portType_xml . $binding_xml; |
|
2903
|
|
|
} |
|
2904
|
|
|
// services |
|
2905
|
|
|
$xml .= '<service name="' . $this->serviceName . '">'; |
|
2906
|
|
|
if (count($this->ports) >= 1) { |
|
2907
|
|
|
foreach($this->ports as $pName => $attrs) { |
|
2908
|
|
|
$xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; |
|
2909
|
|
|
$xml .= '<soap:address location="' . $attrs['location'] . '"/>'; |
|
2910
|
|
|
$xml .= '</port>'; |
|
2911
|
|
|
} |
|
2912
|
|
|
} |
|
2913
|
|
|
$xml .= '</service>'; |
|
2914
|
|
|
return $xml . '</definitions>'; |
|
2915
|
|
|
} |
|
2916
|
|
|
|
|
2917
|
|
|
/** |
|
2918
|
|
|
* serialize a PHP value according to a WSDL message definition |
|
2919
|
|
|
* |
|
2920
|
|
|
* TODO |
|
2921
|
|
|
* - multi-ref serialization |
|
2922
|
|
|
* - validate PHP values against type definitions, return errors if invalid |
|
2923
|
|
|
* |
|
2924
|
|
|
* @param string $ type name |
|
2925
|
|
|
* @param mixed $ param value |
|
2926
|
|
|
* @return mixed new param or false if initial value didn't validate |
|
2927
|
|
|
*/ |
|
2928
|
|
|
function serializeRPCParameters($operation, $direction, $parameters) |
|
2929
|
|
|
{ |
|
2930
|
|
|
$this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion); |
|
2931
|
|
|
|
|
2932
|
|
|
if ($direction != 'input' && $direction != 'output') { |
|
2933
|
|
|
$this->debug('The value of the \$direction argument needs to be either "input" or "output"'); |
|
2934
|
|
|
$this->setError('The value of the \$direction argument needs to be either "input" or "output"'); |
|
2935
|
|
|
return false; |
|
2936
|
|
|
} |
|
2937
|
|
|
if (!$opData = $this->getOperationData($operation)) { |
|
2938
|
|
|
$this->debug('Unable to retrieve WSDL data for operation: ' . $operation); |
|
2939
|
|
|
$this->setError('Unable to retrieve WSDL data for operation: ' . $operation); |
|
2940
|
|
|
return false; |
|
2941
|
|
|
} |
|
2942
|
|
|
$this->debug($this->varDump($opData)); |
|
2943
|
|
|
// set input params |
|
2944
|
|
|
$xml = ''; |
|
2945
|
|
|
if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { |
|
2946
|
|
|
|
|
2947
|
|
|
$use = $opData[$direction]['use']; |
|
2948
|
|
|
$this->debug("use=$use"); |
|
2949
|
|
|
$this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); |
|
2950
|
|
|
foreach($opData[$direction]['parts'] as $name => $type) { |
|
2951
|
|
|
$this->debug('serializing part "'.$name.'" of type "'.$type.'"'); |
|
2952
|
|
|
// NOTE: add error handling here |
|
2953
|
|
|
// if serializeType returns false, then catch global error and fault |
|
2954
|
|
|
if (isset($parameters[$name])) { |
|
2955
|
|
|
$this->debug('calling serializeType w/ named param'); |
|
2956
|
|
|
$xml .= $this->serializeType($name, $type, $parameters[$name], $use); |
|
2957
|
|
|
} elseif(is_array($parameters)) { |
|
2958
|
|
|
$this->debug('calling serializeType w/ unnamed param'); |
|
2959
|
|
|
$xml .= $this->serializeType($name, $type, array_shift($parameters), $use); |
|
2960
|
|
|
} else { |
|
2961
|
|
|
$this->debug('no parameters passed.'); |
|
2962
|
|
|
} |
|
2963
|
|
|
} |
|
2964
|
|
|
} |
|
2965
|
|
|
return $xml; |
|
2966
|
|
|
} |
|
2967
|
|
|
|
|
2968
|
|
|
/** |
|
2969
|
|
|
* serializes a PHP value according a given type definition |
|
2970
|
|
|
* |
|
2971
|
|
|
* @param string $name , name of type (part) |
|
2972
|
|
|
* @param string $type , type of type, heh (type or element) |
|
2973
|
|
|
* @param mixed $value , a native PHP value (parameter value) |
|
2974
|
|
|
* @param string $use , use for part (encoded|literal) |
|
2975
|
|
|
* @return string serialization |
|
2976
|
|
|
* @access public |
|
2977
|
|
|
*/ |
|
2978
|
|
|
function serializeType($name, $type, $value, $use='encoded') |
|
2979
|
|
|
{ |
|
2980
|
|
|
$this->debug("in serializeType: $name, $type, $value, $use"); |
|
2981
|
|
|
$xml = ''; |
|
2982
|
|
|
if (strpos($type, ':')) { |
|
2983
|
|
|
$uqType = substr($type, strrpos($type, ':') + 1); |
|
2984
|
|
|
$ns = substr($type, 0, strrpos($type, ':')); |
|
2985
|
|
|
$this->debug("got a prefixed type: $uqType, $ns"); |
|
2986
|
|
|
|
|
2987
|
|
|
if($ns == $this->XMLSchemaVersion || |
|
2988
|
|
|
($this->getNamespaceFromPrefix($ns)) == $this->XMLSchemaVersion){ |
|
2989
|
|
|
|
|
2990
|
|
|
if ($uqType == 'boolean' && !$value) { |
|
2991
|
|
|
$value = 0; |
|
2992
|
|
|
} elseif ($uqType == 'boolean') { |
|
2993
|
|
|
$value = 1; |
|
2994
|
|
|
} |
|
2995
|
|
|
if ($this->charencoding && $uqType == 'string' && gettype($value) == 'string') { |
|
2996
|
|
|
$value = htmlspecialchars($value); |
|
2997
|
|
|
} |
|
2998
|
|
|
// it's a scalar |
|
2999
|
|
|
if ($use == 'literal') { |
|
3000
|
|
|
return "<$name>$value</$name>"; |
|
3001
|
|
|
} else { |
|
3002
|
|
|
return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\">$value</$name>"; |
|
3003
|
|
|
} |
|
3004
|
|
|
} |
|
3005
|
|
|
} else { |
|
3006
|
|
|
$uqType = $type; |
|
3007
|
|
|
} |
|
3008
|
|
|
if(!$typeDef = $this->getTypeDef($uqType)){ |
|
3009
|
|
|
$this->setError("$uqType is not a supported type."); |
|
3010
|
|
|
return false; |
|
3011
|
|
|
} else { |
|
3012
|
|
|
//foreach($typeDef as $k => $v) { |
|
3013
|
|
|
//$this->debug("typedef, $k: $v"); |
|
3014
|
|
|
//} |
|
3015
|
|
|
} |
|
3016
|
|
|
$phpType = $typeDef['phpType']; |
|
3017
|
|
|
$this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); |
|
3018
|
|
|
// if php type == struct, map value to the <all> element names |
|
3019
|
|
|
if ($phpType == 'struct') { |
|
3020
|
|
|
if (isset($typeDef['element']) && $typeDef['element']) { |
|
3021
|
|
|
$elementName = $uqType; |
|
3022
|
|
|
// TODO: use elementFormDefault="qualified|unqualified" to determine |
|
3023
|
|
|
// how to scope the namespace |
|
3024
|
|
|
$elementNS = " xmlns=\"$ns\""; |
|
3025
|
|
|
} else { |
|
3026
|
|
|
$elementName = $name; |
|
3027
|
|
|
$elementNS = ''; |
|
3028
|
|
|
} |
|
3029
|
|
|
if ($use == 'literal') { |
|
3030
|
|
|
$xml = "<$elementName$elementNS>"; |
|
3031
|
|
|
} else { |
|
3032
|
|
|
$xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; |
|
3033
|
|
|
} |
|
3034
|
|
|
|
|
3035
|
|
|
if (isset($this->complexTypes[$uqType]['elements']) && is_array($this->complexTypes[$uqType]['elements'])) { |
|
3036
|
|
|
|
|
3037
|
|
|
//if (is_array($this->complexTypes[$uqType]['elements'])) { |
|
3038
|
|
|
// toggle whether all elements are present - ideally should validate against schema |
|
3039
|
|
|
if(count($this->complexTypes[$uqType]['elements']) != count($value)){ |
|
3040
|
|
|
$optionals = true; |
|
3041
|
|
|
} |
|
3042
|
|
|
foreach($this->complexTypes[$uqType]['elements'] as $eName => $attrs) { |
|
3043
|
|
|
// if user took advantage of a minOccurs=0, then only serialize named parameters |
|
3044
|
|
|
if(isset($optionals) && !isset($value[$eName])){ |
|
3045
|
|
|
// do nothing |
|
3046
|
|
|
} else { |
|
3047
|
|
|
// get value |
|
3048
|
|
|
if (isset($value[$eName])) { |
|
3049
|
|
|
$v = $value[$eName]; |
|
3050
|
|
|
} elseif (is_array($value)) { |
|
3051
|
|
|
$v = array_shift($value); |
|
3052
|
|
|
} |
|
3053
|
|
|
// serialize schema-defined type |
|
3054
|
|
|
if (!isset($attrs['type'])) { |
|
3055
|
|
|
$xml .= $this->serializeType($eName, $attrs['name'], $v, $use); |
|
3056
|
|
|
// serialize generic type |
|
3057
|
|
|
} else { |
|
3058
|
|
|
$this->debug("calling serialize_val() for $eName, $v, " . $this->getLocalPart($attrs['type']), false, $use); |
|
3059
|
|
|
$xml .= $this->serialize_val($v, $eName, $this->getLocalPart($attrs['type']), null, $this->getNamespaceFromPrefix($this->getPrefix($attrs['type'])), false, $use); |
|
3060
|
|
|
} |
|
3061
|
|
|
} |
|
3062
|
|
|
} |
|
3063
|
|
|
} |
|
3064
|
|
|
$xml .= "</$elementName>"; |
|
3065
|
|
|
} elseif ($phpType == 'array') { |
|
3066
|
|
|
$rows = sizeof($value); |
|
3067
|
|
|
if (isset($typeDef['multidimensional'])) { |
|
3068
|
|
|
$nv = array(); |
|
3069
|
|
|
foreach($value as $v) { |
|
3070
|
|
|
$cols = ',' . sizeof($v); |
|
3071
|
|
|
$nv = array_merge($nv, $v); |
|
3072
|
|
|
} |
|
3073
|
|
|
$value = $nv; |
|
3074
|
|
|
} else { |
|
3075
|
|
|
$cols = ''; |
|
3076
|
|
|
} |
|
3077
|
|
|
if (is_array($value) && sizeof($value) >= 1) { |
|
3078
|
|
|
$contents = ''; |
|
3079
|
|
|
foreach($value as $k => $v) { |
|
3080
|
|
|
$this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); |
|
3081
|
|
|
//if (strpos($typeDef['arrayType'], ':') ) { |
|
3082
|
|
|
if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { |
|
3083
|
|
|
$contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); |
|
3084
|
|
|
} else { |
|
3085
|
|
|
$contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); |
|
3086
|
|
|
} |
|
3087
|
|
|
} |
|
3088
|
|
|
$this->debug('contents: '.$this->varDump($contents)); |
|
3089
|
|
|
} else { |
|
3090
|
|
|
$contents = null; |
|
3091
|
|
|
} |
|
3092
|
|
|
if ($use == 'literal') { |
|
3093
|
|
|
$xml = "<$name>" |
|
3094
|
|
|
.$contents |
|
3095
|
|
|
."</$name>"; |
|
3096
|
|
|
} else { |
|
3097
|
|
|
$xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. |
|
3098
|
|
|
$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') |
|
3099
|
|
|
.':arrayType="' |
|
3100
|
|
|
.$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) |
|
3101
|
|
|
.":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" |
|
3102
|
|
|
.$contents |
|
3103
|
|
|
."</$name>"; |
|
3104
|
|
|
} |
|
3105
|
|
|
} |
|
3106
|
|
|
$this->debug('returning: '.$this->varDump($xml)); |
|
3107
|
|
|
return $xml; |
|
3108
|
|
|
} |
|
3109
|
|
|
|
|
3110
|
|
|
/** |
|
3111
|
|
|
* register a service with the server |
|
3112
|
|
|
* |
|
3113
|
|
|
* @param string $methodname |
|
|
|
|
|
|
3114
|
|
|
* @param string $in assoc array of input values: key = param name, value = param type |
|
3115
|
|
|
* @param string $out assoc array of output values: key = param name, value = param type |
|
3116
|
|
|
* @param string $namespace |
|
3117
|
|
|
* @param string $soapaction |
|
3118
|
|
|
* @param string $style (rpc|literal) |
|
3119
|
|
|
* @access public |
|
3120
|
|
|
*/ |
|
3121
|
|
|
function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '') |
|
3122
|
|
|
{ |
|
3123
|
|
|
if ($style == 'rpc' && $use == 'encoded') { |
|
3124
|
|
|
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; |
|
3125
|
|
|
} else { |
|
3126
|
|
|
$encodingStyle = ''; |
|
3127
|
|
|
} |
|
3128
|
|
|
// get binding |
|
3129
|
|
|
$this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = |
|
3130
|
|
|
array( |
|
3131
|
|
|
'name' => $name, |
|
3132
|
|
|
'binding' => $this->serviceName . 'Binding', |
|
3133
|
|
|
'endpoint' => $this->endpoint, |
|
3134
|
|
|
'soapAction' => $soapaction, |
|
3135
|
|
|
'style' => $style, |
|
3136
|
|
|
'input' => array( |
|
3137
|
|
|
'use' => $use, |
|
3138
|
|
|
'namespace' => $namespace, |
|
3139
|
|
|
'encodingStyle' => $encodingStyle, |
|
3140
|
|
|
'message' => $name . 'Request', |
|
3141
|
|
|
'parts' => $in), |
|
3142
|
|
|
'output' => array( |
|
3143
|
|
|
'use' => $use, |
|
3144
|
|
|
'namespace' => $namespace, |
|
3145
|
|
|
'encodingStyle' => $encodingStyle, |
|
3146
|
|
|
'message' => $name . 'Response', |
|
3147
|
|
|
'parts' => $out), |
|
3148
|
|
|
'namespace' => $namespace, |
|
3149
|
|
|
'transport' => 'http://schemas.xmlsoap.org/soap/http', |
|
3150
|
|
|
'documentation' => $documentation); |
|
3151
|
|
|
// add portTypes |
|
3152
|
|
|
// add messages |
|
3153
|
|
|
if($in) |
|
|
|
|
|
|
3154
|
|
|
{ |
|
3155
|
|
|
foreach($in as $pName => $pType) |
|
|
|
|
|
|
3156
|
|
|
{ |
|
3157
|
|
|
if(strpos($pType,':')) { |
|
3158
|
|
|
$pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); |
|
3159
|
|
|
} |
|
3160
|
|
|
$this->messages[$name.'Request'][$pName] = $pType; |
|
3161
|
|
|
} |
|
3162
|
|
|
} |
|
3163
|
|
|
|
|
3164
|
|
|
if($out) |
|
|
|
|
|
|
3165
|
|
|
{ |
|
3166
|
|
|
foreach($out as $pName => $pType) |
|
|
|
|
|
|
3167
|
|
|
{ |
|
3168
|
|
|
if(strpos($pType,':')) { |
|
3169
|
|
|
$pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); |
|
3170
|
|
|
} |
|
3171
|
|
|
$this->messages[$name.'Response'][$pName] = $pType; |
|
3172
|
|
|
} |
|
3173
|
|
|
} |
|
3174
|
|
|
return true; |
|
3175
|
|
|
} |
|
3176
|
|
|
} |
|
3177
|
|
|
|
|
3178
|
|
|
?><?php |
|
3179
|
|
|
|
|
3180
|
|
|
/** |
|
3181
|
|
|
* |
|
3182
|
|
|
* soap_parser class parses SOAP XML messages into native PHP values |
|
3183
|
|
|
* |
|
3184
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
3185
|
|
|
* @version v 0.6.3 |
|
3186
|
|
|
* @access public |
|
3187
|
|
|
*/ |
|
3188
|
|
|
class soap_parser extends nusoap_base { |
|
3189
|
|
|
|
|
3190
|
|
|
var $xml = ''; |
|
3191
|
|
|
var $xml_encoding = ''; |
|
3192
|
|
|
var $method = ''; |
|
3193
|
|
|
var $root_struct = ''; |
|
3194
|
|
|
var $root_struct_name = ''; |
|
3195
|
|
|
var $root_header = ''; |
|
3196
|
|
|
var $document = ''; |
|
3197
|
|
|
// determines where in the message we are (envelope,header,body,method) |
|
3198
|
|
|
var $status = ''; |
|
3199
|
|
|
var $position = 0; |
|
3200
|
|
|
var $depth = 0; |
|
3201
|
|
|
var $default_namespace = ''; |
|
3202
|
|
|
var $namespaces = array(); |
|
3203
|
|
|
var $message = array(); |
|
3204
|
|
|
var $parent = ''; |
|
3205
|
|
|
var $fault = false; |
|
3206
|
|
|
var $fault_code = ''; |
|
3207
|
|
|
var $fault_str = ''; |
|
3208
|
|
|
var $fault_detail = ''; |
|
3209
|
|
|
var $depth_array = array(); |
|
3210
|
|
|
var $debug_flag = true; |
|
3211
|
|
|
var $soapresponse = NULL; |
|
3212
|
|
|
var $responseHeaders = ''; |
|
3213
|
|
|
var $body_position = 0; |
|
3214
|
|
|
// for multiref parsing: |
|
3215
|
|
|
// array of id => pos |
|
3216
|
|
|
var $ids = array(); |
|
3217
|
|
|
// array of id => hrefs => pos |
|
3218
|
|
|
var $multirefs = array(); |
|
3219
|
|
|
|
|
3220
|
|
|
/** |
|
3221
|
|
|
* constructor |
|
3222
|
|
|
* |
|
3223
|
|
|
* @param string $xml SOAP message |
|
3224
|
|
|
* @param string $encoding character encoding scheme of message |
|
3225
|
|
|
* @access public |
|
3226
|
|
|
*/ |
|
3227
|
|
|
function soap_parser($xml,$encoding='UTF-8',$method=''){ |
|
3228
|
|
|
$this->xml = $xml; |
|
3229
|
|
|
$this->xml_encoding = $encoding; |
|
3230
|
|
|
$this->method = $method; |
|
3231
|
|
|
|
|
3232
|
|
|
// Check whether content has been read. |
|
3233
|
|
|
if(!empty($xml)){ |
|
3234
|
|
|
$this->debug('Entering soap_parser()'); |
|
3235
|
|
|
// Create an XML parser. |
|
3236
|
|
|
$this->parser = xml_parser_create($this->xml_encoding); |
|
3237
|
|
|
// Set the options for parsing the XML data. |
|
3238
|
|
|
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); |
|
3239
|
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
|
3240
|
|
|
// Set the object for the parser. |
|
3241
|
|
|
xml_set_object($this->parser, $this); |
|
3242
|
|
|
// Set the element handlers for the parser. |
|
3243
|
|
|
xml_set_element_handler($this->parser, 'start_element','end_element'); |
|
3244
|
|
|
xml_set_character_data_handler($this->parser,'character_data'); |
|
3245
|
|
|
|
|
3246
|
|
|
// Parse the XML file. |
|
3247
|
|
|
if(!xml_parse($this->parser,$xml,true)){ |
|
3248
|
|
|
// Display an error message. |
|
3249
|
|
|
$err = sprintf('XML error on line %d: %s', |
|
3250
|
|
|
xml_get_current_line_number($this->parser), |
|
3251
|
|
|
xml_error_string(xml_get_error_code($this->parser))); |
|
3252
|
|
|
$this->debug('parse error: '.$err); |
|
3253
|
|
|
$this->errstr = $err; |
|
3254
|
|
|
} else { |
|
3255
|
|
|
$this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); |
|
3256
|
|
|
// get final value |
|
3257
|
|
|
$this->soapresponse = $this->message[$this->root_struct]['result']; |
|
3258
|
|
|
// get header value |
|
3259
|
|
|
if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ |
|
3260
|
|
|
$this->responseHeaders = $this->message[$this->root_header]['result']; |
|
3261
|
|
|
} |
|
3262
|
|
|
// resolve hrefs/ids |
|
3263
|
|
|
if(sizeof($this->multirefs) > 0){ |
|
3264
|
|
|
foreach($this->multirefs as $id => $hrefs){ |
|
3265
|
|
|
$this->debug('resolving multirefs for id: '.$id); |
|
3266
|
|
|
$idVal = $this->buildVal($this->ids[$id]); |
|
3267
|
|
|
foreach($hrefs as $refPos => $ref){ |
|
3268
|
|
|
$this->debug('resolving href at pos '.$refPos); |
|
3269
|
|
|
$this->multirefs[$id][$refPos] = $idVal; |
|
3270
|
|
|
} |
|
3271
|
|
|
} |
|
3272
|
|
|
} |
|
3273
|
|
|
} |
|
3274
|
|
|
xml_parser_free($this->parser); |
|
3275
|
|
|
} else { |
|
3276
|
|
|
$this->debug('xml was empty, didn\'t parse!'); |
|
3277
|
|
|
$this->errstr = 'xml was empty, didn\'t parse!'; |
|
3278
|
|
|
} |
|
3279
|
|
|
} |
|
3280
|
|
|
|
|
3281
|
|
|
/** |
|
3282
|
|
|
* start-element handler |
|
3283
|
|
|
* |
|
3284
|
|
|
* @param string $parser XML parser object |
|
3285
|
|
|
* @param string $name element name |
|
3286
|
|
|
* @param string $attrs associative array of attributes |
|
3287
|
|
|
* @access private |
|
3288
|
|
|
*/ |
|
3289
|
|
|
function start_element($parser, $name, $attrs) { |
|
3290
|
|
|
// position in a total number of elements, starting from 0 |
|
3291
|
|
|
// update class level pos |
|
3292
|
|
|
$pos = $this->position++; |
|
3293
|
|
|
// and set mine |
|
3294
|
|
|
$this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); |
|
3295
|
|
|
// depth = how many levels removed from root? |
|
3296
|
|
|
// set mine as current global depth and increment global depth value |
|
3297
|
|
|
$this->message[$pos]['depth'] = $this->depth++; |
|
3298
|
|
|
|
|
3299
|
|
|
// else add self as child to whoever the current parent is |
|
3300
|
|
|
if($pos != 0){ |
|
3301
|
|
|
$this->message[$this->parent]['children'] .= '|'.$pos; |
|
3302
|
|
|
} |
|
3303
|
|
|
// set my parent |
|
3304
|
|
|
$this->message[$pos]['parent'] = $this->parent; |
|
3305
|
|
|
// set self as current parent |
|
3306
|
|
|
$this->parent = $pos; |
|
|
|
|
|
|
3307
|
|
|
// set self as current value for this depth |
|
3308
|
|
|
$this->depth_array[$this->depth] = $pos; |
|
3309
|
|
|
// get element prefix |
|
3310
|
|
|
if(strpos($name,':')){ |
|
3311
|
|
|
// get ns prefix |
|
3312
|
|
|
$prefix = substr($name,0,strpos($name,':')); |
|
3313
|
|
|
// get unqualified name |
|
3314
|
|
|
$name = substr(strstr($name,':'),1); |
|
3315
|
|
|
} |
|
3316
|
|
|
// set status |
|
3317
|
|
|
if($name == 'Envelope'){ |
|
3318
|
|
|
$this->status = 'envelope'; |
|
3319
|
|
|
} elseif($name == 'Header'){ |
|
3320
|
|
|
$this->root_header = $pos; |
|
|
|
|
|
|
3321
|
|
|
$this->status = 'header'; |
|
3322
|
|
|
} elseif($name == 'Body'){ |
|
3323
|
|
|
$this->status = 'body'; |
|
3324
|
|
|
$this->body_position = $pos; |
|
3325
|
|
|
// set method |
|
3326
|
|
|
} elseif($this->status == 'body' && $pos == ($this->body_position+1)){ |
|
3327
|
|
|
$this->status = 'method'; |
|
3328
|
|
|
$this->root_struct_name = $name; |
|
3329
|
|
|
$this->root_struct = $pos; |
|
|
|
|
|
|
3330
|
|
|
$this->message[$pos]['type'] = 'struct'; |
|
3331
|
|
|
$this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); |
|
3332
|
|
|
} |
|
3333
|
|
|
// set my status |
|
3334
|
|
|
$this->message[$pos]['status'] = $this->status; |
|
3335
|
|
|
// set name |
|
3336
|
|
|
$this->message[$pos]['name'] = htmlspecialchars($name); |
|
3337
|
|
|
// set attrs |
|
3338
|
|
|
$this->message[$pos]['attrs'] = $attrs; |
|
3339
|
|
|
|
|
3340
|
|
|
// loop through atts, logging ns and type declarations |
|
3341
|
|
|
$attstr = ''; |
|
3342
|
|
|
foreach($attrs as $key => $value){ |
|
|
|
|
|
|
3343
|
|
|
$key_prefix = $this->getPrefix($key); |
|
3344
|
|
|
$key_localpart = $this->getLocalPart($key); |
|
3345
|
|
|
// if ns declarations, add to class level array of valid namespaces |
|
3346
|
|
|
if($key_prefix == 'xmlns'){ |
|
3347
|
|
|
if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ |
|
3348
|
|
|
$this->XMLSchemaVersion = $value; |
|
3349
|
|
|
$this->namespaces['xsd'] = $this->XMLSchemaVersion; |
|
3350
|
|
|
$this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; |
|
3351
|
|
|
} |
|
3352
|
|
|
$this->namespaces[$key_localpart] = $value; |
|
3353
|
|
|
// set method namespace |
|
3354
|
|
|
if($name == $this->root_struct_name){ |
|
3355
|
|
|
$this->methodNamespace = $value; |
|
3356
|
|
|
} |
|
3357
|
|
|
// if it's a type declaration, set type |
|
3358
|
|
|
} elseif($key_localpart == 'type'){ |
|
3359
|
|
|
$value_prefix = $this->getPrefix($value); |
|
3360
|
|
|
$value_localpart = $this->getLocalPart($value); |
|
3361
|
|
|
$this->message[$pos]['type'] = $value_localpart; |
|
3362
|
|
|
$this->message[$pos]['typePrefix'] = $value_prefix; |
|
3363
|
|
|
if(isset($this->namespaces[$value_prefix])){ |
|
3364
|
|
|
$this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; |
|
3365
|
|
|
} else if(isset($attrs['xmlns:'.$value_prefix])) { |
|
3366
|
|
|
$this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; |
|
3367
|
|
|
} |
|
3368
|
|
|
// should do something here with the namespace of specified type? |
|
3369
|
|
|
} elseif($key_localpart == 'arrayType'){ |
|
3370
|
|
|
$this->message[$pos]['type'] = 'array'; |
|
3371
|
|
|
/* do arrayType ereg here |
|
3372
|
|
|
[1] arrayTypeValue ::= atype asize |
|
3373
|
|
|
[2] atype ::= QName rank* |
|
3374
|
|
|
[3] rank ::= '[' (',')* ']' |
|
3375
|
|
|
[4] asize ::= '[' length~ ']' |
|
3376
|
|
|
[5] length ::= nextDimension* Digit+ |
|
3377
|
|
|
[6] nextDimension ::= Digit+ ',' |
|
3378
|
|
|
*/ |
|
3379
|
|
|
$expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; |
|
3380
|
|
|
if(ereg($expr,$value,$regs)){ |
|
3381
|
|
|
$this->message[$pos]['typePrefix'] = $regs[1]; |
|
3382
|
|
|
$this->message[$pos]['arraySize'] = $regs[3]; |
|
3383
|
|
|
$this->message[$pos]['arrayCols'] = $regs[4]; |
|
3384
|
|
|
} |
|
3385
|
|
|
} |
|
3386
|
|
|
// log id |
|
3387
|
|
|
if($key == 'id'){ |
|
3388
|
|
|
$this->ids[$value] = $pos; |
|
3389
|
|
|
} |
|
3390
|
|
|
// root |
|
3391
|
|
|
if($key_localpart == 'root' && $value == 1){ |
|
3392
|
|
|
$this->status = 'method'; |
|
3393
|
|
|
$this->root_struct_name = $name; |
|
3394
|
|
|
$this->root_struct = $pos; |
|
3395
|
|
|
$this->debug("found root struct $this->root_struct_name, pos $pos"); |
|
3396
|
|
|
} |
|
3397
|
|
|
// for doclit |
|
3398
|
|
|
$attstr .= " $key=\"$value\""; |
|
3399
|
|
|
} |
|
3400
|
|
|
// get namespace - must be done after namespace atts are processed |
|
3401
|
|
|
if(isset($prefix)){ |
|
3402
|
|
|
$this->message[$pos]['namespace'] = $this->namespaces[$prefix]; |
|
3403
|
|
|
$this->default_namespace = $this->namespaces[$prefix]; |
|
3404
|
|
|
} else { |
|
3405
|
|
|
$this->message[$pos]['namespace'] = $this->default_namespace; |
|
3406
|
|
|
} |
|
3407
|
|
|
if($this->status == 'header'){ |
|
3408
|
|
|
$this->responseHeaders .= "<$name$attstr>"; |
|
3409
|
|
|
} elseif($this->root_struct_name != ''){ |
|
3410
|
|
|
$this->document .= "<$name$attstr>"; |
|
3411
|
|
|
} |
|
3412
|
|
|
} |
|
3413
|
|
|
|
|
3414
|
|
|
/** |
|
3415
|
|
|
* end-element handler |
|
3416
|
|
|
* |
|
3417
|
|
|
* @param string $parser XML parser object |
|
3418
|
|
|
* @param string $name element name |
|
3419
|
|
|
* @access private |
|
3420
|
|
|
*/ |
|
3421
|
|
|
function end_element($parser, $name) { |
|
3422
|
|
|
// position of current element is equal to the last value left in depth_array for my depth |
|
3423
|
|
|
$pos = $this->depth_array[$this->depth--]; |
|
3424
|
|
|
|
|
3425
|
|
|
// get element prefix |
|
3426
|
|
|
if(strpos($name,':')){ |
|
3427
|
|
|
// get ns prefix |
|
3428
|
|
|
$prefix = substr($name,0,strpos($name,':')); |
|
3429
|
|
|
// get unqualified name |
|
3430
|
|
|
$name = substr(strstr($name,':'),1); |
|
3431
|
|
|
} |
|
3432
|
|
|
|
|
3433
|
|
|
// build to native type |
|
3434
|
|
|
if(isset($this->body_position) && $pos > $this->body_position){ |
|
3435
|
|
|
// deal w/ multirefs |
|
3436
|
|
|
if(isset($this->message[$pos]['attrs']['href'])){ |
|
3437
|
|
|
// get id |
|
3438
|
|
|
$id = substr($this->message[$pos]['attrs']['href'],1); |
|
3439
|
|
|
// add placeholder to href array |
|
3440
|
|
|
$this->multirefs[$id][$pos] = "placeholder"; |
|
3441
|
|
|
// add set a reference to it as the result value |
|
3442
|
|
|
$this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; |
|
3443
|
|
|
// build complex values |
|
3444
|
|
|
} elseif($this->message[$pos]['children'] != ""){ |
|
3445
|
|
|
$this->message[$pos]['result'] = $this->buildVal($pos); |
|
3446
|
|
|
} else { |
|
3447
|
|
|
$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); |
|
3448
|
|
|
if(is_numeric($this->message[$pos]['cdata']) ){ |
|
3449
|
|
|
if( strpos($this->message[$pos]['cdata'],'.') ){ |
|
3450
|
|
|
$this->message[$pos]['result'] = doubleval($this->message[$pos]['cdata']); |
|
3451
|
|
|
} else { |
|
3452
|
|
|
$this->message[$pos]['result'] = intval($this->message[$pos]['cdata']); |
|
3453
|
|
|
} |
|
3454
|
|
|
} else { |
|
3455
|
|
|
$this->message[$pos]['result'] = $this->message[$pos]['cdata']; |
|
3456
|
|
|
} |
|
3457
|
|
|
} |
|
3458
|
|
|
} |
|
3459
|
|
|
|
|
3460
|
|
|
// switch status |
|
3461
|
|
|
if($pos == $this->root_struct){ |
|
3462
|
|
|
$this->status = 'body'; |
|
3463
|
|
|
} elseif($name == 'Body'){ |
|
3464
|
|
|
$this->status = 'header'; |
|
3465
|
|
|
} elseif($name == 'Header'){ |
|
3466
|
|
|
$this->status = 'envelope'; |
|
3467
|
|
|
} elseif($name == 'Envelope'){ |
|
3468
|
|
|
// |
|
3469
|
|
|
} |
|
3470
|
|
|
// set parent back to my parent |
|
3471
|
|
|
$this->parent = $this->message[$pos]['parent']; |
|
3472
|
|
|
// for doclit |
|
3473
|
|
|
if($this->status == 'header'){ |
|
3474
|
|
|
$this->responseHeaders .= "</$name>"; |
|
3475
|
|
|
} elseif($pos >= $this->root_struct){ |
|
3476
|
|
|
$this->document .= "</$name>"; |
|
3477
|
|
|
} |
|
3478
|
|
|
} |
|
3479
|
|
|
|
|
3480
|
|
|
/** |
|
3481
|
|
|
* element content handler |
|
3482
|
|
|
* |
|
3483
|
|
|
* @param string $parser XML parser object |
|
3484
|
|
|
* @param string $data element content |
|
3485
|
|
|
* @access private |
|
3486
|
|
|
*/ |
|
3487
|
|
|
function character_data($parser, $data){ |
|
3488
|
|
|
$pos = $this->depth_array[$this->depth]; |
|
3489
|
|
|
if ($this->xml_encoding=='UTF-8'){ |
|
3490
|
|
|
$data = utf8_decode($data); |
|
3491
|
|
|
} |
|
3492
|
|
|
$this->message[$pos]['cdata'] .= $data; |
|
3493
|
|
|
// for doclit |
|
3494
|
|
|
if($this->status == 'header'){ |
|
3495
|
|
|
$this->responseHeaders .= $data; |
|
3496
|
|
|
} else { |
|
3497
|
|
|
$this->document .= $data; |
|
3498
|
|
|
} |
|
3499
|
|
|
} |
|
3500
|
|
|
|
|
3501
|
|
|
/** |
|
3502
|
|
|
* get the parsed message |
|
3503
|
|
|
* |
|
3504
|
|
|
* @return mixed |
|
3505
|
|
|
* @access public |
|
3506
|
|
|
*/ |
|
3507
|
|
|
function get_response(){ |
|
3508
|
|
|
return $this->soapresponse; |
|
3509
|
|
|
} |
|
3510
|
|
|
|
|
3511
|
|
|
/** |
|
3512
|
|
|
* get the parsed headers |
|
3513
|
|
|
* |
|
3514
|
|
|
* @return string XML or empty if no headers |
|
3515
|
|
|
* @access public |
|
3516
|
|
|
*/ |
|
3517
|
|
|
function getHeaders(){ |
|
3518
|
|
|
return $this->responseHeaders; |
|
3519
|
|
|
} |
|
3520
|
|
|
|
|
3521
|
|
|
/** |
|
3522
|
|
|
* decodes entities |
|
3523
|
|
|
* |
|
3524
|
|
|
* @param string $text string to translate |
|
3525
|
|
|
* @access private |
|
3526
|
|
|
*/ |
|
3527
|
|
|
function decode_entities($text){ |
|
3528
|
|
|
foreach($this->entities as $entity => $encoded){ |
|
3529
|
|
|
$text = str_replace($encoded,$entity,$text); |
|
3530
|
|
|
} |
|
3531
|
|
|
return $text; |
|
3532
|
|
|
} |
|
3533
|
|
|
|
|
3534
|
|
|
/** |
|
3535
|
|
|
* builds response structures for compound values (arrays/structs) |
|
3536
|
|
|
* |
|
3537
|
|
|
* @param string $pos position in node tree |
|
3538
|
|
|
* @access private |
|
3539
|
|
|
*/ |
|
3540
|
|
|
function buildVal($pos){ |
|
3541
|
|
|
if(!isset($this->message[$pos]['type'])){ |
|
3542
|
|
|
$this->message[$pos]['type'] = ''; |
|
3543
|
|
|
} |
|
3544
|
|
|
$this->debug('inside buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); |
|
3545
|
|
|
// if there are children... |
|
3546
|
|
|
if($this->message[$pos]['children'] != ''){ |
|
3547
|
|
|
$children = explode('|',$this->message[$pos]['children']); |
|
3548
|
|
|
array_shift($children); // knock off empty |
|
3549
|
|
|
// md array |
|
3550
|
|
|
if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ |
|
3551
|
|
|
$r=0; // rowcount |
|
3552
|
|
|
$c=0; // colcount |
|
3553
|
|
|
foreach($children as $child_pos){ |
|
3554
|
|
|
$this->debug("got an MD array element: $r, $c"); |
|
3555
|
|
|
$params[$r][] = $this->message[$child_pos]['result']; |
|
3556
|
|
|
$c++; |
|
3557
|
|
|
if($c == $this->message[$pos]['arrayCols']){ |
|
3558
|
|
|
$c = 0; |
|
3559
|
|
|
$r++; |
|
3560
|
|
|
} |
|
3561
|
|
|
} |
|
3562
|
|
|
// array |
|
3563
|
|
|
} elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ |
|
3564
|
|
|
$this->debug('adding array '.$this->message[$pos]['name']); |
|
3565
|
|
|
foreach($children as $child_pos){ |
|
3566
|
|
|
$params[] = &$this->message[$child_pos]['result']; |
|
3567
|
|
|
} |
|
3568
|
|
|
// apache Map type: java hashtable |
|
3569
|
|
|
} elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ |
|
3570
|
|
|
foreach($children as $child_pos){ |
|
3571
|
|
|
$kv = explode("|",$this->message[$child_pos]['children']); |
|
3572
|
|
|
$params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; |
|
3573
|
|
|
} |
|
3574
|
|
|
// generic compound type |
|
3575
|
|
|
//} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { |
|
3576
|
|
|
} else { |
|
3577
|
|
|
// is array or struct? better way to do this probably |
|
3578
|
|
|
foreach($children as $child_pos){ |
|
3579
|
|
|
if(isset($keys) && isset($keys[$this->message[$child_pos]['name']])){ |
|
3580
|
|
|
$struct = 1; |
|
3581
|
|
|
break; |
|
3582
|
|
|
} |
|
3583
|
|
|
$keys[$this->message[$child_pos]['name']] = 1; |
|
3584
|
|
|
} |
|
3585
|
|
|
// |
|
3586
|
|
|
foreach($children as $child_pos){ |
|
3587
|
|
|
if(isset($struct)){ |
|
3588
|
|
|
$params[] = &$this->message[$child_pos]['result']; |
|
3589
|
|
|
} else { |
|
3590
|
|
|
$params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; |
|
3591
|
|
|
} |
|
3592
|
|
|
} |
|
3593
|
|
|
} |
|
3594
|
|
|
return is_array($params) ? $params : array(); |
|
3595
|
|
|
} else { |
|
3596
|
|
|
$this->debug('no children'); |
|
3597
|
|
|
if(strpos($this->message[$pos]['cdata'],'&')){ |
|
3598
|
|
|
return strtr($this->message[$pos]['cdata'],array_flip($this->entities)); |
|
3599
|
|
|
} else { |
|
3600
|
|
|
return $this->message[$pos]['cdata']; |
|
3601
|
|
|
} |
|
3602
|
|
|
} |
|
3603
|
|
|
} |
|
3604
|
|
|
} |
|
3605
|
|
|
|
|
3606
|
|
|
|
|
3607
|
|
|
|
|
3608
|
|
|
?><?php |
|
3609
|
|
|
|
|
3610
|
|
|
|
|
3611
|
|
|
|
|
3612
|
|
|
/** |
|
3613
|
|
|
* |
|
3614
|
|
|
* soapclient higher level class for easy usage. |
|
3615
|
|
|
* |
|
3616
|
|
|
* usage: |
|
3617
|
|
|
* |
|
3618
|
|
|
* // instantiate client with server info |
|
3619
|
|
|
* $soapclient = new soapclient( string path [ ,boolean wsdl] ); |
|
3620
|
|
|
* |
|
3621
|
|
|
* // call method, get results |
|
3622
|
|
|
* echo $soapclient->call( string methodname [ ,array parameters] ); |
|
3623
|
|
|
* |
|
3624
|
|
|
* // bye bye client |
|
3625
|
|
|
* unset($soapclient); |
|
3626
|
|
|
* |
|
3627
|
|
|
* @author Dietrich Ayala <[email protected]> |
|
3628
|
|
|
* @version v 0.6.3 |
|
3629
|
|
|
* @access public |
|
3630
|
|
|
*/ |
|
3631
|
|
|
class soapclient extends nusoap_base { |
|
3632
|
|
|
|
|
3633
|
|
|
var $username = ''; |
|
3634
|
|
|
var $password = ''; |
|
3635
|
|
|
var $requestHeaders = false; |
|
3636
|
|
|
var $responseHeaders; |
|
3637
|
|
|
var $endpoint; |
|
3638
|
|
|
var $error_str = false; |
|
3639
|
|
|
var $proxyhost = ''; |
|
3640
|
|
|
var $proxyport = ''; |
|
3641
|
|
|
var $xml_encoding = ''; |
|
3642
|
|
|
var $http_encoding = false; |
|
3643
|
|
|
var $timeout = 0; |
|
3644
|
|
|
var $endpointType = ''; |
|
3645
|
|
|
var $persistentConnection = false; |
|
3646
|
|
|
var $defaultRpcParams = false; |
|
3647
|
|
|
|
|
3648
|
|
|
/** |
|
3649
|
|
|
* fault related variables |
|
3650
|
|
|
* |
|
3651
|
|
|
* @var fault |
|
3652
|
|
|
* @var faultcode |
|
3653
|
|
|
* @var faultstring |
|
3654
|
|
|
* @var faultdetail |
|
3655
|
|
|
* @access public |
|
3656
|
|
|
*/ |
|
3657
|
|
|
var $fault, $faultcode, $faultstring, $faultdetail; |
|
3658
|
|
|
|
|
3659
|
|
|
/** |
|
3660
|
|
|
* constructor |
|
3661
|
|
|
* |
|
3662
|
|
|
* @param string $endpoint SOAP server or WSDL URL |
|
3663
|
|
|
* @param bool $wsdl optional, set to true if using WSDL |
|
3664
|
|
|
* @param int $portName optional portName in WSDL document |
|
|
|
|
|
|
3665
|
|
|
* @access public |
|
3666
|
|
|
*/ |
|
3667
|
|
|
function soapclient($endpoint,$wsdl = false){ |
|
3668
|
|
|
$this->endpoint = $endpoint; |
|
3669
|
|
|
|
|
3670
|
|
|
// make values |
|
3671
|
|
|
if ($wsdl){ |
|
3672
|
|
|
$this->endpointType = 'wsdl'; |
|
3673
|
|
|
$this->wsdlFile = $this->endpoint; |
|
3674
|
|
|
|
|
3675
|
|
|
// instantiate wsdl object and parse wsdl file |
|
3676
|
|
|
$this->debug('instantiating wsdl class with doc: '.$endpoint); |
|
3677
|
|
|
$this->wsdl = new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport); |
|
3678
|
|
|
$this->debug("wsdl debug: \n".$this->wsdl->debug_str); |
|
3679
|
|
|
$this->wsdl->debug_str = ''; |
|
3680
|
|
|
// catch errors |
|
3681
|
|
|
if($errstr = $this->wsdl->getError()){ |
|
3682
|
|
|
$this->debug('got wsdl error: '.$errstr); |
|
3683
|
|
|
$this->setError('wsdl error: '.$errstr); |
|
3684
|
|
|
} elseif($this->operations = $this->wsdl->getOperations()){ |
|
3685
|
|
|
$this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile); |
|
3686
|
|
|
} else { |
|
3687
|
|
|
$this->debug( 'getOperations returned false'); |
|
3688
|
|
|
$this->setError('no operations defined in the WSDL document!'); |
|
3689
|
|
|
} |
|
3690
|
|
|
} |
|
3691
|
|
|
} |
|
3692
|
|
|
|
|
3693
|
|
|
/** |
|
3694
|
|
|
* calls method, returns PHP native type |
|
3695
|
|
|
* |
|
3696
|
|
|
* @param string $method SOAP server URL or path |
|
|
|
|
|
|
3697
|
|
|
* @param array $params array of parameters, can be associative or not |
|
3698
|
|
|
* @param string $namespace optional method namespace |
|
3699
|
|
|
* @param string $soapAction optional SOAPAction value |
|
3700
|
|
|
* @param boolean $headers optional array of soapval objects for headers |
|
3701
|
|
|
* @param boolean $rpcParams optional treat params as RPC for use="literal" |
|
3702
|
|
|
* This can be used on a per-call basis to overrider defaultRpcParams. |
|
3703
|
|
|
* @return mixed |
|
3704
|
|
|
* @access public |
|
3705
|
|
|
*/ |
|
3706
|
|
|
function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null){ |
|
3707
|
|
|
$this->operation = $operation; |
|
3708
|
|
|
$this->fault = false; |
|
3709
|
|
|
$this->error_str = ''; |
|
|
|
|
|
|
3710
|
|
|
$this->request = ''; |
|
3711
|
|
|
$this->response = ''; |
|
3712
|
|
|
$this->faultstring = ''; |
|
3713
|
|
|
$this->faultcode = ''; |
|
3714
|
|
|
$this->opData = array(); |
|
3715
|
|
|
|
|
3716
|
|
|
$this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $rpcParams"); |
|
3717
|
|
|
$this->debug("endpointType: $this->endpointType"); |
|
3718
|
|
|
// if wsdl, get operation data and process parameters |
|
3719
|
|
|
if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ |
|
3720
|
|
|
|
|
3721
|
|
|
$this->opData = $opData; |
|
3722
|
|
|
foreach($opData as $key => $value){ |
|
3723
|
|
|
$this->debug("$key -> $value"); |
|
3724
|
|
|
} |
|
3725
|
|
|
$soapAction = $opData['soapAction']; |
|
3726
|
|
|
$this->endpoint = $opData['endpoint']; |
|
3727
|
|
|
$namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : 'http://testuri.org'; |
|
3728
|
|
|
$style = $opData['style']; |
|
3729
|
|
|
// add ns to ns array |
|
3730
|
|
|
if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ |
|
3731
|
|
|
$this->wsdl->namespaces['nu'] = $namespace; |
|
3732
|
|
|
} |
|
3733
|
|
|
// serialize payload |
|
3734
|
|
|
|
|
3735
|
|
|
if($opData['input']['use'] == 'literal') { |
|
3736
|
|
|
if (is_null($rpcParams)) { |
|
3737
|
|
|
$rpcParams = $this->defaultRpcParams; |
|
3738
|
|
|
} |
|
3739
|
|
|
if ($rpcParams) { |
|
3740
|
|
|
$this->debug("serializing literal params for operation $operation"); |
|
3741
|
|
|
$payload = $this->wsdl->serializeRPCParameters($operation,'input',$params); |
|
3742
|
|
|
$defaultNamespace = $this->wsdl->wsdl_info['targetNamespace']; |
|
3743
|
|
|
} else { |
|
3744
|
|
|
$this->debug("serializing literal document for operation $operation"); |
|
3745
|
|
|
$payload = is_array($params) ? array_shift($params) : $params; |
|
3746
|
|
|
} |
|
3747
|
|
|
} else { |
|
3748
|
|
|
$this->debug("serializing encoded params for operation $operation"); |
|
3749
|
|
|
$payload = "<".$this->wsdl->getPrefixFromNamespace($namespace).":$operation>". |
|
3750
|
|
|
$this->wsdl->serializeRPCParameters($operation,'input',$params). |
|
3751
|
|
|
'</'.$this->wsdl->getPrefixFromNamespace($namespace).":$operation>"; |
|
3752
|
|
|
} |
|
3753
|
|
|
$this->debug('payload size: '.strlen($payload)); |
|
3754
|
|
|
// serialize envelope |
|
3755
|
|
|
$soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$this->wsdl->usedNamespaces,$style); |
|
3756
|
|
|
$this->debug("wsdl debug: \n".$this->wsdl->debug_str); |
|
3757
|
|
|
$this->wsdl->debug_str = ''; |
|
3758
|
|
|
} elseif($this->endpointType == 'wsdl') { |
|
3759
|
|
|
$this->setError( 'operation '.$operation.' not present.'); |
|
3760
|
|
|
$this->debug("operation '$operation' not present."); |
|
3761
|
|
|
$this->debug("wsdl debug: \n".$this->wsdl->debug_str); |
|
3762
|
|
|
return false; |
|
3763
|
|
|
// no wsdl |
|
3764
|
|
|
} else { |
|
3765
|
|
|
// make message |
|
3766
|
|
|
if(!isset($style)){ |
|
|
|
|
|
|
3767
|
|
|
$style = 'rpc'; |
|
3768
|
|
|
} |
|
3769
|
|
|
if($namespace == ''){ |
|
3770
|
|
|
$namespace = 'http://testuri.org'; |
|
3771
|
|
|
$this->wsdl->namespaces['ns1'] = $namespace; |
|
3772
|
|
|
} |
|
3773
|
|
|
// serialize envelope |
|
3774
|
|
|
$payload = ''; |
|
3775
|
|
|
foreach($params as $k => $v){ |
|
3776
|
|
|
$payload .= $this->serialize_val($v,$k); |
|
3777
|
|
|
} |
|
3778
|
|
|
$payload = "<ns1:$operation xmlns:ns1=\"$namespace\">\n".$payload."</ns1:$operation>\n"; |
|
3779
|
|
|
$soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders); |
|
3780
|
|
|
} |
|
3781
|
|
|
$this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace"); |
|
3782
|
|
|
// send |
|
3783
|
|
|
$this->debug('sending msg (len: '.strlen($soapmsg).") w/ soapaction '$soapAction'..."); |
|
3784
|
|
|
$return = $this->send($soapmsg,$soapAction,$this->timeout); |
|
3785
|
|
|
if($errstr = $this->getError()){ |
|
3786
|
|
|
$this->debug('Error: '.$errstr); |
|
3787
|
|
|
return false; |
|
3788
|
|
|
} else { |
|
3789
|
|
|
$this->return = $return; |
|
3790
|
|
|
$this->debug('sent message successfully and got a(n) '.gettype($return).' back'); |
|
3791
|
|
|
|
|
3792
|
|
|
// fault? |
|
3793
|
|
|
if(is_array($return) && isset($return['faultcode'])){ |
|
3794
|
|
|
$this->debug('got fault'); |
|
3795
|
|
|
$this->setError($return['faultcode'].': '.$return['faultstring']); |
|
3796
|
|
|
$this->fault = true; |
|
3797
|
|
|
foreach($return as $k => $v){ |
|
3798
|
|
|
$this->$k = $v; |
|
3799
|
|
|
$this->debug("$k = $v<br>"); |
|
3800
|
|
|
} |
|
3801
|
|
|
return $return; |
|
3802
|
|
|
} else { |
|
3803
|
|
|
// array of return values |
|
3804
|
|
|
if(is_array($return)){ |
|
3805
|
|
|
// multiple 'out' parameters |
|
3806
|
|
|
if(sizeof($return) > 1){ |
|
3807
|
|
|
return $return; |
|
3808
|
|
|
} |
|
3809
|
|
|
// single 'out' parameter |
|
3810
|
|
|
return array_shift($return); |
|
3811
|
|
|
// nothing returned (ie, echoVoid) |
|
3812
|
|
|
} else { |
|
3813
|
|
|
return ""; |
|
3814
|
|
|
} |
|
3815
|
|
|
} |
|
3816
|
|
|
} |
|
3817
|
|
|
} |
|
3818
|
|
|
|
|
3819
|
|
|
/** |
|
3820
|
|
|
* get available data pertaining to an operation |
|
3821
|
|
|
* |
|
3822
|
|
|
* @param string $operation operation name |
|
3823
|
|
|
* @return array array of data pertaining to the operation |
|
3824
|
|
|
* @access public |
|
3825
|
|
|
*/ |
|
3826
|
|
|
function getOperationData($operation){ |
|
3827
|
|
|
if(isset($this->operations[$operation])){ |
|
3828
|
|
|
return $this->operations[$operation]; |
|
3829
|
|
|
} |
|
3830
|
|
|
$this->debug("No data for operation: $operation"); |
|
3831
|
|
|
} |
|
3832
|
|
|
|
|
3833
|
|
|
/** |
|
3834
|
|
|
* send the SOAP message |
|
3835
|
|
|
* |
|
3836
|
|
|
* Note: if the operation has multiple return values |
|
3837
|
|
|
* the return value of this method will be an array |
|
3838
|
|
|
* of those values. |
|
3839
|
|
|
* |
|
3840
|
|
|
* @param string $msg a SOAPx4 soapmsg object |
|
3841
|
|
|
* @param string $soapaction SOAPAction value |
|
3842
|
|
|
* @param integer $timeout set timeout in seconds |
|
3843
|
|
|
* @return mixed native PHP types. |
|
3844
|
|
|
* @access private |
|
3845
|
|
|
*/ |
|
3846
|
|
|
function send($msg, $soapaction = '', $timeout=0) { |
|
3847
|
|
|
// detect transport |
|
3848
|
|
|
switch(true){ |
|
|
|
|
|
|
3849
|
|
|
// http(s) |
|
3850
|
|
|
case ereg('^http',$this->endpoint): |
|
3851
|
|
|
$this->debug('transporting via HTTP'); |
|
3852
|
|
|
if($this->persistentConnection && is_object($this->persistentConnection)){ |
|
3853
|
|
|
$http =& $this->persistentConnection; |
|
3854
|
|
|
} else { |
|
3855
|
|
|
$http = new soap_transport_http($this->endpoint); |
|
3856
|
|
|
// pass encoding into transport layer, so appropriate http headers are sent |
|
3857
|
|
|
$http->soap_defencoding = $this->soap_defencoding; |
|
3858
|
|
|
} |
|
3859
|
|
|
$http->setSOAPAction($soapaction); |
|
3860
|
|
|
if($this->proxyhost && $this->proxyport){ |
|
3861
|
|
|
$http->setProxy($this->proxyhost,$this->proxyport); |
|
3862
|
|
|
} |
|
3863
|
|
|
if($this->username != '' && $this->password != '') { |
|
3864
|
|
|
$http->setCredentials($this->username,$this->password); |
|
3865
|
|
|
} |
|
3866
|
|
|
if($this->http_encoding != ''){ |
|
3867
|
|
|
$http->setEncoding($this->http_encoding); |
|
3868
|
|
|
} |
|
3869
|
|
|
$this->debug('sending message, length: '.strlen($msg)); |
|
3870
|
|
|
if(ereg('^http:',$this->endpoint)){ |
|
3871
|
|
|
//if(strpos($this->endpoint,'http:')){ |
|
3872
|
|
|
$response = $http->send($msg,$timeout); |
|
3873
|
|
|
} elseif(ereg('^https',$this->endpoint)){ |
|
3874
|
|
|
//} elseif(strpos($this->endpoint,'https:')){ |
|
3875
|
|
|
//if(phpversion() == '4.3.0-dev'){ |
|
3876
|
|
|
//$response = $http->send($msg,$timeout); |
|
3877
|
|
|
//$this->request = $http->outgoing_payload; |
|
3878
|
|
|
//$this->response = $http->incoming_payload; |
|
3879
|
|
|
//} else |
|
3880
|
|
|
if (extension_loaded('curl')) { |
|
3881
|
|
|
$response = $http->sendHTTPS($msg,$timeout); |
|
3882
|
|
|
} else { |
|
3883
|
|
|
$this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); |
|
3884
|
|
|
} |
|
3885
|
|
|
} else { |
|
3886
|
|
|
$this->setError('no http/s in endpoint url'); |
|
3887
|
|
|
} |
|
3888
|
|
|
$this->request = $http->outgoing_payload; |
|
3889
|
|
|
$this->response = $http->incoming_payload; |
|
3890
|
|
|
$this->debug("transport debug data...\n".$http->debug_str); |
|
3891
|
|
|
// save transport object if using persistent connections |
|
3892
|
|
|
if($this->persistentConnection && !is_object($this->persistentConnection)){ |
|
3893
|
|
|
$this->persistentConnection = $http; |
|
3894
|
|
|
} |
|
3895
|
|
|
if($err = $http->getError()){ |
|
3896
|
|
|
$this->setError('HTTP Error: '.$err); |
|
3897
|
|
|
return false; |
|
3898
|
|
|
} elseif($this->getError()){ |
|
3899
|
|
|
return false; |
|
3900
|
|
|
} else { |
|
3901
|
|
|
$this->debug('got response, length: '.strlen($response)); |
|
3902
|
|
|
return $this->parseResponse($response); |
|
3903
|
|
|
} |
|
3904
|
|
|
break; |
|
|
|
|
|
|
3905
|
|
|
default: |
|
3906
|
|
|
$this->setError('no transport found, or selected transport is not yet supported!'); |
|
3907
|
|
|
return false; |
|
3908
|
|
|
break; |
|
|
|
|
|
|
3909
|
|
|
} |
|
3910
|
|
|
} |
|
3911
|
|
|
|
|
3912
|
|
|
/** |
|
3913
|
|
|
* processes SOAP message returned from server |
|
3914
|
|
|
* |
|
3915
|
|
|
* @param string unprocessed response data from server |
|
3916
|
|
|
* @return mixed value of the message, decoded into a PHP type |
|
3917
|
|
|
* @access private |
|
3918
|
|
|
*/ |
|
3919
|
|
|
function parseResponse($data) { |
|
3920
|
|
|
$this->debug('Entering parseResponse(), about to create soap_parser instance'); |
|
3921
|
|
|
$parser = new soap_parser($data,$this->xml_encoding,$this->operation); |
|
3922
|
|
|
// if parse errors |
|
3923
|
|
|
if($errstr = $parser->getError()){ |
|
3924
|
|
|
$this->setError( $errstr); |
|
3925
|
|
|
// destroy the parser object |
|
3926
|
|
|
unset($parser); |
|
3927
|
|
|
return false; |
|
3928
|
|
|
} else { |
|
3929
|
|
|
// get SOAP headers |
|
3930
|
|
|
$this->responseHeaders = $parser->getHeaders(); |
|
3931
|
|
|
// get decoded message |
|
3932
|
|
|
$return = $parser->get_response(); |
|
3933
|
|
|
// add parser debug data to our debug |
|
3934
|
|
|
$this->debug($parser->debug_str); |
|
3935
|
|
|
// add document for doclit support |
|
3936
|
|
|
$this->document = $parser->document; |
|
3937
|
|
|
// destroy the parser object |
|
3938
|
|
|
unset($parser); |
|
3939
|
|
|
// return decode message |
|
3940
|
|
|
return $return; |
|
3941
|
|
|
} |
|
3942
|
|
|
} |
|
3943
|
|
|
|
|
3944
|
|
|
/** |
|
3945
|
|
|
* set the SOAP headers |
|
3946
|
|
|
* |
|
3947
|
|
|
* @param $headers string XML |
|
3948
|
|
|
* @access public |
|
3949
|
|
|
*/ |
|
3950
|
|
|
function setHeaders($headers){ |
|
3951
|
|
|
$this->requestHeaders = $headers; |
|
3952
|
|
|
} |
|
3953
|
|
|
|
|
3954
|
|
|
/** |
|
3955
|
|
|
* get the response headers |
|
3956
|
|
|
* |
|
3957
|
|
|
* @return mixed object SOAPx4 soapval object or empty if no headers |
|
3958
|
|
|
* @access public |
|
3959
|
|
|
*/ |
|
3960
|
|
|
function getHeaders(){ |
|
3961
|
|
|
if($this->responseHeaders != '') { |
|
3962
|
|
|
return $this->responseHeaders; |
|
3963
|
|
|
} |
|
3964
|
|
|
} |
|
3965
|
|
|
|
|
3966
|
|
|
/** |
|
3967
|
|
|
* set proxy info here |
|
3968
|
|
|
* |
|
3969
|
|
|
* @param string $proxyhost |
|
3970
|
|
|
* @param string $proxyport |
|
3971
|
|
|
* @access public |
|
3972
|
|
|
*/ |
|
3973
|
|
|
function setHTTPProxy($proxyhost, $proxyport) { |
|
3974
|
|
|
$this->proxyhost = $proxyhost; |
|
3975
|
|
|
$this->proxyport = $proxyport; |
|
3976
|
|
|
} |
|
3977
|
|
|
|
|
3978
|
|
|
/** |
|
3979
|
|
|
* if authenticating, set user credentials here |
|
3980
|
|
|
* |
|
3981
|
|
|
* @param string $username |
|
3982
|
|
|
* @param string $password |
|
3983
|
|
|
* @access public |
|
3984
|
|
|
*/ |
|
3985
|
|
|
function setCredentials($username, $password) { |
|
3986
|
|
|
$this->username = $username; |
|
3987
|
|
|
$this->password = $password; |
|
3988
|
|
|
} |
|
3989
|
|
|
|
|
3990
|
|
|
/** |
|
3991
|
|
|
* use HTTP encoding |
|
3992
|
|
|
* |
|
3993
|
|
|
* @param string $enc |
|
3994
|
|
|
* @access public |
|
3995
|
|
|
*/ |
|
3996
|
|
|
function setHTTPEncoding($enc='gzip, deflate'){ |
|
3997
|
|
|
$this->http_encoding = $enc; |
|
|
|
|
|
|
3998
|
|
|
} |
|
3999
|
|
|
|
|
4000
|
|
|
/** |
|
4001
|
|
|
* use HTTP persistent connections if possible |
|
4002
|
|
|
* |
|
4003
|
|
|
* @access public |
|
4004
|
|
|
*/ |
|
4005
|
|
|
function useHTTPPersistentConnection(){ |
|
4006
|
|
|
$this->persistentConnection = true; |
|
4007
|
|
|
} |
|
4008
|
|
|
|
|
4009
|
|
|
/** |
|
4010
|
|
|
* gets the default RPC parameter setting. |
|
4011
|
|
|
* If true, default is that call params are like RPC even for document style. |
|
4012
|
|
|
* Each call() can override this value. |
|
4013
|
|
|
* |
|
4014
|
|
|
* @access public |
|
4015
|
|
|
*/ |
|
4016
|
|
|
function getDefaultRpcParams() { |
|
4017
|
|
|
return $this->defaultRpcParams; |
|
4018
|
|
|
} |
|
4019
|
|
|
|
|
4020
|
|
|
/** |
|
4021
|
|
|
* sets the default RPC parameter setting. |
|
4022
|
|
|
* If true, default is that call params are like RPC even for document style |
|
4023
|
|
|
* Each call() can override this value. |
|
4024
|
|
|
* |
|
4025
|
|
|
* @param boolean $rpcParams |
|
4026
|
|
|
* @access public |
|
4027
|
|
|
*/ |
|
4028
|
|
|
function setDefaultRpcParams($rpcParams) { |
|
4029
|
|
|
$this->defaultRpcParams = $rpcParams; |
|
4030
|
|
|
} |
|
4031
|
|
|
|
|
4032
|
|
|
/** |
|
4033
|
|
|
* dynamically creates proxy class, allowing user to directly call methods from wsdl |
|
4034
|
|
|
* |
|
4035
|
|
|
* @return object soap_proxy object |
|
4036
|
|
|
* @access public |
|
4037
|
|
|
*/ |
|
4038
|
|
|
function getProxy(){ |
|
4039
|
|
|
$evalStr = ''; |
|
4040
|
|
|
foreach($this->operations as $operation => $opData){ |
|
4041
|
|
|
if($operation != ''){ |
|
4042
|
|
|
// create param string |
|
4043
|
|
|
$paramStr = ''; |
|
4044
|
|
|
if(sizeof($opData['input']['parts']) > 0){ |
|
4045
|
|
|
foreach($opData['input']['parts'] as $name => $type){ |
|
4046
|
|
|
$paramStr .= "\$$name,"; |
|
4047
|
|
|
} |
|
4048
|
|
|
$paramStr = substr($paramStr,0,strlen($paramStr)-1); |
|
4049
|
|
|
} |
|
4050
|
|
|
$opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; |
|
4051
|
|
|
$evalStr .= "function $operation ($paramStr){ |
|
4052
|
|
|
// load params into array |
|
4053
|
|
|
\$params = array($paramStr); |
|
4054
|
|
|
return \$this->call('$operation',\$params,'".$opData['namespace']."','".$opData['soapAction']."'); |
|
4055
|
|
|
}"; |
|
4056
|
|
|
unset($paramStr); |
|
4057
|
|
|
} |
|
4058
|
|
|
} |
|
4059
|
|
|
$r = rand(); |
|
4060
|
|
|
$evalStr = 'class soap_proxy_'.$r.' extends soapclient { |
|
4061
|
|
|
'.$evalStr.' |
|
4062
|
|
|
}'; |
|
4063
|
|
|
//print "proxy class:<pre>$evalStr</pre>"; |
|
4064
|
|
|
// eval the class |
|
4065
|
|
|
eval($evalStr); |
|
|
|
|
|
|
4066
|
|
|
// instantiate proxy object |
|
4067
|
|
|
eval("\$proxy = new soap_proxy_$r('');"); |
|
|
|
|
|
|
4068
|
|
|
// transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice |
|
4069
|
|
|
$proxy->endpointType = 'wsdl'; |
|
|
|
|
|
|
4070
|
|
|
$proxy->wsdlFile = $this->wsdlFile; |
|
4071
|
|
|
$proxy->wsdl = $this->wsdl; |
|
4072
|
|
|
$proxy->operations = $this->operations; |
|
4073
|
|
|
$proxy->defaultRpcParams = $this->defaultRpcParams; |
|
4074
|
|
|
return $proxy; |
|
4075
|
|
|
} |
|
4076
|
|
|
} |
|
4077
|
|
|
|
|
4078
|
|
|
// Local Variables: |
|
4079
|
|
|
// mode: php |
|
4080
|
|
|
// tab-width: 8 |
|
4081
|
|
|
// c-basic-offset: 4 |
|
4082
|
|
|
// c-hanging-comment-ender-p: nil |
|
4083
|
|
|
// indent-tabs-mode: nil |
|
4084
|
|
|
// End: |
|
4085
|
|
|
?> |