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
|
|
|
?> |