ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
nusoap.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4 $Id$
5 
6 NuSOAP - Web Services Toolkit for PHP
7 
8 Copyright (c) 2002 NuSphere Corporation
9 
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14 
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 
24 If you have any questions or comments, please email:
25 
26 Dietrich Ayala
27 dietrich@ganx4.com
28 http://dietrich.ganx4.com/nusoap
29 
30 NuSphere Corporation
31 http://www.nusphere.com
32 
33 */
34 
35 /* load classes
36 
37 // necessary classes
38 require_once('class.soapclient.php');
39 require_once('class.soap_val.php');
40 require_once('class.soap_parser.php');
41 require_once('class.soap_fault.php');
42 
43 // transport classes
44 require_once('class.soap_transport_http.php');
45 
46 // optional add-on classes
47 require_once('class.xmlschema.php');
48 require_once('class.wsdl.php');
49 
50 // server class
51 require_once('class.soap_server.php');*/
52 
61 class nusoap_base {
62 
63  var $title = 'NuSOAP';
64  var $version = '0.6.7';
65  var $revision = '$Revision$';
66  var $error_str = false;
67  var $debug_str = '';
68  // toggles automatic encoding of special characters as entities
69  // (should always be true, I think)
70  var $charencoding = true;
71 
78  var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
79 
86  var $soap_defencoding = 'UTF-8';
87  #var $soap_defencoding = 'ISO-8859-1';
88 
95  var $namespaces = array(
96  'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
97  'xsd' => 'http://www.w3.org/2001/XMLSchema',
98  'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
99  'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
100  'si' => 'http://soapinterop.org/xsd');
101  var $usedNamespaces = array();
102 
110  var $typemap = array(
111  'http://www.w3.org/2001/XMLSchema' => array(
112  'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
113  'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
114  'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
115  // derived datatypes
116  'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
117  'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
118  'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
119  'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
120  'http://www.w3.org/1999/XMLSchema' => 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 
135  var $xmlEntities = array('quot' => '"','amp' => '&',
136  'lt' => '<','gt' => '>','apos' => "'");
137 
144  function debug($string){
145  $this->debug_str .= get_class($this).": $string\n";
146  }
147 
154  function expandEntities($val) {
155  if ($this->charencoding) {
156  $val = str_replace('&', '&amp;', $val);
157  $val = str_replace("'", '&apos;', $val);
158  $val = str_replace('"', '&quot;', $val);
159  $val = str_replace('<', '&lt;', $val);
160  $val = str_replace('>', '&gt;', $val);
161  }
162  return $val;
163  }
164 
171  function getError(){
172  if($this->error_str != ''){
173  return $this->error_str;
174  }
175  return false;
176  }
177 
184  function setError($str){
185  $this->error_str = $str;
186  }
187 
195  function isArraySimpleOrStruct($val) {
196  $keyList = array_keys($val);
197  foreach ($keyList as $keyListValue) {
198  if (!is_int($keyListValue)) {
199  return 'arrayStruct';
200  }
201  }
202  return 'arraySimple';
203  }
204 
212  function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
213  if(is_object($val) && get_class($val) == 'soapval'){
214  return $val->serialize($use);
215  }
216  $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
217  // if no name, use item
218  $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
219  // if name has ns, add ns prefix to name
220  $xmlns = '';
221  if($name_ns){
222  $prefix = 'nu'.rand(1000,9999);
223  $name = $prefix.':'.$name;
224  $xmlns .= " xmlns:$prefix=\"$name_ns\"";
225  }
226  // if type is prefixed, create type prefix
227  if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
228  // need to fix this. shouldn't default to xsd if no ns specified
229  // w/o checking against typemap
230  $type_prefix = 'xsd';
231  } elseif($type_ns){
232  $type_prefix = 'ns'.rand(1000,9999);
233  $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
234  }
235  // serialize attributes if present
236  $atts = '';
237  if($attributes){
238  foreach($attributes as $k => $v){
239  $atts .= " $k=\"$v\"";
240  }
241  }
242  // serialize if an xsd built-in primitive type
243  if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
244  if (is_bool($val)) {
245  if ($type == 'boolean') {
246  $val = $val ? 'true' : 'false';
247  } elseif (! $val) {
248  $val = 0;
249  }
250  } else if (is_string($val)) {
251  $val = $this->expandEntities($val);
252  }
253  if ($use == 'literal') {
254  return "<$name$xmlns>$val</$name>";
255  } else {
256  return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>";
257  }
258  }
259  // detect type and serialize
260  $xml = '';
261  switch(true) {
262  case ($type == '' && is_null($val)):
263  if ($use == 'literal') {
264  // TODO: depends on nillable
265  $xml .= "<$name$xmlns/>";
266  } else {
267  $xml .= "<$name$xmlns xsi:nil=\"true\"/>";
268  }
269  break;
270  case (is_bool($val) || $type == 'boolean'):
271  if ($type == 'boolean') {
272  $val = $val ? 'true' : 'false';
273  } elseif (! $val) {
274  $val = 0;
275  }
276  if ($use == 'literal') {
277  $xml .= "<$name$xmlns $atts>$val</$name>";
278  } else {
279  $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
280  }
281  break;
282  case (is_int($val) || is_long($val) || $type == 'int'):
283  if ($use == 'literal') {
284  $xml .= "<$name$xmlns $atts>$val</$name>";
285  } else {
286  $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
287  }
288  break;
289  case (is_float($val)|| is_double($val) || $type == 'float'):
290  if ($use == 'literal') {
291  $xml .= "<$name$xmlns $atts>$val</$name>";
292  } else {
293  $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
294  }
295  break;
296  case (is_string($val) || $type == 'string'):
297  $val = $this->expandEntities($val);
298  if ($use == 'literal') {
299  $xml .= "<$name$xmlns $atts>$val</$name>";
300  } else {
301  $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
302  }
303  break;
304  case is_object($val):
305  $name = get_class($val);
306  foreach(get_object_vars($val) as $k => $v){
307  $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
308  }
309  $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
310  break;
311  break;
312  case (is_array($val) || $type):
313  // detect if struct or array
314  $valueType = $this->isArraySimpleOrStruct($val);
315  if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
316  $i = 0;
317  if(is_array($val) && count($val)> 0){
318  foreach($val as $v){
319  if(is_object($v) && get_class($v) == 'soapval'){
320  $tt_ns = $v->type_ns;
321  $tt = $v->type;
322  } elseif (is_array($v)) {
323  $tt = $this->isArraySimpleOrStruct($v);
324  } else {
325  $tt = gettype($v);
326  }
327  $array_types[$tt] = 1;
328  $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
329  ++$i;
330  }
331  if(count($array_types) > 1){
332  $array_typename = 'xsd:ur-type';
333  } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
334  if ($tt == 'integer') {
335  $tt = 'int';
336  }
337  $array_typename = 'xsd:'.$tt;
338  } elseif(isset($tt) && $tt == 'arraySimple'){
339  $array_typename = 'SOAP-ENC:Array';
340  } elseif(isset($tt) && $tt == 'arrayStruct'){
341  $array_typename = 'unnamed_struct_use_soapval';
342  } else {
343  // if type is prefixed, create type prefix
344  if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
345  $array_typename = 'xsd:' . $tt;
346  } elseif ($tt_ns) {
347  $tt_prefix = 'ns' . rand(1000, 9999);
348  $array_typename = "$tt_prefix:$tt";
349  $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
350  } else {
351  $array_typename = $tt;
352  }
353  }
354  $array_type = $i;
355  if ($use == 'literal') {
356  $type_str = '';
357  } else if (isset($type) && isset($type_prefix)) {
358  $type_str = " xsi:type=\"$type_prefix:$type\"";
359  } else {
360  $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
361  }
362  // empty array
363  } else {
364  if ($use == 'literal') {
365  $type_str = '';
366  } else if (isset($type) && isset($type_prefix)) {
367  $type_str = " xsi:type=\"$type_prefix:$type\"";
368  } else {
369  $type_str = " xsi:type=\"SOAP-ENC:Array\"";
370  }
371  }
372  $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
373  } else {
374  // got a struct
375  if(isset($type) && isset($type_prefix)){
376  $type_str = " xsi:type=\"$type_prefix:$type\"";
377  } else {
378  $type_str = '';
379  }
380  if ($use == 'literal') {
381  $xml .= "<$name$xmlns $atts>";
382  } else {
383  $xml .= "<$name$xmlns$type_str$atts>";
384  }
385  foreach($val as $k => $v){
386  // Apache Map
387  if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
388  $xml .= '<item>';
389  $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
390  $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
391  $xml .= '</item>';
392  } else {
393  $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
394  }
395  }
396  $xml .= "</$name>";
397  }
398  break;
399  default:
400  $xml .= 'not detected, got '.gettype($val).' for '.$val;
401  break;
402  }
403  return $xml;
404  }
405 
417  function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded'){
418  // TODO: add an option to automatically run utf8_encode on $body and $headers
419  // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
420  // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
421 
422  // serialize namespaces
423  $ns_string = '';
424  foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
425  $ns_string .= " xmlns:$k=\"$v\"";
426  }
427  if($style == 'rpc' && $use == 'encoded') {
428  $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
429  }
430 
431  // serialize headers
432  if($headers){
433  $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
434  }
435  // serialize envelope
436  return
437  '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
438  '<SOAP-ENV:Envelope'.$ns_string.">".
439  $headers.
440  "<SOAP-ENV:Body>".
441  $body.
442  "</SOAP-ENV:Body>".
443  "</SOAP-ENV:Envelope>";
444  }
445 
446  function formatDump($str){
447  $str = htmlspecialchars($str);
448  return nl2br($str);
449  }
450 
458  function contractQname($qname){
459  // get element namespace
460  //$this->xdebug("Contract $qname");
461  if (strrpos($qname, ':')) {
462  // get unqualified name
463  $name = substr($qname, strrpos($qname, ':') + 1);
464  // get ns
465  $ns = substr($qname, 0, strrpos($qname, ':'));
466  $p = $this->getPrefixFromNamespace($ns);
467  if ($p) {
468  return $p . ':' . $name;
469  }
470  return $qname;
471  } else {
472  return $qname;
473  }
474  }
475 
483  function expandQname($qname){
484  // get element prefix
485  if(strpos($qname,':') && !ereg('^http://',$qname)){
486  // get unqualified name
487  $name = substr(strstr($qname,':'),1);
488  // get ns prefix
489  $prefix = substr($qname,0,strpos($qname,':'));
490  if(isset($this->namespaces[$prefix])){
491  return $this->namespaces[$prefix].':'.$name;
492  } else {
493  return $qname;
494  }
495  } else {
496  return $qname;
497  }
498  }
499 
508  function getLocalPart($str){
509  if($sstr = strrchr($str,':')){
510  // get unqualified name
511  return substr( $sstr, 1 );
512  } else {
513  return $str;
514  }
515  }
516 
525  function getPrefix($str){
526  if($pos = strrpos($str,':')){
527  // get prefix
528  return substr($str,0,$pos);
529  }
530  return false;
531  }
532 
541  function getNamespaceFromPrefix($prefix){
542  if (isset($this->namespaces[$prefix])) {
543  return $this->namespaces[$prefix];
544  }
545  //$this->setError("No namespace registered for prefix '$prefix'");
546  return false;
547  }
548 
557  function getPrefixFromNamespace($ns) {
558  foreach ($this->namespaces as $p => $n) {
559  if ($ns == $n || $ns == $p) {
560  $this->usedNamespaces[$p] = $n;
561  return $p;
562  }
563  }
564  return false;
565  }
566 
567  function varDump($data) {
568  ob_start();
569  var_dump($data);
570  $ret_val = ob_get_contents();
571  ob_end_clean();
572  return $ret_val;
573  }
574 }
575 
576 // XML Schema Datatype Helper Functions
577 
578 //xsd:dateTime helpers
579 
586 function timestamp_to_iso8601($timestamp,$utc=true){
587  $datestr = date('Y-m-d\TH:i:sO',$timestamp);
588  if($utc){
589  $eregStr =
590  '([0-9]{4})-'. // centuries & years CCYY-
591  '([0-9]{2})-'. // months MM-
592  '([0-9]{2})'. // days DD
593  'T'. // separator T
594  '([0-9]{2}):'. // hours hh:
595  '([0-9]{2}):'. // minutes mm:
596  '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
597  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
598 
599  if(ereg($eregStr,$datestr,$regs)){
600  return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
601  }
602  return false;
603  } else {
604  return $datestr;
605  }
606 }
607 
614 function iso8601_to_timestamp($datestr){
615  $eregStr =
616  '([0-9]{4})-'. // centuries & years CCYY-
617  '([0-9]{2})-'. // months MM-
618  '([0-9]{2})'. // days DD
619  'T'. // separator T
620  '([0-9]{2}):'. // hours hh:
621  '([0-9]{2}):'. // minutes mm:
622  '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
623  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
624  if(ereg($eregStr,$datestr,$regs)){
625  // not utc
626  if($regs[8] != 'Z'){
627  $op = substr($regs[8],0,1);
628  $h = substr($regs[8],1,2);
629  $m = substr($regs[8],strlen($regs[8])-2,2);
630  if($op == '-'){
631  $regs[4] = $regs[4] + $h;
632  $regs[5] = $regs[5] + $m;
633  } elseif($op == '+'){
634  $regs[4] = $regs[4] - $h;
635  $regs[5] = $regs[5] - $m;
636  }
637  }
638  return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
639  } else {
640  return false;
641  }
642 }
643 
644 function usleepWindows($usec)
645 {
646  $start = gettimeofday();
647 
648  do
649  {
650  $stop = gettimeofday();
651  $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
652  + $stop['usec'] - $start['usec'];
653  }
654  while ($timePassed < $usec);
655 }
656 
657 ?><?php
658 
659 
660 
669 class soap_fault extends nusoap_base {
670 
675 
685  $this->faultcode = $faultcode;
686  $this->faultactor = $faultactor;
687  $this->faultstring = $faultstring;
688  $this->faultdetail = $faultdetail;
689  }
690 
696  function serialize(){
697  $ns_string = '';
698  foreach($this->namespaces as $k => $v){
699  $ns_string .= "\n xmlns:$k=\"$v\"";
700  }
701  $return_msg =
702  '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
703  '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
704  '<SOAP-ENV:Body>'.
705  '<SOAP-ENV:Fault>'.
706  '<faultcode>'.$this->expandEntities($this->faultcode).'</faultcode>'.
707  '<faultactor>'.$this->expandEntities($this->faultactor).'</faultactor>'.
708  '<faultstring>'.$this->expandEntities($this->faultstring).'</faultstring>'.
709  '<detail>'.$this->serialize_val($this->faultdetail).'</detail>'.
710  '</SOAP-ENV:Fault>'.
711  '</SOAP-ENV:Body>'.
712  '</SOAP-ENV:Envelope>';
713  return $return_msg;
714  }
715 }
716 
717 
718 
719 ?><?php
720 
721 
722 
734 class XMLSchema extends nusoap_base {
735 
736  // files
737  var $schema = '';
738  var $xml = '';
739  // namespaces
741  // schema info
742  var $schemaInfo = array();
744  // types, elements, attributes defined by the schema
745  var $attributes = array();
746  var $complexTypes = array();
747  var $currentComplexType = false;
748  var $elements = array();
749  var $currentElement = false;
750  var $simpleTypes = array();
751  var $currentSimpleType = false;
752  // imports
753  var $imports = array();
754  // parser vars
755  var $parser;
756  var $position = 0;
757  var $depth = 0;
758  var $depth_array = array();
759  var $message = array();
760  var $defaultNamespace = array();
761 
770  function XMLSchema($schema='',$xml='',$namespaces=array()){
771 
772  $this->debug('xmlschema class instantiated, inside constructor');
773  // files
774  $this->schema = $schema;
775  $this->xml = $xml;
776 
777  // namespaces
778  $this->enclosingNamespaces = $namespaces;
779  $this->namespaces = array_merge($this->namespaces, $namespaces);
780 
781  // parse schema file
782  if($schema != ''){
783  $this->debug('initial schema file: '.$schema);
784  $this->parseFile($schema, 'schema');
785  }
786 
787  // parse xml file
788  if($xml != ''){
789  $this->debug('initial xml file: '.$xml);
790  $this->parseFile($xml, 'xml');
791  }
792 
793  }
794 
803  function parseFile($xml,$type){
804  // parse xml file
805  if($xml != ""){
806  $xmlStr = @join("",@file($xml));
807  if($xmlStr == ""){
808  $msg = 'Error reading XML from '.$xml;
809  $this->setError($msg);
810  $this->debug($msg);
811  return false;
812  } else {
813  $this->debug("parsing $xml");
814  $this->parseString($xmlStr,$type);
815  $this->debug("done parsing $xml");
816  return true;
817  }
818  }
819  return false;
820  }
821 
829  function parseString($xml,$type){
830  // parse xml string
831  if($xml != ""){
832 
833  // Create an XML parser.
834  $this->parser = xml_parser_create();
835  // Set the options for parsing the XML data.
836  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
837 
838  // Set the object for the parser.
839  xml_set_object($this->parser, $this);
840 
841  // Set the element handlers for the parser.
842  if($type == "schema"){
843  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
844  xml_set_character_data_handler($this->parser,'schemaCharacterData');
845  } elseif($type == "xml"){
846  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
847  xml_set_character_data_handler($this->parser,'xmlCharacterData');
848  }
849 
850  // Parse the XML file.
851  if(!xml_parse($this->parser,$xml,true)){
852  // Display an error message.
853  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
854  xml_get_current_line_number($this->parser),
855  xml_error_string(xml_get_error_code($this->parser))
856  );
857  $this->debug($errstr);
858  $this->debug("XML payload:\n" . $xml);
859  $this->setError($errstr);
860  }
861 
862  xml_parser_free($this->parser);
863  } else{
864  $this->debug('no xml passed to parseString()!!');
865  $this->setError('no xml passed to parseString()!!');
866  }
867  }
868 
877  function schemaStartElement($parser, $name, $attrs) {
878 
879  // position in the total number of elements, starting from 0
880  $pos = $this->position++;
881  $depth = $this->depth++;
882  // set self as current value for this depth
883  $this->depth_array[$depth] = $pos;
884  $this->message[$pos] = array('cdata' => '');
885  if ($depth > 0) {
886  $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
887  } else {
888  $this->defaultNamespace[$pos] = false;
889  }
890 
891  // get element prefix
892  if($prefix = $this->getPrefix($name)){
893  // get unqualified name
894  $name = $this->getLocalPart($name);
895  } else {
896  $prefix = '';
897  }
898 
899  // loop thru attributes, expanding, and registering namespace declarations
900  if(count($attrs) > 0){
901  foreach($attrs as $k => $v){
902  // if ns declarations, add to class level array of valid namespaces
903  if(ereg("^xmlns",$k)){
904  //$this->xdebug("$k: $v");
905  //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
906  if($ns_prefix = substr(strrchr($k,':'),1)){
907  //$this->xdebug("Add namespace[$ns_prefix] = $v");
908  $this->namespaces[$ns_prefix] = $v;
909  } else {
910  $this->defaultNamespace[$pos] = $v;
911  if (! $this->getPrefixFromNamespace($v)) {
912  $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
913  }
914  }
915  if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){
916  $this->XMLSchemaVersion = $v;
917  $this->namespaces['xsi'] = $v.'-instance';
918  }
919  }
920  }
921  foreach($attrs as $k => $v){
922  // expand each attribute
923  $k = strpos($k,':') ? $this->expandQname($k) : $k;
924  $v = strpos($v,':') ? $this->expandQname($v) : $v;
925  $eAttrs[$k] = $v;
926  }
927  $attrs = $eAttrs;
928  } else {
929  $attrs = array();
930  }
931  // find status, register data
932  switch($name){
933  case 'all':
934  case 'choice':
935  case 'sequence':
936  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
937  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
938  if($name == 'all' || $name == 'sequence'){
939  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
940  }
941  break;
942  case 'attribute':
943  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
944  $this->xdebug("parsing attribute " . $this->varDump($attrs));
945  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
946  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
947  if (!strpos($v, ':')) {
948  // no namespace in arrayType attribute value...
949  if ($this->defaultNamespace[$pos]) {
950  // ...so use the default
951  $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
952  }
953  }
954  }
955  if(isset($attrs['name'])){
956  $this->attributes[$attrs['name']] = $attrs;
957  $aname = $attrs['name'];
958  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
959  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
960  $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
961  } else {
962  $aname = '';
963  }
964  } elseif(isset($attrs['ref'])){
965  $aname = $attrs['ref'];
966  $this->attributes[$attrs['ref']] = $attrs;
967  }
968 
969  if(isset($this->currentComplexType)){
970  $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
971  } elseif(isset($this->currentElement)){
972  $this->elements[$this->currentElement]['attrs'][$aname] = $attrs;
973  }
974  // arrayType attribute
975  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
976  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
977  $prefix = $this->getPrefix($aname);
978  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
979  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
980  } else {
981  $v = '';
982  }
983  if(strpos($v,'[,]')){
984  $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
985  }
986  $v = substr($v,0,strpos($v,'[')); // clip the []
987  if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
988  $v = $this->XMLSchemaVersion.':'.$v;
989  }
990  $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
991  }
992  break;
993  case 'complexType':
994  if(isset($attrs['name'])){
995  $this->xdebug('processing named complexType '.$attrs['name']);
996  $this->currentElement = false;
997  $this->currentComplexType = $attrs['name'];
998  $this->complexTypes[$this->currentComplexType] = $attrs;
999  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1000  if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1001  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1002  } else {
1003  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1004  }
1005  }else{
1006  $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
1007  $this->currentComplexType = $this->currentElement . '_ContainedType';
1008  $this->currentElement = false;
1009  $this->complexTypes[$this->currentComplexType] = $attrs;
1010  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1011  if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1012  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1013  } else {
1014  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1015  }
1016  }
1017  break;
1018  case 'element':
1019  // elements defined as part of a complex type should
1020  // not really be added to $this->elements, but for some
1021  // reason, they are
1022  if(isset($attrs['type'])){
1023  $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1024  $this->currentElement = $attrs['name'];
1025  $this->elements[ $attrs['name'] ] = $attrs;
1026  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1027  if (!isset($this->elements[ $attrs['name'] ]['form'])) {
1028  $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
1029  }
1030  $ename = $attrs['name'];
1031  } elseif(isset($attrs['ref'])){
1032  $ename = $attrs['ref'];
1033  } else {
1034  $this->xdebug("processing untyped element ".$attrs['name']);
1035  $this->currentElement = $attrs['name'];
1036  $this->elements[ $attrs['name'] ] = $attrs;
1037  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1038  $this->elements[ $attrs['name'] ]['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
1039  if (!isset($this->elements[ $attrs['name'] ]['form'])) {
1040  $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
1041  }
1042  }
1043  if(isset($ename) && $this->currentComplexType){
1044  $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1045  }
1046  break;
1047  // we ignore enumeration values
1048  //case 'enumeration':
1049  //break;
1050  case 'import':
1051  if (isset($attrs['schemaLocation'])) {
1052  //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1053  $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1054  } else {
1055  //$this->xdebug('import namespace ' . $attrs['namespace']);
1056  $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1057  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1058  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1059  }
1060  }
1061  break;
1062  case 'restriction':
1063  //$this->xdebug("in restriction for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1064  if($this->currentElement){
1065  $this->elements[$this->currentElement]['type'] = $attrs['base'];
1066  } elseif($this->currentSimpleType){
1067  $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1068  } elseif($this->currentComplexType){
1069  $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1070  if(strstr($attrs['base'],':') == ':Array'){
1071  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1072  }
1073  }
1074  break;
1075  case 'schema':
1076  $this->schemaInfo = $attrs;
1077  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1078  if (isset($attrs['targetNamespace'])) {
1079  $this->schemaTargetNamespace = $attrs['targetNamespace'];
1080  }
1081  if (!isset($attrs['elementFormDefault'])) {
1082  $this->schemaInfo['elementFormDefault'] = 'unqualified';
1083  }
1084  break;
1085  case 'simpleType':
1086  if(isset($attrs['name'])){
1087  $this->xdebug("processing simpleType for name " . $attrs['name']);
1088  $this->currentSimpleType = $attrs['name'];
1089  $this->simpleTypes[ $attrs['name'] ] = $attrs;
1090  $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1091  $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1092  } else {
1093  //echo 'not parsing: '.$name;
1094  //var_dump($attrs);
1095  }
1096  break;
1097  default:
1098  //$this->xdebug("do not have anything to do for element $name");
1099  }
1100  }
1101 
1109  function schemaEndElement($parser, $name) {
1110  // bring depth down a notch
1111  $this->depth--;
1112  // position of current element is equal to the last value left in depth_array for my depth
1113  if(isset($this->depth_array[$this->depth])){
1114  $pos = $this->depth_array[$this->depth];
1115  }
1116  // move on...
1117  if($name == 'complexType'){
1118  $this->currentComplexType = false;
1119  $this->currentElement = false;
1120  }
1121  if($name == 'element'){
1122  $this->currentElement = false;
1123  }
1124  if($name == 'simpleType'){
1125  $this->currentSimpleType = false;
1126  }
1127  }
1128 
1137  $pos = $this->depth_array[$this->depth - 1];
1138  $this->message[$pos]['cdata'] .= $data;
1139  }
1140 
1146  function serializeSchema(){
1147 
1148  $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1149  $xml = '';
1150  // imports
1151  if (sizeof($this->imports) > 0) {
1152  foreach($this->imports as $ns => $list) {
1153  foreach ($list as $ii) {
1154  if ($ii['location'] != '') {
1155  $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1156  } else {
1157  $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1158  }
1159  }
1160  }
1161  }
1162  // complex types
1163  foreach($this->complexTypes as $typeName => $attrs){
1164  $contentStr = '';
1165  // serialize child elements
1166  if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1167  foreach($attrs['elements'] as $element => $eParts){
1168  if(isset($eParts['ref'])){
1169  $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1170  } else {
1171  $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
1172  }
1173  }
1174  }
1175  // attributes
1176  if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1177  foreach($attrs['attrs'] as $attr => $aParts){
1178  $contentStr .= " <$schemaPrefix:attribute ref=\"".$this->contractQName($aParts['ref']).'"';
1179  if(isset($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1180  $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1181  $contentStr .= ' wsdl:arrayType="'.$this->contractQName($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType']).'"';
1182  }
1183  $contentStr .= "/>\n";
1184  }
1185  }
1186  // if restriction
1187  if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1188  $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
1189  }
1190  // compositor obviates complex/simple content
1191  if(isset($attrs['compositor']) && ($attrs['compositor'] != '')){
1192  $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
1193  }
1194  // complex or simple content
1195  elseif((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1196  $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
1197  }
1198  // finalize complex type
1199  if($contentStr != ''){
1200  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1201  } else {
1202  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1203  }
1204  $xml .= $contentStr;
1205  }
1206  // simple types
1207  if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1208  foreach($this->simpleTypes as $typeName => $attr){
1209  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n </$schemaPrefix:simpleType>";
1210  }
1211  }
1212  // elements
1213  if(isset($this->elements) && count($this->elements) > 0){
1214  foreach($this->elements as $element => $eParts){
1215  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1216  }
1217  }
1218  // attributes
1219  if(isset($this->attributes) && count($this->attributes) > 0){
1220  foreach($this->attributes as $attr => $aParts){
1221  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1222  }
1223  }
1224  // finish 'er up
1225  $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
1226  foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1227  $el .= " xmlns:$nsp=\"$ns\"\n";
1228  }
1229  $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1230  return $xml;
1231  }
1232 
1239  function xdebug($string){
1240  $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1241  }
1242 
1254  function getPHPType($type,$ns){
1255  if(isset($this->typemap[$ns][$type])){
1256  //print "found type '$type' and ns $ns in typemap<br>";
1257  return $this->typemap[$ns][$type];
1258  } elseif(isset($this->complexTypes[$type])){
1259  //print "getting type '$type' and ns $ns from complexTypes array<br>";
1260  return $this->complexTypes[$type]['phpType'];
1261  }
1262  return false;
1263  }
1264 
1281  function getTypeDef($type){
1282  //$this->debug("in getTypeDef for type $type");
1283  if(isset($this->complexTypes[$type])){
1284  $this->xdebug("in getTypeDef, found complexType $type");
1285  return $this->complexTypes[$type];
1286  } elseif(isset($this->simpleTypes[$type])){
1287  $this->xdebug("in getTypeDef, found simpleType $type");
1288  if (!isset($this->simpleTypes[$type]['phpType'])) {
1289  // get info for type to tack onto the simple type
1290  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1291  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1292  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1293  $etype = $this->getTypeDef($uqType);
1294  if ($etype) {
1295  if (isset($etype['phpType'])) {
1296  $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1297  }
1298  if (isset($etype['elements'])) {
1299  $this->simpleTypes[$type]['elements'] = $etype['elements'];
1300  }
1301  }
1302  }
1303  return $this->simpleTypes[$type];
1304  } elseif(isset($this->elements[$type])){
1305  $this->xdebug("in getTypeDef, found element $type");
1306  if (!isset($this->elements[$type]['phpType'])) {
1307  // get info for type to tack onto the element
1308  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1309  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1310  $etype = $this->getTypeDef($uqType);
1311  if ($etype) {
1312  if (isset($etype['phpType'])) {
1313  $this->elements[$type]['phpType'] = $etype['phpType'];
1314  }
1315  if (isset($etype['elements'])) {
1316  $this->elements[$type]['elements'] = $etype['elements'];
1317  }
1318  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1319  $this->elements[$type]['phpType'] = 'scalar';
1320  }
1321  }
1322  return $this->elements[$type];
1323  } elseif(isset($this->attributes[$type])){
1324  $this->xdebug("in getTypeDef, found attribute $type");
1325  return $this->attributes[$type];
1326  }
1327  $this->xdebug("in getTypeDef, did not find $type");
1328  return false;
1329  }
1330 
1338  function serializeTypeDef($type){
1339  //print "in sTD() for type $type<br>";
1340  if($typeDef = $this->getTypeDef($type)){
1341  $str .= '<'.$type;
1342  if(is_array($typeDef['attrs'])){
1343  foreach($attrs as $attName => $data){
1344  $str .= " $attName=\"{type = ".$data['type']."}\"";
1345  }
1346  }
1347  $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1348  if(count($typeDef['elements']) > 0){
1349  $str .= ">";
1350  foreach($typeDef['elements'] as $element => $eData){
1351  $str .= $this->serializeTypeDef($element);
1352  }
1353  $str .= "</$type>";
1354  } elseif($typeDef['typeClass'] == 'element') {
1355  $str .= "></$type>";
1356  } else {
1357  $str .= "/>";
1358  }
1359  return $str;
1360  }
1361  return false;
1362  }
1363 
1373  function typeToForm($name,$type){
1374  // get typedef
1375  if($typeDef = $this->getTypeDef($type)){
1376  // if struct
1377  if($typeDef['phpType'] == 'struct'){
1378  $buffer .= '<table>';
1379  foreach($typeDef['elements'] as $child => $childDef){
1380  $buffer .= "
1381  <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1382  <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1383  }
1384  $buffer .= '</table>';
1385  // if array
1386  } elseif($typeDef['phpType'] == 'array'){
1387  $buffer .= '<table>';
1388  for($i=0;$i < 3; $i++){
1389  $buffer .= "
1390  <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1391  <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1392  }
1393  $buffer .= '</table>';
1394  // if scalar
1395  } else {
1396  $buffer .= "<input type='text' name='parameters[$name]'>";
1397  }
1398  } else {
1399  $buffer .= "<input type='text' name='parameters[$name]'>";
1400  }
1401  return $buffer;
1402  }
1403 
1444  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1445  $this->complexTypes[$name] = array(
1446  'name' => $name,
1447  'typeClass' => $typeClass,
1448  'phpType' => $phpType,
1449  'compositor'=> $compositor,
1450  'restrictionBase' => $restrictionBase,
1451  'elements' => $elements,
1452  'attrs' => $attrs,
1453  'arrayType' => $arrayType
1454  );
1455 
1456  $this->xdebug("addComplexType $name: " . $this->varDump($this->complexTypes[$name]));
1457  }
1458 
1469  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
1470  $this->simpleTypes[$name] = array(
1471  'name' => $name,
1472  'typeClass' => $typeClass,
1473  'phpType' => $phpType,
1474  'type' => $restrictionBase
1475  );
1476 
1477  $this->xdebug("addSimpleType $name: " . $this->varDump($this->simpleTypes[$name]));
1478  }
1479 }
1480 
1481 
1482 
1483 ?><?php
1484 
1485 
1486 
1495 class soapval extends nusoap_base {
1507  function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
1508  $this->name = $name;
1509  $this->value = $value;
1510  $this->type = $type;
1511  $this->element_ns = $element_ns;
1512  $this->type_ns = $type_ns;
1513  $this->attributes = $attributes;
1514  }
1515 
1522  function serialize($use='encoded') {
1523  return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
1524  }
1525 
1533  function decode(){
1534  return $this->value;
1535  }
1536 }
1537 
1538 
1539 
1540 ?><?php
1541 
1542 
1543 
1553 
1554  var $url = '';
1555  var $uri = '';
1556  var $scheme = '';
1557  var $host = '';
1558  var $port = '';
1559  var $path = '';
1560  var $request_method = 'POST';
1561  var $protocol_version = '1.0';
1562  var $encoding = '';
1563  var $outgoing_headers = array();
1564  var $incoming_headers = array();
1567  var $useSOAPAction = true;
1569  var $ch = false; // cURL handle
1572 
1577  $this->url = $url;
1578 
1579  $u = parse_url($url);
1580  foreach($u as $k => $v){
1581  $this->debug("$k = $v");
1582  $this->$k = $v;
1583  }
1584 
1585  // add any GET params to path
1586  if(isset($u['query']) && $u['query'] != ''){
1587  $this->path .= '?' . $u['query'];
1588  }
1589 
1590  // set default port
1591  if(!isset($u['port'])){
1592  if($u['scheme'] == 'https'){
1593  $this->port = 443;
1594  } else {
1595  $this->port = 80;
1596  }
1597  }
1598 
1599  $this->uri = $this->path;
1600 
1601  // build headers
1602  ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
1603  $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
1604  if (!isset($u['port'])) {
1605  $this->outgoing_headers['Host'] = $this->host;
1606  } else {
1607  $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
1608  }
1609 
1610  if (isset($u['user']) && $u['user'] != '') {
1611  $this->setCredentials($u['user'], isset($u['pass']) ? $u['pass'] : '');
1612  }
1613  }
1614 
1615  function connect($connection_timeout=0,$response_timeout=30){
1616  // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
1617  // "regular" socket.
1618  // TODO: disabled for now because OpenSSL must be *compiled* in (not just
1619  // loaded), and until PHP5 stream_get_wrappers is not available.
1620 // if ($this->scheme == 'https') {
1621 // if (version_compare(phpversion(), '4.3.0') >= 0) {
1622 // if (extension_loaded('openssl')) {
1623 // $this->scheme = 'ssl';
1624 // $this->debug('Using SSL over OpenSSL');
1625 // }
1626 // }
1627 // }
1628  $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
1629  if ($this->scheme == 'http' || $this->scheme == 'ssl') {
1630  // use persistent connection
1631  if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
1632  if (!feof($this->fp)) {
1633  $this->debug('Re-use persistent connection');
1634  return true;
1635  }
1636  fclose($this->fp);
1637  $this->debug('Closed persistent connection at EOF');
1638  }
1639 
1640  // munge host if using OpenSSL
1641  if ($this->scheme == 'ssl') {
1642  $host = 'ssl://' . $this->host;
1643  } else {
1644  $host = $this->host;
1645  }
1646  $this->debug('calling fsockopen with host ' . $host);
1647 
1648  // open socket
1649  if($connection_timeout > 0){
1650  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
1651  } else {
1652  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
1653  }
1654 
1655  // test pointer
1656  if(!$this->fp) {
1657  $msg = 'Couldn\'t open socket connection to server ' . $this->url;
1658  if ($this->errno) {
1659  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
1660  } else {
1661  $msg .= ' prior to connect(). This is often a problem looking up the host name.';
1662  }
1663  $this->debug($msg);
1664  $this->setError($msg);
1665  return false;
1666  }
1667 
1668  // set response timeout
1669  socket_set_timeout( $this->fp, $response_timeout);
1670 
1671  $this->debug('socket connected');
1672  return true;
1673  } else if ($this->scheme == 'https') {
1674  if (!extension_loaded('curl')) {
1675  $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
1676  return false;
1677  }
1678  $this->debug('connect using https');
1679  // init CURL
1680  $this->ch = curl_init();
1681  // set url
1682  $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
1683  // add path
1684  $hostURL .= $this->path;
1685  curl_setopt($this->ch, CURLOPT_URL, $hostURL);
1686  // ask for headers in the response output
1687  curl_setopt($this->ch, CURLOPT_HEADER, 1);
1688  // ask for the response output as the return value
1689  curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
1690  // encode
1691  // We manage this ourselves through headers and encoding
1692 // if(function_exists('gzuncompress')){
1693 // curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
1694 // }
1695  // persistent connection
1696  if ($this->persistentConnection) {
1697  // The way we send data, we cannot use persistent connections, since
1698  // there will be some "junk" at the end of our request.
1699  //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
1700  $this->persistentConnection = false;
1701  $this->outgoing_headers['Connection'] = 'close';
1702  }
1703  // set timeout (NOTE: cURL does not have separate connection and response timeouts)
1704  if ($connection_timeout != 0) {
1705  curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
1706  }
1707 
1708  // recent versions of cURL turn on peer/host checking by default,
1709  // while PHP binaries are not compiled with a default location for the
1710  // CA cert bundle, so disable peer/host checking.
1711 //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
1712  curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
1713  curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
1714 
1715  /*
1716  TODO: support client certificates (thanks Tobias Boes)
1717  curl_setopt($this->ch, CURLOPT_CAINFO, '$pathToPemFiles/rootca.pem');
1718  curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
1719  curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
1720  curl_setopt($this->ch, CURLOPT_SSLCERT, '$pathToPemFiles/mycert.pem');
1721  curl_setopt($this->ch, CURLOPT_SSLKEY, '$pathToPemFiles/mykey.pem');
1722  */
1723  $this->debug('cURL connection set up');
1724  return true;
1725  } else {
1726  $this->setError('Unknown scheme ' . $this->scheme);
1727  $this->debug('Unknown scheme ' . $this->scheme);
1728  return false;
1729  }
1730  }
1731 
1741  function send($data, $timeout=0, $response_timeout=30) {
1742 
1743  $this->debug('entered send() with data of length: '.strlen($data));
1744 
1745  $this->tryagain = true;
1746  $tries = 0;
1747  while ($this->tryagain) {
1748  $this->tryagain = false;
1749  if ($tries++ < 2) {
1750  // make connnection
1751  if (!$this->connect($timeout, $response_timeout)){
1752  return false;
1753  }
1754 
1755  // send request
1756  if (!$this->sendRequest($data)){
1757  return false;
1758  }
1759 
1760  // get response
1761  $respdata = $this->getResponse();
1762  } else {
1763  $this->setError('Too many tries to get an OK response');
1764  }
1765  }
1766  $this->debug('end of send()');
1767  return $respdata;
1768  }
1769 
1770 
1780  function sendHTTPS($data, $timeout=0, $response_timeout=30) {
1781  return $this->send($data, $timeout, $response_timeout);
1782  }
1783 
1793  function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array()) {
1794  global $_SERVER;
1795 
1796  $this->debug("Set credentials for authtype $authtype");
1797  // cf. RFC 2617
1798  if ($authtype == 'basic') {
1799  $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode($username.':'.$password);
1800  } elseif ($authtype == 'digest') {
1801  if (isset($digestRequest['nonce'])) {
1802  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
1803 
1804  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
1805 
1806  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
1807  $A1 = $username. ':' . $digestRequest['realm'] . ':' . $password;
1808 
1809  // H(A1) = MD5(A1)
1810  $HA1 = md5($A1);
1811 
1812  // A2 = Method ":" digest-uri-value
1813  $A2 = 'POST:' . $this->uri;
1814 
1815  // H(A2)
1816  $HA2 = md5($A2);
1817 
1818  // KD(secret, data) = H(concat(secret, ":", data))
1819  // if qop == auth:
1820  // request-digest = <"> < KD ( H(A1), unq(nonce-value)
1821  // ":" nc-value
1822  // ":" unq(cnonce-value)
1823  // ":" unq(qop-value)
1824  // ":" H(A2)
1825  // ) <">
1826  // if qop is missing,
1827  // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
1828 
1829  $unhashedDigest = '';
1830  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
1831  $cnonce = $nonce;
1832  if ($digestRequest['qop'] != '') {
1833  $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
1834  } else {
1835  $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
1836  }
1837 
1838  $hashedDigest = md5($unhashedDigest);
1839 
1840  $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"';
1841  }
1842  }
1843  $this->username = $username;
1844  $this->password = $password;
1845  $this->authtype = $authtype;
1846  $this->digestRequest = $digestRequest;
1847 
1848  if (isset($this->outgoing_headers['Authorization'])) {
1849  $this->debug('Authorization header set: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
1850  } else {
1851  $this->debug('Authorization header not set');
1852  }
1853  }
1854 
1861  function setSOAPAction($soapaction) {
1862  $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
1863  }
1864 
1871  function setEncoding($enc='gzip, deflate'){
1872  $this->protocol_version = '1.1';
1873  $this->outgoing_headers['Accept-Encoding'] = $enc;
1874  $this->outgoing_headers['Connection'] = 'close';
1875  $this->persistentConnection = false;
1876  set_magic_quotes_runtime(0);
1877  // deprecated
1878  $this->encoding = $enc;
1879  }
1880 
1890  function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
1891  $this->uri = $this->url;
1892  $this->host = $proxyhost;
1893  $this->port = $proxyport;
1894  if ($proxyusername != '' && $proxypassword != '') {
1895  $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
1896  }
1897  }
1898 
1908  function decodeChunked($buffer, $lb){
1909  // length := 0
1910  $length = 0;
1911  $new = '';
1912 
1913  // read chunk-size, chunk-extension (if any) and CRLF
1914  // get the position of the linebreak
1915  $chunkend = strpos($buffer, $lb);
1916  if ($chunkend == FALSE) {
1917  $this->debug('no linebreak found in decodeChunked');
1918  return $new;
1919  }
1920  $temp = substr($buffer,0,$chunkend);
1921  $chunk_size = hexdec( trim($temp) );
1922  $chunkstart = $chunkend + strlen($lb);
1923  // while (chunk-size > 0) {
1924  while ($chunk_size > 0) {
1925  $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
1926  $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
1927 
1928  // Just in case we got a broken connection
1929  if ($chunkend == FALSE) {
1930  $chunk = substr($buffer,$chunkstart);
1931  // append chunk-data to entity-body
1932  $new .= $chunk;
1933  $length += strlen($chunk);
1934  break;
1935  }
1936 
1937  // read chunk-data and CRLF
1938  $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
1939  // append chunk-data to entity-body
1940  $new .= $chunk;
1941  // length := length + chunk-size
1942  $length += strlen($chunk);
1943  // read chunk-size and CRLF
1944  $chunkstart = $chunkend + strlen($lb);
1945 
1946  $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
1947  if ($chunkend == FALSE) {
1948  break; //Just in case we got a broken connection
1949  }
1950  $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
1951  $chunk_size = hexdec( trim($temp) );
1952  $chunkstart = $chunkend;
1953  }
1954  return $new;
1955  }
1956 
1957  /*
1958  * Writes payload, including HTTP headers, to $this->outgoing_payload.
1959  */
1960  function buildPayload($data) {
1961  // add content-length header
1962  $this->outgoing_headers['Content-Length'] = strlen($data);
1963 
1964  // start building outgoing payload:
1965  $this->outgoing_payload = "$this->request_method $this->uri HTTP/$this->protocol_version\r\n";
1966 
1967  // loop thru headers, serializing
1968  foreach($this->outgoing_headers as $k => $v){
1969  $this->outgoing_payload .= $k.': '.$v."\r\n";
1970  }
1971 
1972  // header/body separator
1973  $this->outgoing_payload .= "\r\n";
1974 
1975  // add data
1976  $this->outgoing_payload .= $data;
1977  }
1978 
1979  function sendRequest($data){
1980  // build payload
1981  $this->buildPayload($data);
1982 
1983  if ($this->scheme == 'http' || $this->scheme == 'ssl') {
1984  // send payload
1985  if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
1986  $this->setError('couldn\'t write message data to socket');
1987  $this->debug('couldn\'t write message data to socket');
1988  return false;
1989  }
1990  $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
1991  return true;
1992  } else if ($this->scheme == 'https') {
1993  // set payload
1994  // TODO: cURL does say this should only be the verb, and in fact it
1995  // turns out that the URI and HTTP version are appended to this, which
1996  // some servers refuse to work with
1997  //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
1998  foreach($this->outgoing_headers as $k => $v){
1999  $curl_headers[] = "$k: $v";
2000  }
2001  curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
2002  if ($this->request_method == "POST") {
2003  curl_setopt($this->ch, CURLOPT_POST, 1);
2004  curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
2005  } else {
2006  }
2007  $this->debug('set cURL payload');
2008  return true;
2009  }
2010  }
2011 
2012  function getResponse(){
2013  $this->incoming_payload = '';
2014 
2015  if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2016  // loop until headers have been retrieved
2017  $data = '';
2018  while (!isset($lb)){
2019 
2020  // We might EOF during header read.
2021  if(feof($this->fp)) {
2022  $this->incoming_payload = $data;
2023  $this->debug('found no headers before EOF after length ' . strlen($data));
2024  $this->debug("received before EOF:\n" . $data);
2025  $this->setError('server failed to send headers');
2026  return false;
2027  }
2028 
2029  $tmp = fgets($this->fp, 256);
2030  $tmplen = strlen($tmp);
2031  $this->debug("read line of $tmplen bytes: " . trim($tmp));
2032 
2033  if ($tmplen == 0) {
2034  $this->incoming_payload = $data;
2035  $this->debug('socket read of headers timed out after length ' . strlen($data));
2036  $this->debug("read before timeout:\n" . $data);
2037  $this->setError('socket read of headers timed out');
2038  return false;
2039  }
2040 
2041  $data .= $tmp;
2042  $pos = strpos($data,"\r\n\r\n");
2043  if($pos > 1){
2044  $lb = "\r\n";
2045  } else {
2046  $pos = strpos($data,"\n\n");
2047  if($pos > 1){
2048  $lb = "\n";
2049  }
2050  }
2051  // remove 100 header
2052  if(isset($lb) && ereg('^HTTP/1.1 100',$data)){
2053  unset($lb);
2054  $data = '';
2055  }//
2056  }
2057  // store header data
2058  $this->incoming_payload .= $data;
2059  $this->debug('found end of headers after length ' . strlen($data));
2060  // process headers
2061  $header_data = trim(substr($data,0,$pos));
2062  $header_array = explode($lb,$header_data);
2063  $this->incoming_headers = array();
2064  foreach($header_array as $header_line){
2065  $arr = explode(':',$header_line, 2);
2066  if(count($arr) > 1){
2067  $header_name = strtolower(trim($arr[0]));
2068  $this->incoming_headers[$header_name] = trim($arr[1]);
2069  } else if (isset($header_name)) {
2070  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2071  }
2072  }
2073 
2074  // loop until msg has been received
2075  if (isset($this->incoming_headers['content-length'])) {
2076  $content_length = $this->incoming_headers['content-length'];
2077  $chunked = false;
2078  $this->debug("want to read content of length $content_length");
2079  } else {
2080  $content_length = 2147483647;
2081  if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2082  $chunked = true;
2083  $this->debug("want to read chunked content");
2084  } else {
2085  $chunked = false;
2086  $this->debug("want to read content to EOF");
2087  }
2088  }
2089  $data = '';
2090  do {
2091  if ($chunked) {
2092  $tmp = fgets($this->fp, 256);
2093  $tmplen = strlen($tmp);
2094  $this->debug("read chunk line of $tmplen bytes");
2095  if ($tmplen == 0) {
2096  $this->incoming_payload = $data;
2097  $this->debug('socket read of chunk length timed out after length ' . strlen($data));
2098  $this->debug("read before timeout:\n" . $data);
2099  $this->setError('socket read of chunk length timed out');
2100  return false;
2101  }
2102  $content_length = hexdec(trim($tmp));
2103  $this->debug("chunk length $content_length");
2104  }
2105  $strlen = 0;
2106  while (($strlen < $content_length) && (!feof($this->fp))) {
2107  $readlen = min(8192, $content_length - $strlen);
2108  $tmp = fread($this->fp, $readlen);
2109  $tmplen = strlen($tmp);
2110  $this->debug("read buffer of $tmplen bytes");
2111  if (($tmplen == 0) && (!feof($this->fp))) {
2112  $this->incoming_payload = $data;
2113  $this->debug('socket read of body timed out after length ' . strlen($data));
2114  $this->debug("read before timeout:\n" . $data);
2115  $this->setError('socket read of body timed out');
2116  return false;
2117  }
2118  $strlen += $tmplen;
2119  $data .= $tmp;
2120  }
2121  if ($chunked && ($content_length > 0)) {
2122  $tmp = fgets($this->fp, 256);
2123  $tmplen = strlen($tmp);
2124  $this->debug("read chunk terminator of $tmplen bytes");
2125  if ($tmplen == 0) {
2126  $this->incoming_payload = $data;
2127  $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
2128  $this->debug("read before timeout:\n" . $data);
2129  $this->setError('socket read of chunk terminator timed out');
2130  return false;
2131  }
2132  }
2133  } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
2134  if (feof($this->fp)) {
2135  $this->debug('read to EOF');
2136  }
2137  $this->debug('read body of length ' . strlen($data));
2138  $this->incoming_payload .= $data;
2139  $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
2140 
2141  // close filepointer
2142  if(
2143  (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
2144  (! $this->persistentConnection) || feof($this->fp)){
2145  fclose($this->fp);
2146  $this->fp = false;
2147  $this->debug('closed socket');
2148  }
2149 
2150  // connection was closed unexpectedly
2151  if($this->incoming_payload == ''){
2152  $this->setError('no response from server');
2153  return false;
2154  }
2155 
2156  // decode transfer-encoding
2157 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
2158 // if(!$data = $this->decodeChunked($data, $lb)){
2159 // $this->setError('Decoding of chunked data failed');
2160 // return false;
2161 // }
2162  //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
2163  // set decoded payload
2164 // $this->incoming_payload = $header_data.$lb.$lb.$data;
2165 // }
2166 
2167  } else if ($this->scheme == 'https') {
2168  // send and receive
2169  $this->debug('send and receive with cURL');
2170  $this->incoming_payload = curl_exec($this->ch);
2172 
2173  $cErr = curl_error($this->ch);
2174  if ($cErr != '') {
2175  $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
2176  foreach(curl_getinfo($this->ch) as $k => $v){
2177  $err .= "$k: $v<br>";
2178  }
2179  $this->debug($err);
2180  $this->setError($err);
2181  curl_close($this->ch);
2182  return false;
2183  } else {
2184  //echo '<pre>';
2185  //var_dump(curl_getinfo($this->ch));
2186  //echo '</pre>';
2187  }
2188  // close curl
2189  $this->debug('No cURL error, closing cURL');
2190  curl_close($this->ch);
2191 
2192  // remove 100 header
2193  if (ereg('^HTTP/1.1 100',$data)) {
2194  if ($pos = strpos($data,"\r\n\r\n")) {
2195  $data = ltrim(substr($data,$pos));
2196  } elseif($pos = strpos($data,"\n\n") ) {
2197  $data = ltrim(substr($data,$pos));
2198  }
2199  }
2200 
2201  // separate content from HTTP headers
2202  if ($pos = strpos($data,"\r\n\r\n")) {
2203  $lb = "\r\n";
2204  } elseif( $pos = strpos($data,"\n\n")) {
2205  $lb = "\n";
2206  } else {
2207  $this->debug('no proper separation of headers and document');
2208  $this->setError('no proper separation of headers and document');
2209  return false;
2210  }
2211  $header_data = trim(substr($data,0,$pos));
2212  $header_array = explode($lb,$header_data);
2213  $data = ltrim(substr($data,$pos));
2214  $this->debug('found proper separation of headers and document');
2215  $this->debug('cleaned data, stringlen: '.strlen($data));
2216  // clean headers
2217  foreach ($header_array as $header_line) {
2218  $arr = explode(':',$header_line,2);
2219  if (count($arr) > 1) {
2220  $this->incoming_headers[strtolower(trim($arr[0]))] = trim($arr[1]);
2221  }
2222  }
2223  }
2224 
2225  // see if we need to resend the request with http digest authentication
2226  if (isset($this->incoming_headers['www-authenticate']) && strstr($header_array[0], '401 Unauthorized')) {
2227  $this->debug('Got 401 Unauthorized with WWW-Authenticate: ' . $this->incoming_headers['www-authenticate']);
2228  if (substr("Digest ", $this->incoming_headers['www-authenticate'])) {
2229  $this->debug('Server wants digest authentication');
2230  // remove "Digest " from our elements
2231  $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
2232 
2233  // parse elements into array
2234  $digestElements = explode(',', $digestString);
2235  foreach ($digestElements as $val) {
2236  $tempElement = explode('=', trim($val));
2237  $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
2238  }
2239 
2240  // should have (at least) qop, realm, nonce
2241  if (isset($digestRequest['nonce'])) {
2242  $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
2243  $this->tryagain = true;
2244  return false;
2245  }
2246  }
2247  $this->debug('HTTP authentication failed');
2248  $this->setError('HTTP authentication failed');
2249  return false;
2250  }
2251 
2252  // decode content-encoding
2253  if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
2254  if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
2255  // if decoding works, use it. else assume data wasn't gzencoded
2256  if(function_exists('gzuncompress')){
2257  //$timer->setMarker('starting decoding of gzip/deflated content');
2258  if($this->incoming_headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)){
2259  $data = $degzdata;
2260  } elseif($this->incoming_headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){ // do our best
2261  $data = $degzdata;
2262  } else {
2263  $this->setError('Errors occurred when trying to decode the data');
2264  }
2265  //$timer->setMarker('finished decoding of gzip/deflated content');
2266  //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
2267  // set decoded payload
2268  $this->incoming_payload = $header_data.$lb.$lb.$data;
2269  } else {
2270  $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
2271  }
2272  }
2273  }
2274 
2275  if(strlen($data) == 0){
2276  $this->debug('no data after headers!');
2277  $this->setError('no data present after HTTP headers');
2278  return false;
2279  }
2280 
2281  return $data;
2282  }
2283 
2284  function setContentType($type, $charset = false) {
2285  $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
2286  }
2287 
2289  if (isset($this->outgoing_headers['Accept-Encoding'])) {
2290  return false;
2291  }
2292  $this->protocol_version = '1.1';
2293  $this->persistentConnection = true;
2294  $this->outgoing_headers['Connection'] = 'Keep-Alive';
2295  return true;
2296  }
2297 }
2298 
2299 ?><?php
2300 
2301 
2302 
2313 class soap_server extends nusoap_base {
2314  var $headers = array(); // HTTP headers of request
2315  var $request = ''; // HTTP request
2316  var $requestHeaders = ''; // SOAP headers from request (incomplete namespace resolution) (text)
2317  var $document = ''; // SOAP body request portion (incomplete namespace resolution) (text)
2318  var $requestSOAP = ''; // SOAP payload for request (text)
2319  var $methodURI = ''; // requested method namespace URI
2320  var $methodname = ''; // name of method requested
2321  var $methodparams = array(); // method parameters from request
2322  var $xml_encoding = ''; // character set encoding of incoming (request) messages
2323  var $SOAPAction = ''; // SOAP Action from request
2324 
2325  var $outgoing_headers = array();// HTTP headers of response
2326  var $response = ''; // HTTP response
2327  var $responseHeaders = ''; // SOAP headers for response (text)
2328  var $responseSOAP = ''; // SOAP payload for response (text)
2329  var $methodreturn = false; // method return to place in response
2330  var $methodreturnisliteralxml = false; // whether $methodreturn is a string of literal XML
2331  var $fault = false; // SOAP fault for response
2332  var $result = 'successful'; // text indication of result (for debugging)
2333 
2334  var $operations = array(); // assoc array of operations => opData
2335  var $wsdl = false; // wsdl instance
2336  var $externalWSDLURL = false; // URL for WSDL
2337  var $debug_flag = false; // whether to append debug to response as XML comment
2338 
2346  function soap_server($wsdl=false){
2347 
2348  // turn on debugging?
2349  global $debug;
2350  global $_REQUEST;
2351  global $_SERVER;
2352  global $HTTP_SERVER_VARS;
2353 
2354  if (isset($debug)) {
2355  $this->debug_flag = $debug;
2356  } else if (isset($_REQUEST['debug'])) {
2357  $this->debug_flag = $_REQUEST['debug'];
2358  } else if (isset($_SERVER['QUERY_STRING'])) {
2359  $qs = explode('&', $_SERVER['QUERY_STRING']);
2360  foreach ($qs as $v) {
2361  if (substr($v, 0, 6) == 'debug=') {
2362  $this->debug_flag = substr($v, 6);
2363  }
2364  }
2365  } else if (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
2366  $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
2367  foreach ($qs as $v) {
2368  if (substr($v, 0, 6) == 'debug=') {
2369  $this->debug_flag = substr($v, 6);
2370  }
2371  }
2372  }
2373 
2374  // wsdl
2375  if($wsdl){
2376  if (is_object($wsdl) && is_a($wsdl, 'wsdl')) {
2377  $this->wsdl = $wsdl;
2378  $this->externalWSDLURL = $this->wsdl->wsdl;
2379  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
2380  } else {
2381  $this->debug('Create wsdl from ' . $wsdl);
2382  $this->wsdl = new wsdl($wsdl);
2383  $this->externalWSDLURL = $wsdl;
2384  }
2385  $this->debug("wsdl...\n" . $this->wsdl->debug_str);
2386  $this->wsdl->debug_str = '';
2387  if($err = $this->wsdl->getError()){
2388  die('WSDL ERROR: '.$err);
2389  }
2390  }
2391  }
2392 
2399  function service($data){
2400  global $QUERY_STRING;
2401  if(isset($_SERVER['QUERY_STRING'])){
2402  $qs = $_SERVER['QUERY_STRING'];
2403  } elseif(isset($GLOBALS['QUERY_STRING'])){
2404  $qs = $GLOBALS['QUERY_STRING'];
2405  } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
2406  $qs = $QUERY_STRING;
2407  }
2408 
2409  if(isset($qs) && ereg('wsdl', $qs) ){
2410  // This is a request for WSDL
2411  if($this->externalWSDLURL){
2412  if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
2413  header('Location: '.$this->externalWSDLURL);
2414  } else { // assume file
2415  header("Content-Type: text/xml\r\n");
2416  $fp = fopen($this->externalWSDLURL, 'r');
2417  fpassthru($fp);
2418  }
2419  } else {
2420  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
2421  print $this->wsdl->serialize();
2422  }
2423  } elseif($data == '' && $this->wsdl){
2424  // print web interface
2425  print $this->webDescription();
2426  } else {
2427  // handle the request
2428  $this->parse_request($data);
2429  if (! $this->fault) {
2430  $this->invoke_method();
2431  }
2432  if (! $this->fault) {
2433  $this->serialize_return();
2434  }
2435  $this->send_response();
2436  }
2437  }
2438 
2451  function parse_http_headers() {
2452  global $HTTP_SERVER_VARS;
2453  global $_SERVER;
2454 
2455  $this->request = '';
2456  if(function_exists('getallheaders')){
2457  $this->headers = getallheaders();
2458  foreach($this->headers as $k=>$v){
2459  $this->request .= "$k: $v\r\n";
2460  $this->debug("$k: $v");
2461  }
2462  // get SOAPAction header
2463  if(isset($this->headers['SOAPAction'])){
2464  $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']);
2465  }
2466  // get the character encoding of the incoming request
2467  if(strpos($this->headers['Content-Type'],'=')){
2468  $enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1));
2469  if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
2470  $this->xml_encoding = strtoupper($enc);
2471  } else {
2472  $this->xml_encoding = 'US-ASCII';
2473  }
2474  } else {
2475  // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
2476  $this->xml_encoding = 'UTF-8';
2477  }
2478  } elseif(isset($_SERVER) && is_array($_SERVER)){
2479  foreach ($_SERVER as $k => $v) {
2480  if (substr($k, 0, 5) == 'HTTP_') {
2481  $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
2482  } else {
2483  $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
2484  }
2485  if ($k == 'Soapaction') {
2486  // get SOAPAction header
2487  $k = 'SOAPAction';
2488  $v = str_replace('"', '', $v);
2489  $v = str_replace('\\', '', $v);
2490  $this->SOAPAction = $v;
2491  } else if ($k == 'Content-Type') {
2492  // get the character encoding of the incoming request
2493  if (strpos($v, '=')) {
2494  $enc = substr(strstr($v, '='), 1);
2495  $enc = str_replace('"', '', $enc);
2496  $enc = str_replace('\\', '', $enc);
2497  if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
2498  $this->xml_encoding = strtoupper($enc);
2499  } else {
2500  $this->xml_encoding = 'US-ASCII';
2501  }
2502  } else {
2503  // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
2504  $this->xml_encoding = 'UTF-8';
2505  }
2506  }
2507  $this->headers[$k] = $v;
2508  $this->request .= "$k: $v\r\n";
2509  $this->debug("$k: $v");
2510  }
2511  } elseif (is_array($HTTP_SERVER_VARS)) {
2512  foreach ($HTTP_SERVER_VARS as $k => $v) {
2513  if (substr($k, 0, 5) == 'HTTP_') {
2514  $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
2515  if ($k == 'Soapaction') {
2516  // get SOAPAction header
2517  $k = 'SOAPAction';
2518  $v = str_replace('"', '', $v);
2519  $v = str_replace('\\', '', $v);
2520  $this->SOAPAction = $v;
2521  } else if ($k == 'Content-Type') {
2522  // get the character encoding of the incoming request
2523  if (strpos($v, '=')) {
2524  $enc = substr(strstr($v, '='), 1);
2525  $enc = str_replace('"', '', $enc);
2526  $enc = str_replace('\\', '', $enc);
2527  if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
2528  $this->xml_encoding = strtoupper($enc);
2529  } else {
2530  $this->xml_encoding = 'US-ASCII';
2531  }
2532  } else {
2533  // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
2534  $this->xml_encoding = 'UTF-8';
2535  }
2536  }
2537  $this->headers[$k] = $v;
2538  $this->request .= "$k: $v\r\n";
2539  $this->debug("$k: $v");
2540  }
2541  }
2542  }
2543  }
2544 
2567  function parse_request($data='') {
2568  $this->debug('entering parse_request() on '.date('H:i Y-m-d'));
2569  $this->parse_http_headers();
2570  $this->debug('got character encoding: '.$this->xml_encoding);
2571  // uncompress if necessary
2572  if (isset($this->headers['Content-Encoding']) && $this->headers['Content-Encoding'] != '') {
2573  $this->debug('got content encoding: ' . $this->headers['Content-Encoding']);
2574  if ($this->headers['Content-Encoding'] == 'deflate' || $this->headers['Content-Encoding'] == 'gzip') {
2575  // if decoding works, use it. else assume data wasn't gzencoded
2576  if (function_exists('gzuncompress')) {
2577  if ($this->headers['Content-Encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
2578  $data = $degzdata;
2579  } elseif ($this->headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
2580  $data = $degzdata;
2581  } else {
2582  $this->fault('Server', 'Errors occurred when trying to decode the data');
2583  return;
2584  }
2585  } else {
2586  $this->fault('Server', 'This Server does not support compressed data');
2587  return;
2588  }
2589  }
2590  }
2591  $this->request .= "\r\n".$data;
2592  $this->requestSOAP = $data;
2593  // parse response, get soap parser obj
2594  $parser = new soap_parser($data,$this->xml_encoding);
2595  // parser debug
2596  $this->debug("parser debug: \n".$parser->debug_str);
2597  // if fault occurred during message parsing
2598  if($err = $parser->getError()){
2599  $this->result = 'fault: error in msg parsing: '.$err;
2600  $this->fault('Server',"error in msg parsing:\n".$err);
2601  // else successfully parsed request into soapval object
2602  } else {
2603  // get/set methodname
2604  $this->methodURI = $parser->root_struct_namespace;
2605  $this->methodname = $parser->root_struct_name;
2606  $this->debug('method name: '.$this->methodname);
2607  $this->debug('calling parser->get_response()');
2608  $this->methodparams = $parser->get_response();
2609  // get SOAP headers
2610  $this->requestHeaders = $parser->getHeaders();
2611  // add document for doclit support
2612  $this->document = $parser->document;
2613  }
2614  $this->debug('leaving parse_request() on '.date('H:i Y-m-d'));
2615  }
2616 
2634  function invoke_method() {
2635  $this->debug('entering invoke_method');
2636  // does method exist?
2637  if(!function_exists($this->methodname)){
2638  // "method not found" fault here
2639  $this->debug("method '$this->methodname' not found!");
2640  $this->result = 'fault: method not found';
2641  $this->fault('Server',"method '$this->methodname' not defined in service");
2642  return;
2643  }
2644  if($this->wsdl){
2645  if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){
2646  //if(
2647  $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service");
2648  return;
2649  }
2650  $this->debug('opData is ' . $this->varDump($this->opData));
2651  }
2652  $this->debug("method '$this->methodname' exists");
2653  // evaluate message, getting back parameters
2654  // verify that request parameters match the method's signature
2655  if(! $this->verify_method($this->methodname,$this->methodparams)){
2656  // debug
2657  $this->debug('ERROR: request not verified against method signature');
2658  $this->result = 'fault: request failed validation against method signature';
2659  // return fault
2660  $this->fault('Server',"Operation '$this->methodname' not defined in service.");
2661  return;
2662  }
2663 
2664  // if there are parameters to pass
2665  $this->debug('params var dump '.$this->varDump($this->methodparams));
2666  if($this->methodparams){
2667  $this->debug("calling '$this->methodname' with params");
2668  if (! function_exists('call_user_func_array')) {
2669  $this->debug('calling method using eval()');
2670  $funcCall = $this->methodname.'(';
2671  foreach($this->methodparams as $param) {
2672  $funcCall .= "\"$param\",";
2673  }
2674  $funcCall = substr($funcCall, 0, -1).')';
2675  $this->debug('function call:<br>'.$funcCall);
2676  @eval("\$this->methodreturn = $funcCall;");
2677  } else {
2678  $this->debug('calling method using call_user_func_array()');
2679  $this->methodreturn = call_user_func_array("$this->methodname",$this->methodparams);
2680  }
2681  } else {
2682  // call method w/ no parameters
2683  $this->debug("calling $this->methodname w/ no params");
2684  $m = $this->methodname;
2685  $this->methodreturn = @$m();
2686  }
2687  $this->debug('methodreturn var dump'.$this->varDump($this->methodreturn));
2688  $this->debug("leaving invoke_method: called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
2689  }
2690 
2702  function serialize_return() {
2703  $this->debug("Entering serialize_return");
2704  // if we got nothing back. this might be ok (echoVoid)
2705  if(isset($this->methodreturn) && ($this->methodreturn != '' || is_bool($this->methodreturn))) {
2706  // if fault
2707  if(get_class($this->methodreturn) == 'soap_fault'){
2708  $this->debug('got a fault object from method');
2709  $this->fault = $this->methodreturn;
2710  return;
2711  } elseif ($this->methodreturnisliteralxml) {
2712  $return_val = $this->methodreturn;
2713  // returned value(s)
2714  } else {
2715  $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
2716  $this->debug('serializing return value');
2717  if($this->wsdl){
2718  // weak attempt at supporting multiple output params
2719  if(sizeof($this->opData['output']['parts']) > 1){
2720  $opParams = $this->methodreturn;
2721  } else {
2722  // TODO: is this really necessary?
2723  $opParams = array($this->methodreturn);
2724  }
2725  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
2726  if($errstr = $this->wsdl->getError()){
2727  $this->debug('got wsdl error: '.$errstr);
2728  $this->fault('Server', 'got wsdl error: '.$errstr);
2729  return;
2730  }
2731  } else {
2732  $return_val = $this->serialize_val($this->methodreturn, 'return');
2733  }
2734  }
2735  $this->debug('return val: '.$this->varDump($return_val));
2736  } else {
2737  $return_val = '';
2738  $this->debug('got no response from method');
2739  }
2740  $this->debug('serializing response');
2741  if ($this->wsdl) {
2742  if ($this->opData['style'] == 'rpc') {
2743  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
2744  } else {
2745  $payload = $return_val;
2746  }
2747  } else {
2748  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
2749  }
2750  $this->result = 'successful';
2751  if($this->wsdl){
2752  //if($this->debug_flag){
2753  $this->debug("WSDL debug data:\n".$this->wsdl->debug_str);
2754  // }
2755  // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
2756  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style']);
2757  } else {
2758  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
2759  }
2760  $this->debug("Leaving serialize_return");
2761  }
2762 
2773  function send_response() {
2774  $this->debug('Enter send_response');
2775  if ($this->fault) {
2776  $payload = $this->fault->serialize();
2777  $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
2778  $this->outgoing_headers[] = "Status: 500 Internal Server Error";
2779  } else {
2780  $payload = $this->responseSOAP;
2781  // Some combinations of PHP+Web server allow the Status
2782  // to come through as a header. Since OK is the default
2783  // just do nothing.
2784  // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
2785  // $this->outgoing_headers[] = "Status: 200 OK";
2786  }
2787  // add debug data if in debug mode
2788  if(isset($this->debug_flag) && $this->debug_flag){
2789  while (strpos($this->debug_str, '--')) {
2790  $this->debug_str = str_replace('--', '- -', $this->debug_str);
2791  }
2792  $payload .= "<!--\n" . $this->debug_str . "\n-->";
2793  }
2794  $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
2795  ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
2796  $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
2797  // Let the Web server decide about this
2798  //$this->outgoing_headers[] = "Connection: Close\r\n";
2799  $this->outgoing_headers[] = "Content-Type: text/xml; charset=$this->soap_defencoding";
2800  //begin code to compress payload - by John
2801  if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['Accept-Encoding'])) {
2802  if (strstr($this->headers['Accept-Encoding'], 'deflate')) {
2803  if (function_exists('gzcompress')) {
2804  if (isset($this->debug_flag) && $this->debug_flag) {
2805  $payload .= "<!-- Content being deflated -->";
2806  }
2807  $this->outgoing_headers[] = "Content-Encoding: deflate";
2808  $payload = gzcompress($payload);
2809  } else {
2810  if (isset($this->debug_flag) && $this->debug_flag) {
2811  $payload .= "<!-- Content will not be deflated: no gzcompress -->";
2812  }
2813  }
2814  } else if (strstr($this->headers['Accept-Encoding'], 'gzip')) {
2815  if (function_exists('gzencode')) {
2816  if (isset($this->debug_flag) && $this->debug_flag) {
2817  $payload .= "<!-- Content being gzipped -->";
2818  }
2819  $this->outgoing_headers[] = "Content-Encoding: gzip";
2820  $payload = gzencode($payload);
2821  } else {
2822  if (isset($this->debug_flag) && $this->debug_flag) {
2823  $payload .= "<!-- Content will not be gzipped: no gzencode -->";
2824  }
2825  }
2826  }
2827  }
2828  //end code
2829  $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
2830  reset($this->outgoing_headers);
2831  foreach($this->outgoing_headers as $hdr){
2832  header($hdr, false);
2833  }
2834  $this->response = join("\r\n",$this->outgoing_headers)."\r\n".$payload;
2835  print $payload;
2836  }
2837 
2846  function verify_method($operation,$request){
2847  if(isset($this->wsdl) && is_object($this->wsdl)){
2848  if($this->wsdl->getOperationData($operation)){
2849  return true;
2850  }
2851  } elseif(isset($this->operations[$operation])){
2852  return true;
2853  }
2854  return false;
2855  }
2856 
2866  $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
2867  }
2868 
2882  function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false,$documentation=''){
2883  if($this->externalWSDLURL){
2884  die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
2885  }
2886  if(false == $in) {
2887  }
2888  if(false == $out) {
2889  }
2890  if(false == $namespace) {
2891  }
2892  if(false == $soapaction) {
2893  $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
2894  $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
2895  $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name";
2896  }
2897  if(false == $style) {
2898  $style = "rpc";
2899  }
2900  if(false == $use) {
2901  $use = "encoded";
2902  }
2903 
2904  $this->operations[$name] = array(
2905  'name' => $name,
2906  'in' => $in,
2907  'out' => $out,
2908  'namespace' => $namespace,
2909  'soapaction' => $soapaction,
2910  'style' => $style);
2911  if($this->wsdl){
2912  $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation);
2913  }
2914  return true;
2915  }
2916 
2926  function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
2927  $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
2928  }
2929 
2935  function webDescription(){
2936  $b = '
2937  <html><head><title>NuSOAP: '.$this->wsdl->serviceName.'</title>
2938  <style type="text/css">
2939  body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
2940  p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
2941  pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
2942  ul { margin-top: 10px; margin-left: 20px; }
2943  li { list-style-type: none; margin-top: 10px; color: #000000; }
2944  .content{
2945  margin-left: 0px; padding-bottom: 2em; }
2946  .nav {
2947  padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
2948  margin-top: 10px; margin-left: 0px; color: #000000;
2949  background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
2950  .title {
2951  font-family: arial; font-size: 26px; color: #ffffff;
2952  background-color: #999999; width: 105%; margin-left: 0px;
2953  padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
2954  .hidden {
2955  position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
2956  font-family: arial; overflow: hidden; width: 600;
2957  padding: 20px; font-size: 10px; background-color: #999999;
2958  layer-background-color:#FFFFFF; }
2959  a,a:active { color: charcoal; font-weight: bold; }
2960  a:visited { color: #666666; font-weight: bold; }
2961  a:hover { color: cc3300; font-weight: bold; }
2962  </style>
2963  <script language="JavaScript" type="text/javascript">
2964  <!--
2965  // POP-UP CAPTIONS...
2966  function lib_bwcheck(){ //Browsercheck (needed)
2967  this.ver=navigator.appVersion
2968  this.agent=navigator.userAgent
2969  this.dom=document.getElementById?1:0
2970  this.opera5=this.agent.indexOf("Opera 5")>-1
2971  this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
2972  this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
2973  this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
2974  this.ie=this.ie4||this.ie5||this.ie6
2975  this.mac=this.agent.indexOf("Mac")>-1
2976  this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
2977  this.ns4=(document.layers && !this.dom)?1:0;
2978  this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
2979  return this
2980  }
2981  var bw = new lib_bwcheck()
2982  //Makes crossbrowser object.
2983  function makeObj(obj){
2984  this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
2985  if(!this.evnt) return false
2986  this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
2987  this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
2988  this.writeIt=b_writeIt;
2989  return this
2990  }
2991  // A unit of measure that will be added when setting the position of a layer.
2992  //var px = bw.ns4||window.opera?"":"px";
2993  function b_writeIt(text){
2994  if (bw.ns4){this.wref.write(text);this.wref.close()}
2995  else this.wref.innerHTML = text
2996  }
2997  //Shows the messages
2998  var oDesc;
2999  function popup(divid){
3000  if(oDesc = new makeObj(divid)){
3001  oDesc.css.visibility = "visible"
3002  }
3003  }
3004  function popout(){ // Hides message
3005  if(oDesc) oDesc.css.visibility = "hidden"
3006  }
3007  //-->
3008  </script>
3009  </head>
3010  <body>
3011  <div class=content>
3012  <br><br>
3013  <div class=title>'.$this->wsdl->serviceName.'</div>
3014  <div class=nav>
3015  <p>View the <a href="'.(isset($GLOBALS['PHP_SELF']) ? $GLOBALS['PHP_SELF'] : $_SERVER['PHP_SELF']).'?wsdl">WSDL</a> for the service.
3016  Click on an operation name to view it&apos;s details.</p>
3017  <ul>';
3018  foreach($this->wsdl->getOperations() as $op => $data){
3019  $b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>";
3020  // create hidden div
3021  $b .= "<div id='$op' class='hidden'>
3022  <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
3023  foreach($data as $donnie => $marie){ // loop through opdata
3024  if($donnie == 'input' || $donnie == 'output'){ // show input/output data
3025  $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
3026  foreach($marie as $captain => $tenille){ // loop through data
3027  if($captain == 'parts'){ // loop thru parts
3028  $b .= "&nbsp;&nbsp;$captain:<br>";
3029  //if(is_array($tenille)){
3030  foreach($tenille as $joanie => $chachi){
3031  $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
3032  }
3033  //}
3034  } else {
3035  $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
3036  }
3037  }
3038  } else {
3039  $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
3040  }
3041  }
3042  $b .= '</div>';
3043  }
3044  $b .= '
3045  <ul>
3046  </div>
3047  </div></body></html>';
3048  return $b;
3049  }
3050 
3062  function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
3063  {
3064  $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
3065  $SERVER_PORT = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : $GLOBALS['SERVER_PORT'];
3066  if ($SERVER_PORT == 80) {
3067  $SERVER_PORT = '';
3068  } else {
3069  $SERVER_PORT = ':' . $SERVER_PORT;
3070  }
3071  $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
3072  if(false == $namespace) {
3073  $namespace = "http://$SERVER_NAME/soap/$serviceName";
3074  }
3075 
3076  if(false == $endpoint) {
3077  if (isset($_SERVER['HTTPS'])) {
3078  $HTTPS = $_SERVER['HTTPS'];
3079  } elseif (isset($GLOBALS['HTTPS'])) {
3080  $HTTPS = $GLOBALS['HTTPS'];
3081  } else {
3082  $HTTPS = '0';
3083  }
3084  if ($HTTPS == '1' || $HTTPS == 'on') {
3085  $SCHEME = 'https';
3086  } else {
3087  $SCHEME = 'http';
3088  }
3089  $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
3090  }
3091 
3092  if(false == $schemaTargetNamespace) {
3093  $schemaTargetNamespace = $namespace;
3094  }
3095 
3096  $this->wsdl = new wsdl;
3097  $this->wsdl->serviceName = $serviceName;
3098  $this->wsdl->endpoint = $endpoint;
3099  $this->wsdl->namespaces['tns'] = $namespace;
3100  $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
3101  $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
3102  if ($schemaTargetNamespace != $namespace) {
3103  $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
3104  }
3105  $this->wsdl->schemas[$schemaTargetNamespace][0] = new xmlschema('', '', $this->wsdl->namespaces);
3106  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
3107  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
3108  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
3109  $this->wsdl->bindings[$serviceName.'Binding'] = array(
3110  'name'=>$serviceName.'Binding',
3111  'style'=>$style,
3112  'transport'=>$transport,
3113  'portType'=>$serviceName.'PortType');
3114  $this->wsdl->ports[$serviceName.'Port'] = array(
3115  'binding'=>$serviceName.'Binding',
3116  'location'=>$endpoint,
3117  'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
3118  }
3119 }
3120 
3121 
3122 
3123 ?><?php
3124 
3125 
3126 
3133 class wsdl extends nusoap_base {
3134  // URL or filename of the root of this WSDL
3135  var $wsdl;
3136  // define internal arrays of bindings, ports, operations, messages, etc.
3137  var $schemas = array();
3139  var $message = array();
3140  var $complexTypes = array();
3141  var $messages = array();
3144  var $portTypes = array();
3146  var $bindings = array();
3148  var $ports = array();
3150  var $opData = array();
3151  var $status = '';
3152  var $documentation = false;
3153  var $endpoint = '';
3154  // array of wsdl docs to import
3155  var $import = array();
3156  // parser vars
3157  var $parser;
3158  var $position = 0;
3159  var $depth = 0;
3160  var $depth_array = array();
3161  // for getting wsdl
3162  var $proxyhost = '';
3163  var $proxyport = '';
3164  var $proxyusername = '';
3165  var $proxypassword = '';
3166  var $timeout = 0;
3168 
3182  $this->wsdl = $wsdl;
3183  $this->proxyhost = $proxyhost;
3184  $this->proxyport = $proxyport;
3185  $this->proxyusername = $proxyusername;
3186  $this->proxypassword = $proxypassword;
3187  $this->timeout = $timeout;
3188  $this->response_timeout = $response_timeout;
3189 
3190  // parse wsdl file
3191  if ($wsdl != "") {
3192  $this->debug('initial wsdl URL: ' . $wsdl);
3193  $this->parseWSDL($wsdl);
3194  }
3195  // imports
3196  // TODO: handle imports more properly, grabbing them in-line and nesting them
3197  $imported_urls = array();
3198  $imported = 1;
3199  while ($imported > 0) {
3200  $imported = 0;
3201  // Schema imports
3202  foreach ($this->schemas as $ns => $list) {
3203  foreach ($list as $xs) {
3204  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
3205  foreach ($xs->imports as $ns2 => $list2) {
3206  for ($ii = 0; $ii < count($list2); $ii++) {
3207  if (! $list2[$ii]['loaded']) {
3208  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
3209  $url = $list2[$ii]['location'];
3210  if ($url != '') {
3211  $urlparts = parse_url($url);
3212  if (!isset($urlparts['host'])) {
3213  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] .
3214  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
3215  }
3216  if (! in_array($url, $imported_urls)) {
3217  $this->parseWSDL($url);
3218  $imported++;
3219  $imported_urls[] = $url;
3220  }
3221  } else {
3222  $this->debug("Unexpected scenario: empty URL for unloaded import");
3223  }
3224  }
3225  }
3226  }
3227  }
3228  }
3229  // WSDL imports
3230  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
3231  foreach ($this->import as $ns => $list) {
3232  for ($ii = 0; $ii < count($list); $ii++) {
3233  if (! $list[$ii]['loaded']) {
3234  $this->import[$ns][$ii]['loaded'] = true;
3235  $url = $list[$ii]['location'];
3236  if ($url != '') {
3237  $urlparts = parse_url($url);
3238  if (!isset($urlparts['host'])) {
3239  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] .
3240  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
3241  }
3242  if (! in_array($url, $imported_urls)) {
3243  $this->parseWSDL($url);
3244  $imported++;
3245  $imported_urls[] = $url;
3246  }
3247  } else {
3248  $this->debug("Unexpected scenario: empty URL for unloaded import");
3249  }
3250  }
3251  }
3252  }
3253  }
3254  // add new data to operation data
3255  foreach($this->bindings as $binding => $bindingData) {
3256  if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
3257  foreach($bindingData['operations'] as $operation => $data) {
3258  $this->debug('post-parse data gathering for ' . $operation);
3259  $this->bindings[$binding]['operations'][$operation]['input'] =
3260  isset($this->bindings[$binding]['operations'][$operation]['input']) ?
3261  array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
3262  $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
3263  $this->bindings[$binding]['operations'][$operation]['output'] =
3264  isset($this->bindings[$binding]['operations'][$operation]['output']) ?
3265  array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
3266  $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
3267  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
3268  $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
3269  }
3270  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
3271  $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
3272  }
3273  if (isset($bindingData['style'])) {
3274  $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
3275  }
3276  $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
3277  $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
3278  $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
3279  }
3280  }
3281  }
3282  }
3283 
3290  function parseWSDL($wsdl = '')
3291  {
3292  if ($wsdl == '') {
3293  $this->debug('no wsdl passed to parseWSDL()!!');
3294  $this->setError('no wsdl passed to parseWSDL()!!');
3295  return false;
3296  }
3297 
3298  // parse $wsdl for url format
3299  $wsdl_props = parse_url($wsdl);
3300 
3301  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
3302  $this->debug('getting WSDL http(s) URL ' . $wsdl);
3303  // get wsdl
3304  $tr = new soap_transport_http($wsdl);
3305  $tr->request_method = 'GET';
3306  $tr->useSOAPAction = false;
3307  if($this->proxyhost && $this->proxyport){
3308  $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
3309  }
3310  if (isset($wsdl_props['user'])) {
3311  $tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']);
3312  }
3313  $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
3314  //$this->debug("WSDL request\n" . $tr->outgoing_payload);
3315  //$this->debug("WSDL response\n" . $tr->incoming_payload);
3316  $this->debug("transport debug data...\n" . $tr->debug_str);
3317  // catch errors
3318  if($err = $tr->getError() ){
3319  $errstr = 'HTTP ERROR: '.$err;
3320  $this->debug($errstr);
3321  $this->setError($errstr);
3322  unset($tr);
3323  return false;
3324  }
3325  unset($tr);
3326  } else {
3327  // $wsdl is not http(s), so treat it as a file URL or plain file path
3328  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
3329  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
3330  } else {
3331  $path = $wsdl;
3332  }
3333  $this->debug('getting WSDL file ' . $path);
3334  if ($fp = @fopen($path, 'r')) {
3335  $wsdl_string = '';
3336  while ($data = fread($fp, 32768)) {
3337  $wsdl_string .= $data;
3338  }
3339  fclose($fp);
3340  } else {
3341  $errstr = "Bad path to WSDL file $path";
3342  $this->debug($errstr);
3343  $this->setError($errstr);
3344  return false;
3345  }
3346  }
3347  // end new code added
3348  // Create an XML parser.
3349  $this->parser = xml_parser_create();
3350  // Set the options for parsing the XML data.
3351  // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
3352  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
3353  // Set the object for the parser.
3354  xml_set_object($this->parser, $this);
3355  // Set the element handlers for the parser.
3356  xml_set_element_handler($this->parser, 'start_element', 'end_element');
3357  xml_set_character_data_handler($this->parser, 'character_data');
3358  // Parse the XML file.
3359  if (!xml_parse($this->parser, $wsdl_string, true)) {
3360  // Display an error message.
3361  $errstr = sprintf(
3362  'XML error parsing WSDL from %s on line %d: %s',
3363  $wsdl,
3364  xml_get_current_line_number($this->parser),
3365  xml_error_string(xml_get_error_code($this->parser))
3366  );
3367  $this->debug($errstr);
3368  $this->debug("XML payload:\n" . $wsdl_string);
3369  $this->setError($errstr);
3370  return false;
3371  }
3372  // free the parser
3373  xml_parser_free($this->parser);
3374  // catch wsdl parse errors
3375  if($this->getError()){
3376  return false;
3377  }
3378  return true;
3379  }
3380 
3389  function start_element($parser, $name, $attrs)
3390  {
3391  if ($this->status == 'schema') {
3392  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
3393  $this->debug_str .= $this->currentSchema->debug_str;
3394  $this->currentSchema->debug_str = '';
3395  } elseif (ereg('schema$', $name)) {
3396  // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
3397  $this->status = 'schema';
3398  $this->currentSchema = new xmlschema('', '', $this->namespaces);
3399  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
3400  $this->debug_str .= $this->currentSchema->debug_str;
3401  $this->currentSchema->debug_str = '';
3402  } else {
3403  // position in the total number of elements, starting from 0
3404  $pos = $this->position++;
3405  $depth = $this->depth++;
3406  // set self as current value for this depth
3407  $this->depth_array[$depth] = $pos;
3408  $this->message[$pos] = array('cdata' => '');
3409  // get element prefix
3410  if (ereg(':', $name)) {
3411  // get ns prefix
3412  $prefix = substr($name, 0, strpos($name, ':'));
3413  // get ns
3414  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
3415  // get unqualified name
3416  $name = substr(strstr($name, ':'), 1);
3417  }
3418 
3419  if (count($attrs) > 0) {
3420  foreach($attrs as $k => $v) {
3421  // if ns declarations, add to class level array of valid namespaces
3422  if (ereg("^xmlns", $k)) {
3423  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
3424  $this->namespaces[$ns_prefix] = $v;
3425  } else {
3426  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
3427  }
3428  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema') {
3429  $this->XMLSchemaVersion = $v;
3430  $this->namespaces['xsi'] = $v . '-instance';
3431  }
3432  } //
3433  // expand each attribute
3434  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
3435  if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
3436  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
3437  }
3438  $eAttrs[$k] = $v;
3439  }
3440  $attrs = $eAttrs;
3441  } else {
3442  $attrs = array();
3443  }
3444  // find status, register data
3445  switch ($this->status) {
3446  case 'message':
3447  if ($name == 'part') {
3448  if (isset($attrs['type'])) {
3449  $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
3450  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
3451  }
3452  if (isset($attrs['element'])) {
3453  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
3454  }
3455  }
3456  break;
3457  case 'portType':
3458  switch ($name) {
3459  case 'operation':
3460  $this->currentPortOperation = $attrs['name'];
3461  $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
3462  if (isset($attrs['parameterOrder'])) {
3463  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
3464  }
3465  break;
3466  case 'documentation':
3467  $this->documentation = true;
3468  break;
3469  // merge input/output data
3470  default:
3471  $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
3472  $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
3473  break;
3474  }
3475  break;
3476  case 'binding':
3477  switch ($name) {
3478  case 'binding':
3479  // get ns prefix
3480  if (isset($attrs['style'])) {
3481  $this->bindings[$this->currentBinding]['prefix'] = $prefix;
3482  }
3483  $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
3484  break;
3485  case 'header':
3486  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
3487  break;
3488  case 'operation':
3489  if (isset($attrs['soapAction'])) {
3490  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
3491  }
3492  if (isset($attrs['style'])) {
3493  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
3494  }
3495  if (isset($attrs['name'])) {
3496  $this->currentOperation = $attrs['name'];
3497  $this->debug("current binding operation: $this->currentOperation");
3498  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
3499  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
3500  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
3501  }
3502  break;
3503  case 'input':
3504  $this->opStatus = 'input';
3505  break;
3506  case 'output':
3507  $this->opStatus = 'output';
3508  break;
3509  case 'body':
3510  if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
3511  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
3512  } else {
3513  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
3514  }
3515  break;
3516  }
3517  break;
3518  case 'service':
3519  switch ($name) {
3520  case 'port':
3521  $this->currentPort = $attrs['name'];
3522  $this->debug('current port: ' . $this->currentPort);
3523  $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
3524 
3525  break;
3526  case 'address':
3527  $this->ports[$this->currentPort]['location'] = $attrs['location'];
3528  $this->ports[$this->currentPort]['bindingType'] = $namespace;
3529  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
3530  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
3531  break;
3532  }
3533  break;
3534  }
3535  // set status
3536  switch ($name) {
3537  case 'import':
3538  if (isset($attrs['location'])) {
3539  $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
3540  $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
3541  } else {
3542  $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
3543  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
3544  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
3545  }
3546  $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
3547  }
3548  break;
3549  //wait for schema
3550  //case 'types':
3551  // $this->status = 'schema';
3552  // break;
3553  case 'message':
3554  $this->status = 'message';
3555  $this->messages[$attrs['name']] = array();
3556  $this->currentMessage = $attrs['name'];
3557  break;
3558  case 'portType':
3559  $this->status = 'portType';
3560  $this->portTypes[$attrs['name']] = array();
3561  $this->currentPortType = $attrs['name'];
3562  break;
3563  case "binding":
3564  if (isset($attrs['name'])) {
3565  // get binding name
3566  if (strpos($attrs['name'], ':')) {
3567  $this->currentBinding = $this->getLocalPart($attrs['name']);
3568  } else {
3569  $this->currentBinding = $attrs['name'];
3570  }
3571  $this->status = 'binding';
3572  $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
3573  $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
3574  }
3575  break;
3576  case 'service':
3577  $this->serviceName = $attrs['name'];
3578  $this->status = 'service';
3579  $this->debug('current service: ' . $this->serviceName);
3580  break;
3581  case 'definitions':
3582  foreach ($attrs as $name => $value) {
3583  $this->wsdl_info[$name] = $value;
3584  }
3585  break;
3586  }
3587  }
3588  }
3589 
3597  function end_element($parser, $name){
3598  // unset schema status
3599  if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
3600  $this->status = "";
3601  $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
3602  }
3603  if ($this->status == 'schema') {
3604  $this->currentSchema->schemaEndElement($parser, $name);
3605  } else {
3606  // bring depth down a notch
3607  $this->depth--;
3608  }
3609  // end documentation
3610  if ($this->documentation) {
3611  //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
3612  //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
3613  $this->documentation = false;
3614  }
3615  }
3616 
3625  {
3626  $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
3627  if (isset($this->message[$pos]['cdata'])) {
3628  $this->message[$pos]['cdata'] .= $data;
3629  }
3630  if ($this->documentation) {
3631  $this->documentation .= $data;
3632  }
3633  }
3634 
3635  function getBindingData($binding)
3636  {
3637  if (is_array($this->bindings[$binding])) {
3638  return $this->bindings[$binding];
3639  }
3640  }
3641 
3649  function getOperations($bindingType = 'soap')
3650  {
3651  $ops = array();
3652  if ($bindingType == 'soap') {
3653  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
3654  }
3655  // loop thru ports
3656  foreach($this->ports as $port => $portData) {
3657  // binding type of port matches parameter
3658  if ($portData['bindingType'] == $bindingType) {
3659  //$this->debug("getOperations for port $port");
3660  //$this->debug("port data: " . $this->varDump($portData));
3661  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
3662  // merge bindings
3663  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
3664  $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
3665  }
3666  }
3667  }
3668  return $ops;
3669  }
3670 
3679  function getOperationData($operation, $bindingType = 'soap')
3680  {
3681  if ($bindingType == 'soap') {
3682  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
3683  }
3684  // loop thru ports
3685  foreach($this->ports as $port => $portData) {
3686  // binding type of port matches parameter
3687  if ($portData['bindingType'] == $bindingType) {
3688  // get binding
3689  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
3690  foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
3691  if ($operation == $bOperation) {
3692  $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
3693  return $opData;
3694  }
3695  }
3696  }
3697  }
3698  }
3699 
3718  function getTypeDef($type, $ns) {
3719  if ((! $ns) && isset($this->namespaces['tns'])) {
3720  $ns = $this->namespaces['tns'];
3721  }
3722  if (isset($this->schemas[$ns])) {
3723  foreach ($this->schemas[$ns] as $xs) {
3724  $t = $xs->getTypeDef($type);
3725  $this->debug_str .= $xs->debug_str;
3726  $xs->debug_str = '';
3727  if ($t) {
3728  return $t;
3729  }
3730  }
3731  }
3732  return false;
3733  }
3734 
3741  function serialize()
3742  {
3743  $xml = '<?xml version="1.0" encoding="ISO-8859-1"?><definitions';
3744  foreach($this->namespaces as $k => $v) {
3745  $xml .= " xmlns:$k=\"$v\"";
3746  }
3747  // 10.9.02 - add poulter fix for wsdl and tns declarations
3748  if (isset($this->namespaces['wsdl'])) {
3749  $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
3750  }
3751  if (isset($this->namespaces['tns'])) {
3752  $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
3753  }
3754  $xml .= '>';
3755  // imports
3756  if (sizeof($this->import) > 0) {
3757  foreach($this->import as $ns => $list) {
3758  foreach ($list as $ii) {
3759  if ($ii['location'] != '') {
3760  $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
3761  } else {
3762  $xml .= '<import namespace="' . $ns . '" />';
3763  }
3764  }
3765  }
3766  }
3767  // types
3768  if (count($this->schemas)>=1) {
3769  $xml .= '<types>';
3770  foreach ($this->schemas as $ns => $list) {
3771  foreach ($list as $xs) {
3772  $xml .= $xs->serializeSchema();
3773  }
3774  }
3775  $xml .= '</types>';
3776  }
3777  // messages
3778  if (count($this->messages) >= 1) {
3779  foreach($this->messages as $msgName => $msgParts) {
3780  $xml .= '<message name="' . $msgName . '">';
3781  if(is_array($msgParts)){
3782  foreach($msgParts as $partName => $partType) {
3783  // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
3784  if (strpos($partType, ':')) {
3785  $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
3786  } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
3787  // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
3788  $typePrefix = 'xsd';
3789  } else {
3790  foreach($this->typemap as $ns => $types) {
3791  if (isset($types[$partType])) {
3792  $typePrefix = $this->getPrefixFromNamespace($ns);
3793  }
3794  }
3795  if (!isset($typePrefix)) {
3796  die("$partType has no namespace!");
3797  }
3798  }
3799  $xml .= '<part name="' . $partName . '" type="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
3800  }
3801  }
3802  $xml .= '</message>';
3803  }
3804  }
3805  // bindings & porttypes
3806  if (count($this->bindings) >= 1) {
3807  $binding_xml = '';
3808  $portType_xml = '';
3809  foreach($this->bindings as $bindingName => $attrs) {
3810  $binding_xml .= '<binding name="' . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
3811  $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
3812  $portType_xml .= '<portType name="' . $attrs['portType'] . '">';
3813  foreach($attrs['operations'] as $opName => $opParts) {
3814  $binding_xml .= '<operation name="' . $opName . '">';
3815  $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $attrs['style'] . '"/>';
3816  if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
3817  $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
3818  } else {
3819  $enc_style = '';
3820  }
3821  $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
3822  if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
3823  $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
3824  } else {
3825  $enc_style = '';
3826  }
3827  $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
3828  $binding_xml .= '</operation>';
3829  $portType_xml .= '<operation name="' . $opParts['name'] . '"';
3830  if (isset($opParts['parameterOrder'])) {
3831  $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
3832  }
3833  $portType_xml .= '>';
3834  if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
3835  $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
3836  }
3837  $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
3838  $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
3839  $portType_xml .= '</operation>';
3840  }
3841  $portType_xml .= '</portType>';
3842  $binding_xml .= '</binding>';
3843  }
3844  $xml .= $portType_xml . $binding_xml;
3845  }
3846  // services
3847  $xml .= '<service name="' . $this->serviceName . '">';
3848  if (count($this->ports) >= 1) {
3849  foreach($this->ports as $pName => $attrs) {
3850  $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
3851  $xml .= '<soap:address location="' . $attrs['location'] . '"/>';
3852  $xml .= '</port>';
3853  }
3854  }
3855  $xml .= '</service>';
3856  return $xml . '</definitions>';
3857  }
3858 
3870  function serializeRPCParameters($operation, $direction, $parameters)
3871  {
3872  $this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion);
3873 
3874  if ($direction != 'input' && $direction != 'output') {
3875  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
3876  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
3877  return false;
3878  }
3879  if (!$opData = $this->getOperationData($operation)) {
3880  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
3881  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
3882  return false;
3883  }
3884  $this->debug($this->varDump($opData));
3885 
3886  // Get encoding style for output and set to current
3887  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
3888  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
3889  $encodingStyle = $opData['output']['encodingStyle'];
3890  $enc_style = $encodingStyle;
3891  }
3892 
3893  // set input params
3894  $xml = '';
3895  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
3896 
3897  $use = $opData[$direction]['use'];
3898  $this->debug("use=$use");
3899  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
3900  if (is_array($parameters)) {
3901  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
3902  $this->debug('have ' . $parametersArrayType . ' parameters');
3903  foreach($opData[$direction]['parts'] as $name => $type) {
3904  $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
3905  // Track encoding style
3906  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
3907  $encodingStyle = $opData[$direction]['encodingStyle'];
3908  $enc_style = $encodingStyle;
3909  } else {
3910  $enc_style = false;
3911  }
3912  // NOTE: add error handling here
3913  // if serializeType returns false, then catch global error and fault
3914  if ($parametersArrayType == 'arraySimple') {
3915  $p = array_shift($parameters);
3916  $this->debug('calling serializeType w/indexed param');
3917  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
3918  } elseif (isset($parameters[$name])) {
3919  $this->debug('calling serializeType w/named param');
3920  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
3921  } else {
3922  // TODO: only send nillable
3923  $this->debug('calling serializeType w/null param');
3924  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
3925  }
3926  }
3927  } else {
3928  $this->debug('no parameters passed.');
3929  }
3930  }
3931  return $xml;
3932  }
3933 
3945  function serializeParameters($operation, $direction, $parameters)
3946  {
3947  $this->debug('in serializeParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion);
3948 
3949  if ($direction != 'input' && $direction != 'output') {
3950  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
3951  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
3952  return false;
3953  }
3954  if (!$opData = $this->getOperationData($operation)) {
3955  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
3956  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
3957  return false;
3958  }
3959  $this->debug($this->varDump($opData));
3960 
3961  // Get encoding style for output and set to current
3962  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
3963  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
3964  $encodingStyle = $opData['output']['encodingStyle'];
3965  $enc_style = $encodingStyle;
3966  }
3967 
3968  // set input params
3969  $xml = '';
3970  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
3971 
3972  $use = $opData[$direction]['use'];
3973  $this->debug("use=$use");
3974  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
3975  if (is_array($parameters)) {
3976  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
3977  $this->debug('have ' . $parametersArrayType . ' parameters');
3978  foreach($opData[$direction]['parts'] as $name => $type) {
3979  $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
3980  // Track encoding style
3981  if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
3982  $encodingStyle = $opData[$direction]['encodingStyle'];
3983  $enc_style = $encodingStyle;
3984  } else {
3985  $enc_style = false;
3986  }
3987  // NOTE: add error handling here
3988  // if serializeType returns false, then catch global error and fault
3989  if ($parametersArrayType == 'arraySimple') {
3990  $p = array_shift($parameters);
3991  $this->debug('calling serializeType w/indexed param');
3992  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
3993  } elseif (isset($parameters[$name])) {
3994  $this->debug('calling serializeType w/named param');
3995  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
3996  } else {
3997  // TODO: only send nillable
3998  $this->debug('calling serializeType w/null param');
3999  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
4000  }
4001  }
4002  } else {
4003  $this->debug('no parameters passed.');
4004  }
4005  }
4006  return $xml;
4007  }
4008 
4020  function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false)
4021  {
4022  $this->debug("in serializeType: $name, $type, $value, $use, $encodingStyle");
4023  if($use == 'encoded' && $encodingStyle) {
4024  $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
4025  }
4026 
4027  // if a soap_val has been supplied, let its type override the WSDL
4028  if (is_object($value) && get_class($value) == 'soapval') {
4029  // TODO: get attributes from soapval?
4030  if ($value->type_ns) {
4031  $type = $value->type_ns . ':' . $value->type;
4032  } else {
4033  $type = $value->type;
4034  }
4035  $value = $value->value;
4036  $forceType = true;
4037  $this->debug("in serializeType: soapval overrides type to $type, value to $value");
4038  } else {
4039  $forceType = false;
4040  }
4041 
4042  $xml = '';
4043  if (strpos($type, ':')) {
4044  $uqType = substr($type, strrpos($type, ':') + 1);
4045  $ns = substr($type, 0, strrpos($type, ':'));
4046  $this->debug("got a prefixed type: $uqType, $ns");
4047  if ($this->getNamespaceFromPrefix($ns)) {
4048  $ns = $this->getNamespaceFromPrefix($ns);
4049  $this->debug("expanded prefixed type: $uqType, $ns");
4050  }
4051 
4052  if($ns == $this->XMLSchemaVersion){
4053 
4054  if (is_null($value)) {
4055  if ($use == 'literal') {
4056  // TODO: depends on nillable
4057  return "<$name/>";
4058  } else {
4059  return "<$name xsi:nil=\"true\"/>";
4060  }
4061  }
4062  if ($uqType == 'boolean' && !$value) {
4063  $value = 'false';
4064  } elseif ($uqType == 'boolean') {
4065  $value = 'true';
4066  }
4067  if ($uqType == 'string' && gettype($value) == 'string') {
4068  $value = $this->expandEntities($value);
4069  }
4070  // it's a scalar
4071  // TODO: what about null/nil values?
4072  // check type isn't a custom type extending xmlschema namespace
4073  if (!$this->getTypeDef($uqType, $ns)) {
4074  if ($use == 'literal') {
4075  if ($forceType) {
4076  return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\">$value</$name>";
4077  } else {
4078  return "<$name>$value</$name>";
4079  }
4080  } else {
4081  return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\"$encodingStyle>$value</$name>";
4082  }
4083  }
4084  } else if ($ns == 'http://xml.apache.org/xml-soap') {
4085  if ($uqType == 'Map') {
4086  $contents = '';
4087  foreach($value as $k => $v) {
4088  $this->debug("serializing map element: key $k, value $v");
4089  $contents .= '<item>';
4090  $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
4091  $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
4092  $contents .= '</item>';
4093  }
4094  if ($use == 'literal') {
4095  if ($forceType) {
4096  return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\">$contents</$name>";
4097  } else {
4098  return "<$name>$contents</$name>";
4099  }
4100  } else {
4101  return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\"$encodingStyle>$contents</$name>";
4102  }
4103  }
4104  }
4105  } else {
4106  $this->debug("No namespace for type $type");
4107  $ns = '';
4108  $uqType = $type;
4109  }
4110  if(!$typeDef = $this->getTypeDef($uqType, $ns)){
4111  $this->setError("$type ($uqType) is not a supported type.");
4112  $this->debug("$type ($uqType) is not a supported type.");
4113  return false;
4114  } else {
4115  foreach($typeDef as $k => $v) {
4116  $this->debug("typedef, $k: $v");
4117  }
4118  }
4119  $phpType = $typeDef['phpType'];
4120  $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
4121  // if php type == struct, map value to the <all> element names
4122  if ($phpType == 'struct') {
4123  if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
4124  $elementName = $uqType;
4125  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
4126  $elementNS = " xmlns=\"$ns\"";
4127  }
4128  } else {
4129  $elementName = $name;
4130  $elementNS = '';
4131  }
4132  if (is_null($value)) {
4133  if ($use == 'literal') {
4134  // TODO: depends on nillable
4135  return "<$elementName$elementNS/>";
4136  } else {
4137  return "<$elementName$elementNS xsi:nil=\"true\"/>";
4138  }
4139  }
4140  if ($use == 'literal') {
4141  if ($forceType) {
4142  $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
4143  } else {
4144  $xml = "<$elementName$elementNS>";
4145  }
4146  } else {
4147  $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
4148  }
4149 
4150  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
4151  if (is_array($value)) {
4152  $xvalue = $value;
4153  } elseif (is_object($value)) {
4154  $xvalue = get_object_vars($value);
4155  } else {
4156  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
4157  $xvalue = array();
4158  }
4159  // toggle whether all elements are present - ideally should validate against schema
4160  if(count($typeDef['elements']) != count($xvalue)){
4161  $optionals = true;
4162  }
4163  foreach($typeDef['elements'] as $eName => $attrs) {
4164  // if user took advantage of a minOccurs=0, then only serialize named parameters
4165  if(isset($optionals) && !isset($xvalue[$eName])){
4166  // do nothing
4167  } else {
4168  // get value
4169  if (isset($xvalue[$eName])) {
4170  $v = $xvalue[$eName];
4171  } else {
4172  $v = null;
4173  }
4174  // TODO: if maxOccurs > 1 (not just unbounded), then allow serialization of an array
4175  if (isset($attrs['maxOccurs']) && $attrs['maxOccurs'] == 'unbounded' && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
4176  $vv = $v;
4177  foreach ($vv as $k => $v) {
4178  if (isset($attrs['type'])) {
4179  // serialize schema-defined type
4180  $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
4181  } else {
4182  // serialize generic type
4183  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
4184  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
4185  }
4186  }
4187  } else {
4188  if (isset($attrs['type'])) {
4189  // serialize schema-defined type
4190  $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
4191  } else {
4192  // serialize generic type
4193  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
4194  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
4195  }
4196  }
4197  }
4198  }
4199  } else {
4200  $this->debug("Expected elements for XML Schema type $ns:$uqType");
4201  }
4202  $xml .= "</$elementName>";
4203  } elseif ($phpType == 'array') {
4204  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
4205  $elementNS = " xmlns=\"$ns\"";
4206  } else {
4207  $elementNS = '';
4208  }
4209  if (is_null($value)) {
4210  if ($use == 'literal') {
4211  // TODO: depends on nillable
4212  return "<$name$elementNS/>";
4213  } else {
4214  return "<$name$elementNS xsi:nil=\"true\"/>";
4215  }
4216  }
4217  if (isset($typeDef['multidimensional'])) {
4218  $nv = array();
4219  foreach($value as $v) {
4220  $cols = ',' . sizeof($v);
4221  $nv = array_merge($nv, $v);
4222  }
4223  $value = $nv;
4224  } else {
4225  $cols = '';
4226  }
4227  if (is_array($value) && sizeof($value) >= 1) {
4228  $rows = sizeof($value);
4229  $contents = '';
4230  foreach($value as $k => $v) {
4231  $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
4232  //if (strpos($typeDef['arrayType'], ':') ) {
4233  if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
4234  $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
4235  } else {
4236  $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
4237  }
4238  }
4239  $this->debug('contents: '.$this->varDump($contents));
4240  } else {
4241  $rows = 0;
4242  $contents = null;
4243  }
4244  // TODO: for now, an empty value will be serialized as a zero element
4245  // array. Revisit this when coding the handling of null/nil values.
4246  if ($use == 'literal') {
4247  $xml = "<$name$elementNS>"
4248  .$contents
4249  ."</$name>";
4250  } else {
4251  $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
4252  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
4253  .':arrayType="'
4254  .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
4255  .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
4256  .$contents
4257  ."</$name>";
4258  }
4259  } elseif ($phpType == 'scalar') {
4260  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
4261  $elementNS = " xmlns=\"$ns\"";
4262  } else {
4263  $elementNS = '';
4264  }
4265  if ($use == 'literal') {
4266  if ($forceType) {
4267  return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
4268  } else {
4269  return "<$name$elementNS>$value</$name>";
4270  }
4271  } else {
4272  return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
4273  }
4274  }
4275  $this->debug('returning: '.$this->varDump($xml));
4276  return $xml;
4277  }
4278 
4298  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
4299  if (count($elements) > 0) {
4300  foreach($elements as $n => $e){
4301  // expand each element
4302  foreach ($e as $k => $v) {
4303  $k = strpos($k,':') ? $this->expandQname($k) : $k;
4304  $v = strpos($v,':') ? $this->expandQname($v) : $v;
4305  $ee[$k] = $v;
4306  }
4307  $eElements[$n] = $ee;
4308  }
4309  $elements = $eElements;
4310  }
4311 
4312  if (count($attrs) > 0) {
4313  foreach($attrs as $n => $a){
4314  // expand each attribute
4315  foreach ($a as $k => $v) {
4316  $k = strpos($k,':') ? $this->expandQname($k) : $k;
4317  $v = strpos($v,':') ? $this->expandQname($v) : $v;
4318  $aa[$k] = $v;
4319  }
4320  $eAttrs[$n] = $aa;
4321  }
4322  $attrs = $eAttrs;
4323  }
4324 
4325  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
4326  $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
4327 
4328  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
4329  $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
4330  }
4331 
4342  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
4343  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
4344 
4345  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
4346  $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType);
4347  }
4348 
4362  function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = ''){
4363  if ($style == 'rpc' && $use == 'encoded') {
4364  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4365  } else {
4366  $encodingStyle = '';
4367  }
4368  // get binding
4369  $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
4370  array(
4371  'name' => $name,
4372  'binding' => $this->serviceName . 'Binding',
4373  'endpoint' => $this->endpoint,
4374  'soapAction' => $soapaction,
4375  'style' => $style,
4376  'input' => array(
4377  'use' => $use,
4378  'namespace' => $namespace,
4379  'encodingStyle' => $encodingStyle,
4380  'message' => $name . 'Request',
4381  'parts' => $in),
4382  'output' => array(
4383  'use' => $use,
4384  'namespace' => $namespace,
4385  'encodingStyle' => $encodingStyle,
4386  'message' => $name . 'Response',
4387  'parts' => $out),
4388  'namespace' => $namespace,
4389  'transport' => 'http://schemas.xmlsoap.org/soap/http',
4390  'documentation' => $documentation);
4391  // add portTypes
4392  // add messages
4393  if($in)
4394  {
4395  foreach($in as $pName => $pType)
4396  {
4397  if(strpos($pType,':')) {
4398  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
4399  }
4400  $this->messages[$name.'Request'][$pName] = $pType;
4401  }
4402  } else {
4403  $this->messages[$name.'Request']= '0';
4404  }
4405  if($out)
4406  {
4407  foreach($out as $pName => $pType)
4408  {
4409  if(strpos($pType,':')) {
4410  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
4411  }
4412  $this->messages[$name.'Response'][$pName] = $pType;
4413  }
4414  } else {
4415  $this->messages[$name.'Response']= '0';
4416  }
4417  return true;
4418  }
4419 }
4420 ?><?php
4421 
4422 
4423 
4431 class soap_parser extends nusoap_base {
4432 
4433  var $xml = '';
4434  var $xml_encoding = '';
4435  var $method = '';
4436  var $root_struct = '';
4439  var $root_header = '';
4440  var $document = ''; // incoming SOAP body (text)
4441  // determines where in the message we are (envelope,header,body,method)
4442  var $status = '';
4443  var $position = 0;
4444  var $depth = 0;
4446  var $namespaces = array();
4447  var $message = array();
4448  var $parent = '';
4449  var $fault = false;
4450  var $fault_code = '';
4451  var $fault_str = '';
4452  var $fault_detail = '';
4453  var $depth_array = array();
4454  var $debug_flag = true;
4455  var $soapresponse = NULL;
4456  var $responseHeaders = ''; // incoming SOAP headers (text)
4458  // for multiref parsing:
4459  // array of id => pos
4460  var $ids = array();
4461  // array of id => hrefs => pos
4462  var $multirefs = array();
4463  // toggle for auto-decoding element content
4464  var $decode_utf8 = false;
4465 
4475  function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=false){
4476  $this->xml = $xml;
4477  $this->xml_encoding = $encoding;
4478  $this->method = $method;
4479  $this->decode_utf8 = $decode_utf8;
4480 
4481  // Check whether content has been read.
4482  if(!empty($xml)){
4483  $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding);
4484  // Create an XML parser - why not xml_parser_create_ns?
4485  $this->parser = xml_parser_create($this->xml_encoding);
4486  // Set the options for parsing the XML data.
4487  //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4488  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4489  xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
4490  // Set the object for the parser.
4491  xml_set_object($this->parser, $this);
4492  // Set the element handlers for the parser.
4493  xml_set_element_handler($this->parser, 'start_element','end_element');
4494  xml_set_character_data_handler($this->parser,'character_data');
4495 
4496  // Parse the XML file.
4497  if(!xml_parse($this->parser,$xml,true)){
4498  // Display an error message.
4499  $err = sprintf('XML error parsing SOAP payload on line %d: %s',
4500  xml_get_current_line_number($this->parser),
4501  xml_error_string(xml_get_error_code($this->parser)));
4502  $this->debug($err);
4503  $this->debug("XML payload:\n" . $xml);
4504  $this->setError($err);
4505  } else {
4506  $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
4507  // get final value
4508  $this->soapresponse = $this->message[$this->root_struct]['result'];
4509  // get header value: no, because this is documented as XML string
4510 // if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
4511 // $this->responseHeaders = $this->message[$this->root_header]['result'];
4512 // }
4513  // resolve hrefs/ids
4514  if(sizeof($this->multirefs) > 0){
4515  foreach($this->multirefs as $id => $hrefs){
4516  $this->debug('resolving multirefs for id: '.$id);
4517  $idVal = $this->buildVal($this->ids[$id]);
4518  foreach($hrefs as $refPos => $ref){
4519  $this->debug('resolving href at pos '.$refPos);
4520  $this->multirefs[$id][$refPos] = $idVal;
4521  }
4522  }
4523  }
4524  }
4525  xml_parser_free($this->parser);
4526  } else {
4527  $this->debug('xml was empty, didn\'t parse!');
4528  $this->setError('xml was empty, didn\'t parse!');
4529  }
4530  }
4531 
4540  function start_element($parser, $name, $attrs) {
4541  // position in a total number of elements, starting from 0
4542  // update class level pos
4543  $pos = $this->position++;
4544  // and set mine
4545  $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
4546  // depth = how many levels removed from root?
4547  // set mine as current global depth and increment global depth value
4548  $this->message[$pos]['depth'] = $this->depth++;
4549 
4550  // else add self as child to whoever the current parent is
4551  if($pos != 0){
4552  $this->message[$this->parent]['children'] .= '|'.$pos;
4553  }
4554  // set my parent
4555  $this->message[$pos]['parent'] = $this->parent;
4556  // set self as current parent
4557  $this->parent = $pos;
4558  // set self as current value for this depth
4559  $this->depth_array[$this->depth] = $pos;
4560  // get element prefix
4561  if(strpos($name,':')){
4562  // get ns prefix
4563  $prefix = substr($name,0,strpos($name,':'));
4564  // get unqualified name
4565  $name = substr(strstr($name,':'),1);
4566  }
4567  // set status
4568  if($name == 'Envelope'){
4569  $this->status = 'envelope';
4570  } elseif($name == 'Header'){
4571  $this->root_header = $pos;
4572  $this->status = 'header';
4573  } elseif($name == 'Body'){
4574  $this->status = 'body';
4575  $this->body_position = $pos;
4576  // set method
4577  } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
4578  $this->status = 'method';
4579  $this->root_struct_name = $name;
4580  $this->root_struct = $pos;
4581  $this->message[$pos]['type'] = 'struct';
4582  $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
4583  }
4584  // set my status
4585  $this->message[$pos]['status'] = $this->status;
4586  // set name
4587  $this->message[$pos]['name'] = htmlspecialchars($name);
4588  // set attrs
4589  $this->message[$pos]['attrs'] = $attrs;
4590 
4591  // loop through atts, logging ns and type declarations
4592  $attstr = '';
4593  foreach($attrs as $key => $value){
4594  $key_prefix = $this->getPrefix($key);
4595  $key_localpart = $this->getLocalPart($key);
4596  // if ns declarations, add to class level array of valid namespaces
4597  if($key_prefix == 'xmlns'){
4598  if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
4599  $this->XMLSchemaVersion = $value;
4600  $this->namespaces['xsd'] = $this->XMLSchemaVersion;
4601  $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
4602  }
4603  $this->namespaces[$key_localpart] = $value;
4604  // set method namespace
4605  if($name == $this->root_struct_name){
4606  $this->methodNamespace = $value;
4607  }
4608  // if it's a type declaration, set type
4609  } elseif($key_localpart == 'type'){
4610  $value_prefix = $this->getPrefix($value);
4611  $value_localpart = $this->getLocalPart($value);
4612  $this->message[$pos]['type'] = $value_localpart;
4613  $this->message[$pos]['typePrefix'] = $value_prefix;
4614  if(isset($this->namespaces[$value_prefix])){
4615  $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
4616  } else if(isset($attrs['xmlns:'.$value_prefix])) {
4617  $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
4618  }
4619  // should do something here with the namespace of specified type?
4620  } elseif($key_localpart == 'arrayType'){
4621  $this->message[$pos]['type'] = 'array';
4622  /* do arrayType ereg here
4623  [1] arrayTypeValue ::= atype asize
4624  [2] atype ::= QName rank*
4625  [3] rank ::= '[' (',')* ']'
4626  [4] asize ::= '[' length~ ']'
4627  [5] length ::= nextDimension* Digit+
4628  [6] nextDimension ::= Digit+ ','
4629  */
4630  $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
4631  if(ereg($expr,$value,$regs)){
4632  $this->message[$pos]['typePrefix'] = $regs[1];
4633  $this->message[$pos]['arrayTypePrefix'] = $regs[1];
4634  if (isset($this->namespaces[$regs[1]])) {
4635  $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
4636  } else if (isset($attrs['xmlns:'.$regs[1]])) {
4637  $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
4638  }
4639  $this->message[$pos]['arrayType'] = $regs[2];
4640  $this->message[$pos]['arraySize'] = $regs[3];
4641  $this->message[$pos]['arrayCols'] = $regs[4];
4642  }
4643  }
4644  // log id
4645  if($key == 'id'){
4646  $this->ids[$value] = $pos;
4647  }
4648  // root
4649  if($key_localpart == 'root' && $value == 1){
4650  $this->status = 'method';
4651  $this->root_struct_name = $name;
4652  $this->root_struct = $pos;
4653  $this->debug("found root struct $this->root_struct_name, pos $pos");
4654  }
4655  // for doclit
4656  $attstr .= " $key=\"$value\"";
4657  }
4658  // get namespace - must be done after namespace atts are processed
4659  if(isset($prefix)){
4660  $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
4661  $this->default_namespace = $this->namespaces[$prefix];
4662  } else {
4663  $this->message[$pos]['namespace'] = $this->default_namespace;
4664  }
4665  if($this->status == 'header'){
4666  if ($this->root_header != $pos) {
4667  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
4668  }
4669  } elseif($this->root_struct_name != ''){
4670  $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
4671  }
4672  }
4673 
4681  function end_element($parser, $name) {
4682  // position of current element is equal to the last value left in depth_array for my depth
4683  $pos = $this->depth_array[$this->depth--];
4684 
4685  // get element prefix
4686  if(strpos($name,':')){
4687  // get ns prefix
4688  $prefix = substr($name,0,strpos($name,':'));
4689  // get unqualified name
4690  $name = substr(strstr($name,':'),1);
4691  }
4692 
4693  // build to native type
4694  if(isset($this->body_position) && $pos > $this->body_position){
4695  // deal w/ multirefs
4696  if(isset($this->message[$pos]['attrs']['href'])){
4697  // get id
4698  $id = substr($this->message[$pos]['attrs']['href'],1);
4699  // add placeholder to href array
4700  $this->multirefs[$id][$pos] = 'placeholder';
4701  // add set a reference to it as the result value
4702  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
4703  // build complex values
4704  } elseif($this->message[$pos]['children'] != ''){
4705 
4706  // if result has already been generated (struct/array
4707  if(!isset($this->message[$pos]['result'])){
4708  $this->message[$pos]['result'] = $this->buildVal($pos);
4709  }
4710 
4711  // set value of simple type
4712  } else {
4713  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
4714  if (isset($this->message[$pos]['type'])) {
4715  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
4716  } else {
4717  $parent = $this->message[$pos]['parent'];
4718  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
4719  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
4720  } else {
4721  $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
4722  }
4723  }
4724 
4725  /* add value to parent's result, if parent is struct/array
4726  $parent = $this->message[$pos]['parent'];
4727  if($this->message[$parent]['type'] != 'map'){
4728  if(strtolower($this->message[$parent]['type']) == 'array'){
4729  $this->message[$parent]['result'][] = $this->message[$pos]['result'];
4730  } else {
4731  $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
4732  }
4733  }
4734  */
4735  }
4736  }
4737 
4738  // for doclit
4739  if($this->status == 'header'){
4740  if ($this->root_header != $pos) {
4741  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
4742  }
4743  } elseif($pos >= $this->root_struct){
4744  $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
4745  }
4746  // switch status
4747  if($pos == $this->root_struct){
4748  $this->status = 'body';
4749  $this->root_struct_namespace = $this->message[$pos]['namespace'];
4750  } elseif($name == 'Body'){
4751  $this->status = 'envelope';
4752  } elseif($name == 'Header'){
4753  $this->status = 'envelope';
4754  } elseif($name == 'Envelope'){
4755  //
4756  }
4757  // set parent back to my parent
4758  $this->parent = $this->message[$pos]['parent'];
4759  }
4760 
4768  function character_data($parser, $data){
4769  $pos = $this->depth_array[$this->depth];
4770  if ($this->xml_encoding=='UTF-8'){
4771  // TODO: add an option to disable this for folks who want
4772  // raw UTF-8 that, e.g., might not map to iso-8859-1
4773  // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
4774  if($this->decode_utf8){
4775  $data = utf8_decode($data);
4776  }
4777  }
4778  $this->message[$pos]['cdata'] .= $data;
4779  // for doclit
4780  if($this->status == 'header'){
4781  $this->responseHeaders .= $data;
4782  } else {
4783  $this->document .= $data;
4784  }
4785  }
4786 
4793  function get_response(){
4794  return $this->soapresponse;
4795  }
4796 
4803  function getHeaders(){
4804  return $this->responseHeaders;
4805  }
4806 
4813  function decode_entities($text){
4814  foreach($this->entities as $entity => $encoded){
4815  $text = str_replace($encoded,$entity,$text);
4816  }
4817  return $text;
4818  }
4819 
4828  function decodeSimple($value, $type, $typens) {
4829  // TODO: use the namespace!
4830  if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
4831  return (string) $value;
4832  }
4833  if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
4834  return (int) $value;
4835  }
4836  if ($type == 'float' || $type == 'double' || $type == 'decimal') {
4837  return (double) $value;
4838  }
4839  if ($type == 'boolean') {
4840  if (strtolower($value) == 'false' || strtolower($value) == 'f') {
4841  return false;
4842  }
4843  return (boolean) $value;
4844  }
4845  if ($type == 'base64' || $type == 'base64Binary') {
4846  return base64_decode($value);
4847  }
4848  // obscure numeric types
4849  if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
4850  || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
4851  || $type == 'unsignedInt'
4852  || $type == 'unsignedShort' || $type == 'unsignedByte') {
4853  return (int) $value;
4854  }
4855  // everything else
4856  return (string) $value;
4857  }
4858 
4865  function buildVal($pos){
4866  if(!isset($this->message[$pos]['type'])){
4867  $this->message[$pos]['type'] = '';
4868  }
4869  $this->debug('inside buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
4870  // if there are children...
4871  if($this->message[$pos]['children'] != ''){
4872  $children = explode('|',$this->message[$pos]['children']);
4873  array_shift($children); // knock off empty
4874  // md array
4875  if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
4876  $r=0; // rowcount
4877  $c=0; // colcount
4878  foreach($children as $child_pos){
4879  $this->debug("got an MD array element: $r, $c");
4880  $params[$r][] = $this->message[$child_pos]['result'];
4881  $c++;
4882  if($c == $this->message[$pos]['arrayCols']){
4883  $c = 0;
4884  $r++;
4885  }
4886  }
4887  // array
4888  } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
4889  $this->debug('adding array '.$this->message[$pos]['name']);
4890  foreach($children as $child_pos){
4891  $params[] = &$this->message[$child_pos]['result'];
4892  }
4893  // apache Map type: java hashtable
4894  } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
4895  foreach($children as $child_pos){
4896  $kv = explode("|",$this->message[$child_pos]['children']);
4897  $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
4898  }
4899  // generic compound type
4900  //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
4901  } else {
4902  // Apache Vector type: treat as an array
4903  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
4904  $notstruct = 1;
4905  } else {
4906  // is array or struct?
4907  foreach($children as $child_pos){
4908  if(isset($keys) && isset($keys[$this->message[$child_pos]['name']])){
4909  $notstruct = 1;
4910  break;
4911  }
4912  $keys[$this->message[$child_pos]['name']] = 1;
4913  }
4914  }
4915  //
4916  foreach($children as $child_pos){
4917  if(isset($notstruct)){
4918  $params[] = &$this->message[$child_pos]['result'];
4919  } else {
4920  if (isset($params[$this->message[$child_pos]['name']])) {
4921  // de-serialize repeated element name into an array
4922  if (!is_array($params[$this->message[$child_pos]['name']])) {
4923  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
4924  }
4925  $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
4926  } else {
4927  $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
4928  }
4929  }
4930  }
4931  }
4932  return is_array($params) ? $params : array();
4933  } else {
4934  $this->debug('no children');
4935  if(strpos($this->message[$pos]['cdata'],'&')){
4936  return strtr($this->message[$pos]['cdata'],array_flip($this->entities));
4937  } else {
4938  return $this->message[$pos]['cdata'];
4939  }
4940  }
4941  }
4942 }
4943 
4944 
4945 
4946 ?><?php
4947 
4948 
4949 
4968 class soap_client extends nusoap_base {
4969 
4970  var $username = '';
4971  var $password = '';
4972  var $authtype = '';
4973  var $requestHeaders = false; // SOAP headers in request (text)
4974  var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
4975  var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
4977  var $error_str = false;
4978  var $proxyhost = '';
4979  var $proxyport = '';
4980  var $proxyusername = '';
4981  var $proxypassword = '';
4982  var $xml_encoding = ''; // character set encoding of incoming (response) messages
4983  var $http_encoding = false;
4984  var $timeout = 0; // HTTP connection timeout
4985  var $response_timeout = 30; // HTTP response timeout
4986  var $endpointType = '';
4988  var $defaultRpcParams = false; // This is no longer used
4989  var $request = ''; // HTTP request
4990  var $response = ''; // HTTP response
4991  var $responseData = ''; // SOAP payload of response
4992  // toggles whether the parser decodes element content w/ utf8_decode()
4993  var $decode_utf8 = true;
4994 
5005 
5020  function soap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
5021  $this->endpoint = $endpoint;
5022  $this->proxyhost = $proxyhost;
5023  $this->proxyport = $proxyport;
5024  $this->proxyusername = $proxyusername;
5025  $this->proxypassword = $proxypassword;
5026  $this->timeout = $timeout;
5027  $this->response_timeout = $response_timeout;
5028 
5029  // make values
5030  if($wsdl){
5031  $this->endpointType = 'wsdl';
5032  if (is_object($endpoint) && is_a($endpoint, 'wsdl')) {
5033  $this->wsdl = $endpoint;
5034  $this->endpoint = $this->wsdl->wsdl;
5035  $this->wsdlFile = $this->endpoint;
5036  $this->debug('existing wsdl instance created from ' . $this->endpoint);
5037  } else {
5038  $this->wsdlFile = $this->endpoint;
5039 
5040  // instantiate wsdl object and parse wsdl file
5041  $this->debug('instantiating wsdl class with doc: '.$endpoint);
5042  $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
5043  }
5044  $this->debug("wsdl debug...\n".$this->wsdl->debug_str);
5045  $this->wsdl->debug_str = '';
5046  // catch errors
5047  if($errstr = $this->wsdl->getError()){
5048  $this->debug('got wsdl error: '.$errstr);
5049  $this->setError('wsdl error: '.$errstr);
5050  } elseif($this->operations = $this->wsdl->getOperations()){
5051  $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
5052  } else {
5053  $this->debug( 'getOperations returned false');
5054  $this->setError('no operations defined in the WSDL document!');
5055  }
5056  }
5057  }
5058 
5084  function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
5085  $this->operation = $operation;
5086  $this->fault = false;
5087  $this->error_str = '';
5088  $this->request = '';
5089  $this->response = '';
5090  $this->responseData = '';
5091  $this->faultstring = '';
5092  $this->faultcode = '';
5093  $this->opData = array();
5094 
5095  $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $style, $use; endpointType: $this->endpointType");
5096  if ($headers) {
5097  $this->requestHeaders = $headers;
5098  }
5099  // serialize parameters
5100  if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
5101  // use WSDL for operation
5102  $this->opData = $opData;
5103  foreach($opData as $key => $value){
5104  $this->debug("$key -> $value");
5105  }
5106  if (isset($opData['soapAction'])) {
5107  $soapAction = $opData['soapAction'];
5108  }
5109  $this->endpoint = $opData['endpoint'];
5110  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : ($namespace != '' ? $namespace : 'http://testuri.org');
5111  $style = $opData['style'];
5112  $use = $opData['input']['use'];
5113  // add ns to ns array
5114  if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
5115  $this->wsdl->namespaces['nu'] = $namespace;
5116  }
5117  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
5118  // serialize payload
5119  if (is_string($params)) {
5120  $this->debug("serializing param string for WSDL operation $operation");
5121  $payload = $params;
5122  } elseif (is_array($params)) {
5123  $this->debug("serializing param array for WSDL operation $operation");
5124  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
5125  } else {
5126  $this->debug('params must be array or string');
5127  $this->setError('params must be array or string');
5128  return false;
5129  }
5130  $usedNamespaces = $this->wsdl->usedNamespaces;
5131  // Partial fix for multiple encoding styles in the same function call
5132  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5133  if (isset($opData['output']['encodingStyle']) && $encodingStyle != $opData['output']['encodingStyle']) {
5134  $methodEncodingStyle = ' SOAP-ENV:encodingStyle="' . $opData['output']['encodingStyle'] . '"';
5135  } else {
5136  $methodEncodingStyle = '';
5137  }
5138  $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
5139  $this->wsdl->debug_str = '';
5140  if ($errstr = $this->wsdl->getError()) {
5141  $this->debug('got wsdl error: '.$errstr);
5142  $this->setError('wsdl error: '.$errstr);
5143  return false;
5144  }
5145  } elseif($this->endpointType == 'wsdl') {
5146  // operation not in WSDL
5147  $this->setError( 'operation '.$operation.' not present.');
5148  $this->debug("operation '$operation' not present.");
5149  $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
5150  $this->wsdl->debug_str = '';
5151  return false;
5152  } else {
5153  // no WSDL
5154  if($namespace == ''){
5155  $namespace = 'http://testuri.org';
5156  }
5157  //$this->namespaces['ns1'] = $namespace;
5158  $nsPrefix = 'ns1';
5159  // serialize
5160  $payload = '';
5161  if (is_string($params)) {
5162  $this->debug("serializing param string for operation $operation");
5163  $payload = $params;
5164  } elseif (is_array($params)) {
5165  $this->debug("serializing param array for operation $operation");
5166  foreach($params as $k => $v){
5167  $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
5168  }
5169  } else {
5170  $this->debug('params must be array or string');
5171  $this->setError('params must be array or string');
5172  return false;
5173  }
5174  $usedNamespaces = array();
5175  $methodEncodingStyle = '';
5176  }
5177  // wrap RPC calls with method element
5178  if ($style == 'rpc') {
5179  if ($use == 'literal') {
5180  $this->debug("wrapping RPC request with literal method element");
5181  $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>";
5182  } else {
5183  $this->debug("wrapping RPC request with encoded method element");
5184  $payload = "<$nsPrefix:$operation$methodEncodingStyle xmlns:$nsPrefix=\"$namespace\">" .
5185  $payload .
5186  "</$nsPrefix:$operation>";
5187  }
5188  }
5189  // serialize envelope
5190  $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use);
5191 //echo htmlentities($soapmsg)."<br><br>";
5192  $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace, style: $style, use: $use");
5193  $this->debug('SOAP message length: ' . strlen($soapmsg) . ' contents: ' . substr($soapmsg, 0, 1000));
5194  // send
5195  $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
5196  if($errstr = $this->getError()){
5197  $this->debug('Error: '.$errstr);
5198  return false;
5199  } else {
5200  $this->return = $return;
5201  $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
5202 
5203  // fault?
5204  if(is_array($return) && isset($return['faultcode'])){
5205  $this->debug('got fault');
5206  $this->setError($return['faultcode'].': '.$return['faultstring']);
5207  $this->fault = true;
5208  foreach($return as $k => $v){
5209  $this->$k = $v;
5210  $this->debug("$k = $v<br>");
5211  }
5212  return $return;
5213  } else {
5214  // array of return values
5215  if(is_array($return)){
5216  // multiple 'out' parameters
5217  if(sizeof($return) > 1){
5218  return $return;
5219  }
5220  // single 'out' parameter
5221  return array_shift($return);
5222  // nothing returned (ie, echoVoid)
5223  } else {
5224  return "";
5225  }
5226  }
5227  }
5228  }
5229 
5237  function getOperationData($operation){
5238  if(isset($this->operations[$operation])){
5239  return $this->operations[$operation];
5240  }
5241  $this->debug("No data for operation: $operation");
5242  }
5243 
5258  function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
5259  // detect transport
5260  switch(true){
5261  // http(s)
5262  case ereg('^http',$this->endpoint):
5263  $this->debug('transporting via HTTP');
5264  if($this->persistentConnection == true && is_object($this->persistentConnection)){
5265  $http =& $this->persistentConnection;
5266  } else {
5267  $http = new soap_transport_http($this->endpoint);
5268  if ($this->persistentConnection) {
5269  $http->usePersistentConnection();
5270  }
5271  }
5272  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
5273  $http->setSOAPAction($soapaction);
5274  if($this->proxyhost && $this->proxyport){
5275  $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
5276  }
5277  if($this->username != '' && $this->password != '') {
5278  $http->setCredentials($this->username, $this->password, $this->authtype);
5279  }
5280  if($this->http_encoding != ''){
5281  $http->setEncoding($this->http_encoding);
5282  }
5283  $this->debug('sending message, length: '.strlen($msg));
5284  if(ereg('^http:',$this->endpoint)){
5285  //if(strpos($this->endpoint,'http:')){
5286  $this->responseData = $http->send($msg,$timeout,$response_timeout);
5287  } elseif(ereg('^https',$this->endpoint)){
5288  //} elseif(strpos($this->endpoint,'https:')){
5289  //if(phpversion() == '4.3.0-dev'){
5290  //$response = $http->send($msg,$timeout,$response_timeout);
5291  //$this->request = $http->outgoing_payload;
5292  //$this->response = $http->incoming_payload;
5293  //} else
5294  if (extension_loaded('curl')) {
5295  $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout);
5296  } else {
5297  $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
5298  }
5299  } else {
5300  $this->setError('no http/s in endpoint url');
5301  }
5302  $this->request = $http->outgoing_payload;
5303  $this->response = $http->incoming_payload;
5304  $this->debug("transport debug data...\n".$http->debug_str);
5305 
5306  // save transport object if using persistent connections
5307  if ($this->persistentConnection) {
5308  $http->debug_str = '';
5309  if (!is_object($this->persistentConnection)) {
5310  $this->persistentConnection = $http;
5311  }
5312  }
5313 
5314  if($err = $http->getError()){
5315  $this->setError('HTTP Error: '.$err);
5316  return false;
5317  } elseif($this->getError()){
5318  return false;
5319  } else {
5320  $this->debug('got response, length: '. strlen($this->responseData).' type: '.$http->incoming_headers['content-type']);
5321  return $this->parseResponse($http->incoming_headers, $this->responseData);
5322  }
5323  break;
5324  default:
5325  $this->setError('no transport found, or selected transport is not yet supported!');
5326  return false;
5327  break;
5328  }
5329  }
5330 
5339  function parseResponse($headers, $data) {
5340  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
5341  if (!strstr($headers['content-type'], 'text/xml')) {
5342 echo "-".$data."<br /><br />".htmlentities($data)."-";
5343  $this->setError('Response not of type text/xml');
5344  return false;
5345  }
5346  if (strpos($headers['content-type'], '=')) {
5347  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
5348  $this->debug('Got response encoding: ' . $enc);
5349  if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
5350  $this->xml_encoding = strtoupper($enc);
5351  } else {
5352  $this->xml_encoding = 'US-ASCII';
5353  }
5354  } else {
5355  // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
5356  $this->xml_encoding = 'UTF-8';
5357  }
5358  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
5359  $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
5360  // add parser debug data to our debug
5361  $this->debug($parser->debug_str);
5362  // if parse errors
5363  if($errstr = $parser->getError()){
5364  $this->setError( $errstr);
5365  // destroy the parser object
5366  unset($parser);
5367  return false;
5368  } else {
5369  // get SOAP headers
5370  $this->responseHeaders = $parser->getHeaders();
5371  // get decoded message
5372  $return = $parser->get_response();
5373  // add document for doclit support
5374  $this->document = $parser->document;
5375  // destroy the parser object
5376  unset($parser);
5377  // return decode message
5378  return $return;
5379  }
5380  }
5381 
5388  function setHeaders($headers){
5389  $this->requestHeaders = $headers;
5390  }
5391 
5398  function getHeaders(){
5399  if($this->responseHeaders != '') {
5400  return $this->responseHeaders;
5401  }
5402  }
5403 
5414  $this->proxyhost = $proxyhost;
5415  $this->proxyport = $proxyport;
5416  $this->proxyusername = $proxyusername;
5417  $this->proxypassword = $proxypassword;
5418  }
5419 
5429  $this->username = $username;
5430  $this->password = $password;
5431  $this->authtype = $authtype;
5432  }
5433 
5440  function setHTTPEncoding($enc='gzip, deflate'){
5441  $this->http_encoding = $enc;
5442  }
5443 
5450  $this->persistentConnection = true;
5451  }
5452 
5463  function getDefaultRpcParams() {
5464  return $this->defaultRpcParams;
5465  }
5466 
5475  function setDefaultRpcParams($rpcParams) {
5476  $this->defaultRpcParams = $rpcParams;
5477  }
5478 
5485  function getProxy(){
5486  $evalStr = '';
5487  foreach($this->operations as $operation => $opData){
5488  if($operation != ''){
5489  // create param string
5490  $paramStr = '';
5491  if(sizeof($opData['input']['parts']) > 0){
5492  foreach($opData['input']['parts'] as $name => $type){
5493  $paramStr .= "\$$name,";
5494  }
5495  $paramStr = substr($paramStr,0,strlen($paramStr)-1);
5496  }
5497  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
5498  $evalStr .= "function $operation ($paramStr){
5499  // load params into array
5500  \$params = array($paramStr);
5501  return \$this->call('$operation',\$params,'".$opData['namespace']."','".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
5502  }";
5503  unset($paramStr);
5504  }
5505  }
5506  $r = rand();
5507  $evalStr = 'class soap_proxy_'.$r.' extends soap_client {
5508  '.$evalStr.'
5509  }';
5510  //print "proxy class:<pre>$evalStr</pre>";
5511  // eval the class
5512  eval($evalStr);
5513  // instantiate proxy object
5514  eval("\$proxy = new soap_proxy_$r('');");
5515  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
5516  $proxy->endpointType = 'wsdl';
5517  $proxy->wsdlFile = $this->wsdlFile;
5518  $proxy->wsdl = $this->wsdl;
5519  $proxy->operations = $this->operations;
5520  $proxy->defaultRpcParams = $this->defaultRpcParams;
5521  // transfer other state
5522  $proxy->username = $this->username;
5523  $proxy->password = $this->password;
5524  $proxy->proxyhost = $this->proxyhost;
5525  $proxy->proxyport = $this->proxyport;
5526  $proxy->proxyusername = $this->proxyusername;
5527  $proxy->proxypassword = $this->proxypassword;
5528  $proxy->timeout = $this->timeout;
5529  $proxy->response_timeout = $this->response_timeout;
5530  $proxy->http_encoding = $this->http_encoding;
5531  $proxy->persistentConnection = $this->persistentConnection;
5532  return $proxy;
5533  }
5534 
5542  function getHTTPBody($soapmsg) {
5543  return $soapmsg;
5544  }
5545 
5554  function getHTTPContentType() {
5555  return 'text/xml';
5556  }
5557 
5568  return $this->soap_defencoding;
5569  }
5570 
5571  /*
5572  * whether or not parser should decode utf8 element content
5573  *
5574  * @return always returns true
5575  * @access public
5576  */
5577  function decodeUTF8($bool){
5578  $this->decode_utf8 = $bool;
5579  return true;
5580  }
5581 }
5582 ?>