5 NuSOAP - Web Services Toolkit for PHP
7 Copyright (c) 2002 NuSphere Corporation
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 If you have any questions or comments, please email:
27 http://dietrich.ganx4.com/nusoap
30 http://www.nusphere.com
37 require_once('class.soapclient.php');
38 require_once('class.soap_val.php');
39 require_once('class.soap_parser.php');
40 require_once('class.soap_fault.php');
43 require_once('class.soap_transport_http.php');
45 // optional add-on classes
46 require_once('class.xmlschema.php');
47 require_once('class.wsdl.php');
50 require_once('class.soap_server.php');*/
56 * @author Dietrich Ayala <dietrich@ganx4.com>
62 var $title = 'NuSOAP';
63 var $version = '0.6.3';
64 var $error_str = false;
66 // toggles automatic encoding of special characters
67 var $charencoding = true;
72 * @var XMLSchemaVersion
75 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
78 * set default encoding
80 * @var soap_defencoding
83 //var $soap_defencoding = 'UTF-8';
84 var $soap_defencoding = 'ISO-8859-1';
87 * load namespace uris into an array of uri => prefix
92 var $namespaces = array(
93 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
94 'xsd' => 'http://www.w3.org/2001/XMLSchema',
95 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
96 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
97 'si' => 'http://soapinterop.org/xsd');
99 * load types into typemap array
100 * is this legacy yet?
101 * no, this is used by the xmlschema class to verify type => namespace mappings.
105 var $typemap = array(
106 'http://www.w3.org/2001/XMLSchema' => array(
107 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
108 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
109 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
111 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
112 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
113 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
114 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
115 'http://www.w3.org/1999/XMLSchema' => array(
116 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
117 'float'=>'double','dateTime'=>'string',
118 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
119 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
120 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
121 'http://xml.apache.org/xml-soap' => array('Map')
125 * entities to convert
130 var $xmlEntities = array('quot' => '"','amp' => '&',
131 'lt' => '<','gt' => '>','apos' => "'");
134 * adds debug data to the class level debug string
136 * @param string $string debug data
139 function debug($string){
140 $this->debug_str
.= get_class($this).": $string\n";
144 * returns error string if present
146 * @return boolean $string error string
150 if($this->error_str
!= ''){
151 return $this->error_str
;
159 * @return boolean $string error string
162 function setError($str){
163 $this->error_str
= $str;
167 * serializes PHP values in accordance w/ section 5. Type information is
168 * not serialized if $use == 'literal'.
173 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
174 if(is_object($val) && get_class($val) == 'soapval'){
175 return $val->serialize($use);
177 $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
178 // if no name, use item
179 $name = (!$name||
is_numeric($name)) ?
'soapVal' : $name;
180 // if name has ns, add ns prefix to name
183 $prefix = 'nu'.rand(1000,9999);
184 $name = $prefix.':'.$name;
185 $xmlns .= " xmlns:$prefix=\"$name_ns\"";
187 // if type is prefixed, create type prefix
188 if($type_ns != '' && $type_ns == $this->namespaces
['xsd']){
189 // need to fix this. shouldn't default to xsd if no ns specified
190 // w/o checking against typemap
191 $type_prefix = 'xsd';
193 $type_prefix = 'ns'.rand(1000,9999);
194 $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
196 // serialize attributes if present
198 foreach($attributes as $k => $v){
199 $atts .= " $k=\"$v\"";
202 // serialize if an xsd built-in primitive type
203 if($type != '' && isset($this->typemap
[$this->XMLSchemaVersion
][$type])){
204 if ($use == 'literal') {
205 return "<$name$xmlns>$val</$name>";
207 return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>";
210 // detect type and serialize
214 case ($type == '' && is_null($val)):
215 if ($use == 'literal') {
216 // TODO: depends on nillable
217 $xml .= "<$name$xmlns/>";
219 $xml .= "<$name$xmlns xsi:type=\"xsd:nil\"/>";
222 case (is_bool($val) ||
$type == 'boolean'):
226 if ($use == 'literal') {
227 $xml .= "<$name$xmlns $atts>$val</$name>";
229 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
232 case (is_int($val) ||
is_long($val) ||
$type == 'int'):
233 if ($use == 'literal') {
234 $xml .= "<$name$xmlns $atts>$val</$name>";
236 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
239 case (is_float($val)||
is_double($val) ||
$type == 'float'):
240 if ($use == 'literal') {
241 $xml .= "<$name$xmlns $atts>$val</$name>";
243 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
246 case (is_string($val) ||
$type == 'string'):
247 if($this->charencoding
){
248 $val = htmlspecialchars($val, ENT_QUOTES
);
250 if ($use == 'literal') {
251 $xml .= "<$name$xmlns $atts>$val</$name>";
253 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
256 case is_object($val):
257 $name = get_class($val);
258 foreach(get_object_vars($val) as $k => $v){
259 $pXml = isset($pXml) ?
$pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
261 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
264 case (is_array($val) ||
$type):
265 // detect if struct or array
266 $keyList = array_keys($val);
267 $valueType = 'arraySimple';
268 foreach($keyList as $keyListValue){
269 if(!is_int($keyListValue)){
270 $valueType = 'arrayStruct';
274 if($valueType=='arraySimple' ||
ereg('^ArrayOf',$type)){
276 if(is_array($val) && count($val)> 0){
278 if(is_object($v) && get_class($v) == 'soapval'){
283 $array_types[$tt] = 1;
284 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
285 if(is_array($v) && is_numeric(key($v))){
291 if(count($array_types) > 1){
292 $array_typename = 'xsd:ur-type';
293 } elseif(isset($tt) && isset($this->typemap
[$this->XMLSchemaVersion
][$tt])) {
294 $array_typename = 'xsd:'.$tt;
295 } elseif($tt == 'array' ||
$tt == 'Array'){
296 $array_typename = 'SOAP-ENC:Array';
298 $array_typename = $tt;
300 if(isset($array_types['array'])){
301 $array_type = $i.",".$i;
305 if ($use == 'literal') {
306 $xml = "<$name $atts>".$xml."</$name>";
308 $xml = "<$name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"$atts>".$xml."</$name>";
312 if ($use == 'literal') {
313 $xml = "<$name $atts>".$xml."</$name>";;
315 $xml = "<$name xsi:type=\"SOAP-ENC:Array\" $atts>".$xml."</$name>";;
320 if(isset($type) && isset($type_prefix)){
321 $type_str = " xsi:type=\"$type_prefix:$type\"";
325 if ($use == 'literal') {
326 $xml .= "<$name$xmlns $atts>";
328 $xml .= "<$name$xmlns$type_str$atts>";
330 foreach($val as $k => $v){
331 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
337 $xml .= 'not detected, got '.gettype($val).' for '.$val;
347 * @param string headers
348 * @param array namespaces
349 * @param string style
350 * @return string message
353 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc'){
354 // serialize namespaces
356 foreach(array_merge($this->namespaces
,$namespaces) as $k => $v){
357 $ns_string .= " xmlns:$k=\"$v\"";
359 if($style == 'rpc') {
360 $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
365 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
367 // serialize envelope
369 '<?xml version="1.0" encoding="'.$this->soap_defencoding
.'"?'.">".
370 '<SOAP-ENV:Envelope'.$ns_string.">".
375 "</SOAP-ENV:Envelope>";
378 function formatDump($str){
379 $str = htmlspecialchars($str);
384 * returns the local part of a prefixed string
385 * returns the original string, if not prefixed
391 function getLocalPart($str){
392 if($sstr = strrchr($str,':')){
393 // get unqualified name
394 return substr( $sstr, 1 );
401 * returns the prefix part of a prefixed string
402 * returns false, if not prefixed
408 function getPrefix($str){
409 if($pos = strrpos($str,':')){
411 return substr($str,0,$pos);
416 function varDump($data) {
419 $ret_val = ob_get_contents();
425 // XML Schema Datatype Helper Functions
427 //xsd:dateTime helpers
430 * convert unix timestamp to ISO 8601 compliant date string
432 * @param string $timestamp Unix time stamp
435 function timestamp_to_iso8601($timestamp,$utc=true){
436 $datestr = date('Y-m-d\TH:i:sO',$timestamp);
439 '([0-9]{4})-'. // centuries & years CCYY-
440 '([0-9]{2})-'. // months MM-
441 '([0-9]{2})'. // days DD
443 '([0-9]{2}):'. // hours hh:
444 '([0-9]{2}):'. // minutes mm:
445 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
446 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
448 if(ereg($eregStr,$datestr,$regs)){
449 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
458 * convert ISO 8601 compliant date string to unix timestamp
460 * @param string $datestr ISO 8601 compliant date string
463 function iso8601_to_timestamp($datestr){
465 '([0-9]{4})-'. // centuries & years CCYY-
466 '([0-9]{2})-'. // months MM-
467 '([0-9]{2})'. // days DD
469 '([0-9]{2}):'. // hours hh:
470 '([0-9]{2}):'. // minutes mm:
471 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
472 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
473 if(ereg($eregStr,$datestr,$regs)){
476 $op = substr($regs[8],0,1);
477 $h = substr($regs[8],1,2);
478 $m = substr($regs[8],strlen($regs[8])-2,2);
480 $regs[4] = $regs[4] +
$h;
481 $regs[5] = $regs[5] +
$m;
482 } elseif($op == '+'){
483 $regs[4] = $regs[4] - $h;
484 $regs[5] = $regs[5] - $m;
487 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
500 * soap_fault class, allows for creation of faults
501 * mainly used for returning faults from deployed functions
502 * in a server instance.
503 * @author Dietrich Ayala <dietrich@ganx4.com>
507 class soap_fault
extends nusoap_base
{
517 * @param string $faultcode (client | server)
518 * @param string $faultactor only used when msg routed between multiple actors
519 * @param string $faultstring human readable error message
520 * @param string $faultdetail
522 function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
523 $this->faultcode
= $faultcode;
524 $this->faultactor
= $faultactor;
525 $this->faultstring
= $faultstring;
526 $this->faultdetail
= $faultdetail;
534 function serialize(){
536 foreach($this->namespaces
as $k => $v){
537 $ns_string .= "\n xmlns:$k=\"$v\"";
540 '<?xml version="1.0"?'.">\n".
541 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
544 '<faultcode>'.$this->faultcode
.'</faultcode>'.
545 '<faultactor>'.$this->faultactor
.'</faultactor>'.
546 '<faultstring>'.$this->faultstring
.'</faultstring>'.
547 '<detail>'.$this->serialize_val($this->faultdetail
).'</detail>'.
550 '</SOAP-ENV:Envelope>';
562 * parses an XML Schema, allows access to it's data, other utility methods
563 * no validation... yet.
564 * very experimental and limited. As is discussed on XML-DEV, I'm one of the people
565 * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
566 * tutorials I refer to :)
568 * @author Dietrich Ayala <dietrich@ganx4.com>
572 class XMLSchema
extends nusoap_base
{
577 // define internal arrays of bindings, ports, operations, messages, etc.
578 var $complexTypes = array();
580 var $schemaTargetNamespace = '';
585 var $depth_array = array();
590 * @param string $schema schema document URI
591 * @param string $xml xml document URI
594 function XMLSchema($schema='',$xml=''){
596 $this->debug('xmlschema class instantiated, inside constructor');
598 $this->schema
= $schema;
603 $this->debug('initial schema file: '.$schema);
604 $this->parseFile($schema);
609 $this->debug('initial xml file: '.$xml);
610 $this->parseFile($xml);
618 * @param string $xml, path/URL to XML file
619 * @param string $type, (schema | xml)
623 function parseFile($xml,$type){
626 $this->debug('parsing $xml');
627 $xmlStr = @join
("",@file
($xml));
629 $this->setError('No file at the specified URL: '.$xml);
632 $this->parseString($xmlStr,$type);
640 * parse an XML string
642 * @param string $xml path or URL
643 * @param string $type, (schema|xml)
646 function parseString($xml,$type){
650 // Create an XML parser.
651 $this->parser
= xml_parser_create();
652 // Set the options for parsing the XML data.
653 xml_parser_set_option($this->parser
, XML_OPTION_CASE_FOLDING
, 0);
655 // Set the object for the parser.
656 xml_set_object($this->parser
, $this);
658 // Set the element handlers for the parser.
659 if($type == "schema"){
660 xml_set_element_handler($this->parser
, 'schemaStartElement','schemaEndElement');
661 xml_set_character_data_handler($this->parser
,'schemaCharacterData');
662 } elseif($type == "xml"){
663 xml_set_element_handler($this->parser
, 'xmlStartElement','xmlEndElement');
664 xml_set_character_data_handler($this->parser
,'xmlCharacterData');
667 // Parse the XML file.
668 if(!xml_parse($this->parser
,$xml,true)){
669 // Display an error message.
670 $errstr = sprintf('XML error on line %d: %s',
671 xml_get_current_line_number($this->parser
),
672 xml_error_string(xml_get_error_code($this->parser
))
674 $this->debug('XML parse error: '.$errstr);
675 $this->setError('Parser error: '.$errstr);
678 xml_parser_free($this->parser
);
680 $this->debug('no xml passed to parseString()!!');
681 $this->setError('no xml passed to parseString()!!');
686 * start-element handler
688 * @param string $parser XML parser object
689 * @param string $name element name
690 * @param string $attrs associative array of attributes
693 function schemaStartElement($parser, $name, $attrs) {
695 // position in the total number of elements, starting from 0
696 $pos = $this->position++
;
697 $depth = $this->depth++
;
698 // set self as current value for this depth
699 $this->depth_array
[$depth] = $pos;
701 // get element prefix
702 if($prefix = $this->getPrefix($name)){
703 // get unqualified name
704 $name = $this->getLocalPart($name);
709 // loop thru attributes, expanding, and registering namespace declarations
710 if(count($attrs) > 0){
711 foreach($attrs as $k => $v){
712 // if ns declarations, add to class level array of valid namespaces
713 if(ereg("^xmlns",$k)){
714 //$this->xdebug("$k: $v");
715 //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
716 if($ns_prefix = substr(strrchr($k,':'),1)){
717 $this->namespaces
[$ns_prefix] = $v;
719 $this->namespaces
['ns'.(count($this->namespaces
)+
1)] = $v;
721 if($v == 'http://www.w3.org/2001/XMLSchema' ||
$v == 'http://www.w3.org/1999/XMLSchema'){
722 $this->XMLSchemaVersion
= $v;
723 $this->namespaces
['xsi'] = $v.'-instance';
727 foreach($attrs as $k => $v){
728 // expand each attribute
729 $k = strpos($k,':') ?
$this->expandQname($k) : $k;
730 $v = strpos($v,':') ?
$this->expandQname($v) : $v;
737 // find status, register data
739 case ('all'|
'choice'|
'sequence'):
740 //$this->complexTypes[$this->currentComplexType]['compositor'] = 'all';
741 $this->complexTypes
[$this->currentComplexType
]['compositor'] = $name;
743 $this->complexTypes
[$this->currentComplexType
]['phpType'] = 'struct';
747 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
748 if(isset($attrs['name'])){
749 $this->attributes
[$attrs['name']] = $attrs;
750 $aname = $attrs['name'];
751 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
752 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
753 } elseif(isset($attrs['ref'])){
754 $aname = $attrs['ref'];
755 $this->attributes
[$attrs['ref']] = $attrs;
758 if(isset($this->currentComplexType
)){
759 $this->complexTypes
[$this->currentComplexType
]['attrs'][$aname] = $attrs;
760 } elseif(isset($this->currentElement
)){
761 $this->elements
[$this->currentElement
]['attrs'][$aname] = $attrs;
763 // arrayType attribute
764 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) ||
$this->getLocalPart($aname) == 'arrayType'){
765 $this->complexTypes
[$this->currentComplexType
]['phpType'] = 'array';
766 $prefix = $this->getPrefix($aname);
767 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
768 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
772 if(strpos($v,'[,]')){
773 $this->complexTypes
[$this->currentComplexType
]['multidimensional'] = true;
775 $v = substr($v,0,strpos($v,'[')); // clip the []
776 if(!strpos($v,':') && isset($this->typemap
[$this->XMLSchemaVersion
][$v])){
777 $v = $this->XMLSchemaVersion
.':'.$v;
779 $this->complexTypes
[$this->currentComplexType
]['arrayType'] = $v;
783 if(isset($attrs['name'])){
784 $this->currentElement
= false;
785 $this->currentComplexType
= $attrs['name'];
786 $this->complexTypes
[$this->currentComplexType
] = $attrs;
787 $this->complexTypes
[$this->currentComplexType
]['typeClass'] = 'complexType';
788 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
789 $this->complexTypes
[$this->currentComplexType
]['phpType'] = 'array';
791 $this->complexTypes
[$this->currentComplexType
]['phpType'] = 'struct';
793 $this->xdebug('processing complexType '.$attrs['name']);
797 if(isset($attrs['type'])){
798 $this->xdebug("processing element ".$attrs['name']);
799 $this->currentElement
= $attrs['name'];
800 $this->elements
[ $attrs['name'] ] = $attrs;
801 $this->elements
[ $attrs['name'] ]['typeClass'] = 'element';
802 $ename = $attrs['name'];
803 } elseif(isset($attrs['ref'])){
804 $ename = $attrs['ref'];
806 $this->xdebug('adding complexType '.$attrs['name']);
807 $this->currentComplexType
= $attrs['name'];
808 $this->complexTypes
[ $attrs['name'] ] = $attrs;
809 $this->complexTypes
[ $attrs['name'] ]['element'] = 1;
810 $this->complexTypes
[$this->currentComplexType
]['phpType'] = 'struct';
812 if(isset($ename) && $this->currentComplexType
){
813 $this->complexTypes
[$this->currentComplexType
]['elements'][$ename] = $attrs;
817 $this->xdebug("in restriction for ct: $this->currentComplexType and ce: $this->currentElement");
818 if($this->currentElement
){
819 $this->elements
[$this->currentElement
]['type'] = $attrs['base'];
820 } elseif($this->currentComplexType
){
821 $this->complexTypes
[$this->currentComplexType
]['restrictionBase'] = $attrs['base'];
822 if(strstr($attrs['base'],':') == ':Array'){
823 $this->complexTypes
[$this->currentComplexType
]['phpType'] = 'array';
828 $this->schema
= $attrs;
829 $this->schema
['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
832 $this->currentElement
= $attrs['name'];
833 $this->elements
[ $attrs['name'] ] = $attrs;
834 $this->elements
[ $attrs['name'] ]['typeClass'] = 'element';
840 * end-element handler
842 * @param string $parser XML parser object
843 * @param string $name element name
846 function schemaEndElement($parser, $name) {
847 // position of current element is equal to the last value left in depth_array for my depth
848 if(isset($this->depth_array
[$this->depth
])){
849 $pos = $this->depth_array
[$this->depth
];
851 // bring depth down a notch
854 if($name == 'complexType'){
855 $this->currentComplexType
= false;
856 $this->currentElement
= false;
858 if($name == 'element'){
859 $this->currentElement
= false;
864 * element content handler
866 * @param string $parser XML parser object
867 * @param string $data element content
870 function schemaCharacterData($parser, $data){
871 $pos = $this->depth_array
[$this->depth
];
872 $this->message
[$pos]['cdata'] .= $data;
876 * serialize the schema
880 function serializeSchema(){
882 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion
);
885 foreach($this->complexTypes
as $typeName => $attrs){
887 // serialize child elements
888 if(count($attrs['elements']) > 0){
889 foreach($attrs['elements'] as $element => $eParts){
890 if(isset($eParts['ref'])){
891 $contentStr .= "<element ref=\"$element\"/>";
893 $contentStr .= "<element name=\"$element\" type=\"$eParts[type]\"/>";
898 if(count($attrs['attrs']) >= 1){
899 foreach($attrs['attrs'] as $attr => $aParts){
900 $contentStr .= '<attribute ref="'.$aParts['ref'].'"';
901 if(isset($aParts['wsdl:arrayType'])){
902 $contentStr .= ' wsdl:arrayType="'.$aParts['wsdl:arrayType'].'"';
908 if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
909 $contentStr = "<$schemaPrefix:restriction base=\"".$attrs['restrictionBase']."\">".$contentStr."</$schemaPrefix:restriction>";
911 // "all" compositor obviates complex/simple content
912 if(isset($attrs['compositor']) && $attrs['compositor'] == 'all'){
913 $contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>";
915 // complex or simple content
916 elseif( count($attrs['elements']) > 0 ||
count($attrs['attrs']) > 0){
917 $contentStr = "<$schemaPrefix:complexContent>".$contentStr."</$schemaPrefix:complexContent>";
920 if(isset($attrs['compositor']) && $attrs['compositor'] != '' && $attrs['compositor'] != 'all'){
921 $contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>";
923 // finalize complex type
924 if($contentStr != ''){
925 $contentStr = "<$schemaPrefix:complexType name=\"$typeName\">".$contentStr."</$schemaPrefix:complexType>";
927 $contentStr = "<$schemaPrefix:complexType name=\"$typeName\"/>";
932 if(isset($this->elements
) && count($this->elements
) > 0){
933 foreach($this->elements
as $element => $eParts){
934 $xml .= "<$schemaPrefix:element name=\"$element\" type=\"".$eParts['type']."\"/>";
938 if(isset($this->attributes
) && count($this->attributes
) > 0){
939 foreach($this->attributes
as $attr => $aParts){
940 $xml .= "<$schemaPrefix:attribute name=\"$attr\" type=\"".$aParts['type']."\"/>";
944 $xml = "<$schemaPrefix:schema xmlns=\"$this->XMLSchemaVersion\" targetNamespace=\"$this->schemaTargetNamespace\">".$xml."</$schemaPrefix:schema>";
949 * expands a qualified name
951 * @param string $string qname
952 * @return string expanded qname
955 function expandQname($qname){
956 // get element prefix
957 if(strpos($qname,':') && !ereg('^http://',$qname)){
958 // get unqualified name
959 $name = substr(strstr($qname,':'),1);
961 $prefix = substr($qname,0,strpos($qname,':'));
962 if(isset($this->namespaces
[$prefix])){
963 return $this->namespaces
[$prefix].':'.$name;
973 * adds debug data to the clas level debug string
975 * @param string $string debug data
978 function xdebug($string){
979 $this->debug(' xmlschema: '.$string);
983 * get the PHP type of a user defined type in the schema
984 * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
985 * returns false if no type exists, or not w/ the given namespace
986 * else returns a string that is either a native php type, or 'struct'
988 * @param string $type, name of defined type
989 * @param string $ns, namespace of type
993 function getPHPType($type,$ns){
995 if(isset($typemap[$ns][$type])){
996 //print "found type '$type' and ns $ns in typemap<br>";
997 return $typemap[$ns][$type];
998 } elseif(isset($this->complexTypes
[$type])){
999 //print "getting type '$type' and ns $ns from complexTypes array<br>";
1000 return $this->complexTypes
[$type]['phpType'];
1006 * returns the local part of a prefixed string
1007 * returns the original string, if not prefixed
1013 function getLocalPart($str){
1014 if($sstr = strrchr($str,':')){
1015 // get unqualified name
1016 return substr( $sstr, 1 );
1023 * returns the prefix part of a prefixed string
1024 * returns false, if not prefixed
1030 function getPrefix($str){
1031 if($pos = strrpos($str,':')){
1033 return substr($str,0,$pos);
1039 * pass it a prefix, it returns a namespace
1040 * returns false if no namespace registered with the given prefix
1046 function getNamespaceFromPrefix($prefix){
1047 if(isset($this->namespaces
[$prefix])){
1048 return $this->namespaces
[$prefix];
1050 //$this->setError("No namespace registered for prefix '$prefix'");
1055 * returns the prefix for a given namespace (or prefix)
1056 * or false if no prefixes registered for the given namespace
1062 function getPrefixFromNamespace($ns){
1063 foreach($this->namespaces
as $p => $n){
1064 if($ns == $n ||
$ns == $p){
1065 $this->usedNamespaces
[$p] = $n;
1073 * returns an array of information about a given type
1074 * returns false if no type exists by the given name
1077 * 'elements' => array(), // refs to elements array
1078 * 'restrictionBase' => '',
1080 * 'order' => '(sequence|all)',
1081 * 'attrs' => array() // refs to attributes array
1088 function getTypeDef($type){
1089 if(isset($this->complexTypes
[$type])){
1090 return $this->complexTypes
[$type];
1091 } elseif(isset($this->elements
[$type])){
1092 return $this->elements
[$type];
1093 } elseif(isset($this->attributes
[$type])){
1094 return $this->attributes
[$type];
1100 * returns a sample serialization of a given type, or false if no type by the given name
1102 * @param string $type, name of type
1106 function serializeTypeDef($type){
1107 //print "in sTD() for type $type<br>";
1108 if($typeDef = $this->getTypeDef($type)){
1110 if(is_array($typeDef['attrs'])){
1111 foreach($attrs as $attName => $data){
1112 $str .= " $attName=\"{type = ".$data['type']."}\"";
1115 $str .= " xmlns=\"".$this->schema
['targetNamespace']."\"";
1116 if(count($typeDef['elements']) > 0){
1118 foreach($typeDef['elements'] as $element => $eData){
1119 $str .= $this->serializeTypeDef($element);
1122 } elseif($typeDef['typeClass'] == 'element') {
1123 $str .= "></$type>";
1133 * returns HTML form elements that allow a user
1134 * to enter values for creating an instance of the given type.
1136 * @param string $name, name for type instance
1137 * @param string $type, name of type
1141 function typeToForm($name,$type){
1143 if($typeDef = $this->getTypeDef($type)){
1145 if($typeDef['phpType'] == 'struct'){
1146 $buffer .= '<table>';
1147 foreach($typeDef['elements'] as $child => $childDef){
1149 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1150 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1152 $buffer .= '</table>';
1154 } elseif($typeDef['phpType'] == 'array'){
1155 $buffer .= '<table>';
1156 for($i=0;$i < 3; $i++
){
1158 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1159 <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1161 $buffer .= '</table>';
1164 $buffer .= "<input type='text' name='parameters[$name]'>";
1167 $buffer .= "<input type='text' name='parameters[$name]'>";
1173 * adds an XML Schema complex type to the WSDL types
1183 * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
1187 * example: PHP associative array ( SOAP Struct )
1194 * array('myVar'=> array('name'=>'myVar','type'=>'string')
1198 * @param typeClass (complexType|simpleType|attribute)
1199 * @param phpType: currently supported are array and struct (php assoc array)
1200 * @param compositor (all|sequence|choice)
1201 * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1202 * @param elements = array ( name = array(name=>'',type=>'') )
1203 * @param attrs = array(
1205 * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
1206 * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
1209 * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
1212 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1213 $this->complexTypes
[$name] = array(
1215 'typeClass' => $typeClass,
1216 'phpType' => $phpType,
1217 'compositor'=> $compositor,
1218 'restrictionBase' => $restrictionBase,
1219 'elements' => $elements,
1221 'arrayType' => $arrayType
1233 * for creating serializable abstractions of native PHP types
1234 * NOTE: this is only really used when WSDL is not available.
1236 * @author Dietrich Ayala <dietrich@ganx4.com>
1240 class soapval
extends nusoap_base
{
1244 * @param string $name optional name
1245 * @param string $type optional type name
1246 * @param mixed $value optional value
1247 * @param string $namespace optional namespace of value
1248 * @param string $type_namespace optional namespace of type
1249 * @param array $attributes associative array of attributes to add to element serialization
1252 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
1253 $this->name
= $name;
1254 $this->value
= $value;
1255 $this->type
= $type;
1256 $this->element_ns
= $element_ns;
1257 $this->type_ns
= $type_ns;
1258 $this->attributes
= $attributes;
1262 * return serialized value
1264 * @return string XML data
1267 function serialize($use='encoded') {
1268 return $this->serialize_val($this->value
,$this->name
,$this->type
,$this->element_ns
,$this->type_ns
,$this->attributes
,$use);
1272 * decodes a soapval object into a PHP native type
1274 * @param object $soapval optional SOAPx4 soapval object, else uses self
1279 return $this->value
;
1290 * transport class for sending/receiving data via HTTP and HTTPS
1291 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
1293 * @author Dietrich Ayala <dietrich@ganx4.com>
1297 class soap_transport_http
extends nusoap_base
{
1302 var $proxyhost = '';
1303 var $proxyport = '';
1305 var $request_method = 'POST';
1306 var $protocol_version = '1.0';
1308 var $outgoing_headers = array();
1309 var $incoming_headers = array();
1310 var $outgoing_payload = '';
1311 var $incoming_payload = '';
1312 var $useSOAPAction = true;
1317 function soap_transport_http($url){
1319 $u = parse_url($url);
1320 foreach($u as $k => $v){
1321 $this->debug("$k = $v");
1324 if(isset($u['query']) && $u['query'] != ''){
1325 $this->path
.= '?' . $u['query'];
1327 if(!isset($u['port']) && $u['scheme'] == 'http'){
1332 function connect($timeout){
1335 if($this->proxyhost
!= '' && $this->proxyport
!= ''){
1336 $host = $this->proxyhost
;
1337 $port = $this->proxyport
;
1338 $this->debug("using http proxy: $host, $port");
1340 $host = $this->host
;
1341 $port = $this->port
;
1344 if($this->scheme
== 'https'){
1345 $host = 'ssl://'.$host;
1349 $this->debug("connection params: $host, $port");
1352 $fp = fsockopen($host, $port, $this->errno
, $this->error_str
, $timeout);
1354 $fp = fsockopen($host, $port, $this->errno
, $this->error_str
);
1359 $this->debug('Couldn\'t open socket connection to server '.$this->url
.', Error: '.$this->error_str
);
1360 $this->setError('Couldn\'t open socket connection to server: '.$this->url
.', Error: '.$this->error_str
);
1367 * send the SOAP message via HTTP
1369 * @param string $data message data
1370 * @param integer $timeout set timeout in seconds
1371 * @return string data
1374 function send($data, $timeout=0) {
1375 $this->debug('entered send() with data of length: '.strlen($data));
1377 if(!$fp = $this->connect($timeout)){
1380 $this->debug('socket connected');
1382 // start building outgoing payload:
1383 // swap url for path if going through a proxy
1384 if($this->proxyhost
!= '' && $this->proxyport
!= ''){
1385 $this->outgoing_payload
= "$this->request_method $this->url ".strtoupper($this->scheme
)."/$this->protocol_version\r\n";
1387 $this->outgoing_payload
= "$this->request_method $this->path ".strtoupper($this->scheme
)."/$this->protocol_version\r\n";
1390 $this->outgoing_payload
.=
1391 "User-Agent: $this->title/$this->version\r\n".
1392 "Host: ".$this->host
."\r\n";
1395 if($this->username
!= '') {
1396 $this->debug('setting http auth credentials');
1397 $this->outgoing_payload
.= 'Authorization: Basic '.base64_encode("$this->username:$this->password")."\r\n";
1400 $this->outgoing_payload
.= 'Content-Type: text/xml; charset='.$this->soap_defencoding
."\r\nContent-Length: ".strlen($data)."\r\n";
1402 if($this->encoding
!= '' && function_exists('gzdeflate')){
1403 $this->outgoing_payload
.= "Accept-Encoding: $this->encoding\r\n".
1404 "Connection: close\r\n";
1405 set_magic_quotes_runtime(0);
1408 if($this->useSOAPAction
){
1409 $this->outgoing_payload
.= "SOAPAction: \"$this->soapaction\""."\r\n";
1411 $this->outgoing_payload
.= "\r\n";
1413 $this->outgoing_payload
.= $data;
1416 if(!fputs($fp, $this->outgoing_payload
, strlen($this->outgoing_payload
))) {
1417 $this->setError('couldn\'t write message data to socket');
1418 $this->debug('Write error');
1420 $this->debug('wrote data to socket');
1423 $this->incoming_payload
= '';
1425 while( $data = fread($fp, 32768) ){
1426 $this->incoming_payload
.= $data;
1427 //$strlen += strlen($data);
1429 $this->debug('received '.strlen($this->incoming_payload
).' bytes of data from server');
1431 // close filepointer
1433 $this->debug('closed socket');
1435 // connection was closed unexpectedly
1436 if($this->incoming_payload
== ''){
1437 $this->setError('no response from server');
1441 $this->debug('received incoming payload: '.strlen($this->incoming_payload
));
1442 $data = $this->incoming_payload
."\r\n\r\n\r\n\r\n";
1444 // remove 100 header
1445 if(ereg('^HTTP/1.1 100',$data)){
1446 if($pos = strpos($data,"\r\n\r\n") ){
1447 $data = ltrim(substr($data,$pos));
1448 } elseif($pos = strpos($data,"\n\n") ){
1449 $data = ltrim(substr($data,$pos));
1453 // separate content from HTTP headers
1454 if( $pos = strpos($data,"\r\n\r\n") ){
1456 } elseif( $pos = strpos($data,"\n\n") ){
1459 $this->setError('no proper separation of headers and document');
1462 $header_data = trim(substr($data,0,$pos));
1463 $header_array = explode($lb,$header_data);
1464 $data = ltrim(substr($data,$pos));
1465 $this->debug('found proper separation of headers and document');
1466 $this->debug('cleaned data, stringlen: '.strlen($data));
1468 foreach($header_array as $header_line){
1469 $arr = explode(':',$header_line);
1470 if(count($arr) >= 2){
1471 $headers[trim($arr[0])] = trim($arr[1]);
1474 //print "headers: <pre>$header_data</pre><br>";
1475 //print "data: <pre>$data</pre><br>";
1477 // decode transfer-encoding
1478 if(isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] == 'chunked'){
1479 //$timer->setMarker('starting to decode chunked content');
1480 if(!$data = $this->decodeChunked($data)){
1481 $this->setError('Decoding of chunked data failed');
1484 //$timer->setMarker('finished decoding of chunked content');
1485 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
1488 // decode content-encoding
1489 if(isset($headers['Content-Encoding']) && $headers['Content-Encoding'] != ''){
1490 if($headers['Content-Encoding'] == 'deflate' ||
$headers['Content-Encoding'] == 'gzip'){
1491 // if decoding works, use it. else assume data wasn't gzencoded
1492 if(function_exists('gzinflate')){
1493 //$timer->setMarker('starting decoding of gzip/deflated content');
1494 if($headers['Content-Encoding'] == 'deflate' && $degzdata = @gzinflate
($data)){
1496 } elseif($headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){
1499 $this->setError('Errors occurred when trying to decode the data');
1501 //$timer->setMarker('finished decoding of gzip/deflated content');
1502 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
1504 $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
1509 if(strlen($data) == 0){
1510 $this->debug('no data after headers!');
1511 $this->setError('no data present after HTTP headers');
1514 $this->debug('end of send()');
1520 * send the SOAP message via HTTPS 1.0 using CURL
1522 * @param string $msg message data
1523 * @param integer $timeout set timeout in seconds
1524 * @return string data
1527 function sendHTTPS($data, $timeout=0) {
1529 //$t->setMarker('inside sendHTTPS()');
1530 $this->debug('entered sendHTTPS() with data of length: '.strlen($data));
1533 //$t->setMarker('got curl handle');
1535 if($this->proxyhost
&& $this->proxyport
){
1536 $host = $this->proxyhost
;
1537 $port = $this->proxyport
;
1539 $host = $this->host
;
1540 $port = $this->port
;
1543 $hostURL = ($port != '') ?
"https://$host:$port" : "https://$host";
1545 $hostURL .= $this->path
;
1546 curl_setopt($ch, CURLOPT_URL
, $hostURL);
1547 // set other options
1548 curl_setopt($ch, CURLOPT_HEADER
, 1);
1549 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, 1);
1551 if(function_exists('gzinflate')){
1552 curl_setopt($ch, CURLOPT_ENCODING
, 'deflate');
1554 // persistent connection
1555 //curl_setopt($ch, CURL_HTTP_VERSION_1_1, true);
1559 curl_setopt($ch, CURLOPT_TIMEOUT
, $timeout);
1563 if($this->username
!= '') {
1564 $credentials = 'Authorization: Basic '.base64_encode("$this->username:$this->password").'\r\n';
1567 if($this->encoding
!= ''){
1568 if(function_exists('gzdeflate')){
1569 $encoding_headers = "Accept-Encoding: $this->encoding\r\n".
1570 "Connection: close\r\n";
1571 set_magic_quotes_runtime(0);
1575 if($this->proxyhost
&& $this->proxyport
){
1576 $this->outgoing_payload
= "POST $this->url HTTP/$this->protocol_version\r\n";
1578 $this->outgoing_payload
= "POST $this->path HTTP/$this->protocol_version\r\n";
1581 $this->outgoing_payload
.=
1582 "User-Agent: $this->title v$this->version\r\n".
1583 "Host: ".$this->host
."\r\n".
1586 "Content-Type: text/xml; charset=\"$this->soap_defencoding\"\r\n".
1587 "Content-Length: ".strlen($data)."\r\n".
1588 "SOAPAction: \"$this->soapaction\""."\r\n\r\n".
1592 curl_setopt($ch, CURLOPT_CUSTOMREQUEST
, $this->outgoing_payload
);
1593 //$t->setMarker('set curl options, executing...');
1595 $this->incoming_payload
= curl_exec($ch);
1596 //$t->setMarker('executed transfer');
1597 $data = $this->incoming_payload
;
1599 $cErr = curl_error($ch);
1602 $err = 'cURL ERROR: '.curl_errno($ch).': '.$cErr.'<br>';
1603 foreach(curl_getinfo($ch) as $k => $v){
1604 $err .= "$k: $v<br>";
1606 $this->setError($err);
1611 //var_dump(curl_getinfo($ch));
1616 //$t->setMarker('closed curl');
1618 // remove 100 header
1619 if(ereg('^HTTP/1.1 100',$data)){
1620 if($pos = strpos($data,"\r\n\r\n") ){
1621 $data = ltrim(substr($data,$pos));
1622 } elseif($pos = strpos($data,"\n\n") ){
1623 $data = ltrim(substr($data,$pos));
1627 // separate content from HTTP headers
1628 if( $pos = strpos($data,"\r\n\r\n") ){
1630 } elseif( $pos = strpos($data,"\n\n") ){
1633 $this->setError('no proper separation of headers and document');
1636 $header_data = trim(substr($data,0,$pos));
1637 $header_array = explode($lb,$header_data);
1638 $data = ltrim(substr($data,$pos));
1639 $this->debug('found proper separation of headers and document');
1640 $this->debug('cleaned data, stringlen: '.strlen($data));
1642 foreach($header_array as $header_line){
1643 $arr = explode(':',$header_line);
1644 $headers[trim($arr[0])] = trim($arr[1]);
1646 if(strlen($data) == 0){
1647 $this->debug('no data after headers!');
1648 $this->setError('no data present after HTTP headers.');
1652 // decode transfer-encoding
1653 if($headers['Transfer-Encoding'] == 'chunked'){
1654 if(!$data = $this->decodeChunked($data)){
1655 $this->setError('Decoding of chunked data failed');
1659 // decode content-encoding
1660 if($headers['Content-Encoding'] != ''){
1661 if($headers['Content-Encoding'] == 'deflate' ||
$headers['Content-Encoding'] == 'gzip'){
1662 // if decoding works, use it. else assume data wasn't gzencoded
1663 if(function_exists('gzinflate')){
1664 if($headers['Content-Encoding'] == 'deflate' && $degzdata = @gzinflate
($data)){
1666 } elseif($headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){
1669 $this->setError('Errors occurred when trying to decode the data');
1672 $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
1676 // set decoded payload
1677 $this->incoming_payload
= $header_data."\r\n\r\n".$data;
1682 * if authenticating, set user credentials here
1684 * @param string $user
1685 * @param string $pass
1688 function setCredentials($username, $password) {
1689 $this->username
= $username;
1690 $this->password
= $password;
1694 * set the soapaction value
1696 * @param string $soapaction
1699 function setSOAPAction($soapaction) {
1700 $this->soapaction
= $soapaction;
1706 * @param string $enc encoding style. supported values: gzip, deflate, or both
1709 function setEncoding($enc='gzip, deflate'){
1710 $this->encoding
= $enc;
1711 $this->protocol_version
= '1.1';
1715 * set proxy info here
1717 * @param string $proxyhost
1718 * @param string $proxyport
1721 function setProxy($proxyhost, $proxyport) {
1722 $this->proxyhost
= $proxyhost;
1723 $this->proxyport
= $proxyport;
1727 * decode a string that is encoded w/ "chunked' transfer encoding
1728 * as defined in RFC2068 19.4.6
1730 * @param string $buffer
1734 function decodeChunked($buffer){
1739 // read chunk-size, chunk-extension (if any) and CRLF
1740 // get the position of the linebreak
1741 $chunkend = strpos($buffer,"\r\n") +
2;
1742 $temp = substr($buffer,0,$chunkend);
1743 $chunk_size = hexdec( trim($temp) );
1744 $chunkstart = $chunkend;
1745 // while (chunk-size > 0) {
1746 while ($chunk_size > 0) {
1748 $chunkend = strpos( $buffer, "\r\n", $chunkstart +
$chunk_size);
1750 // Just in case we got a broken connection
1751 if ($chunkend == FALSE) {
1752 $chunk = substr($buffer,$chunkstart);
1753 // append chunk-data to entity-body
1755 $length +
= strlen($chunk);
1759 // read chunk-data and CRLF
1760 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
1761 // append chunk-data to entity-body
1763 // length := length + chunk-size
1764 $length +
= strlen($chunk);
1765 // read chunk-size and CRLF
1766 $chunkstart = $chunkend +
2;
1768 $chunkend = strpos($buffer,"\r\n",$chunkstart)+
2;
1769 if ($chunkend == FALSE) {
1770 break; //Just in case we got a broken connection
1772 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
1773 $chunk_size = hexdec( trim($temp) );
1774 $chunkstart = $chunkend;
1777 //$this->Header['content-length'] = $length;
1778 //unset($this->Header['transfer-encoding']);
1792 * soap_server allows the user to create a SOAP server
1793 * that is capable of receiving messages and returning responses
1795 * NOTE: WSDL functionality is experimental
1797 * @author Dietrich Ayala <dietrich@ganx4.com>
1801 class soap_server
extends nusoap_base
{
1803 var $service = ''; // service name
1804 var $operations = array(); // assoc array of operations => opData
1805 var $responseHeaders = false;
1808 var $charset_encoding = 'UTF-8';
1810 var $result = 'successful';
1812 var $externalWSDLURL = false;
1813 var $debug_flag = true;
1817 * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
1819 * @param string $wsdl path or URL to a WSDL file
1822 function soap_server($wsdl=false){
1824 // turn on debugging?
1827 $this->debug_flag
= 1;
1832 $this->wsdl
= new wsdl($wsdl);
1833 $this->externalWSDLURL
= $wsdl;
1834 if($err = $this->wsdl
->getError()){
1835 die('WSDL ERROR: '.$err);
1841 * processes request and returns response
1843 * @param string $data usually is the value of $HTTP_RAW_POST_DATA
1846 function service($data){
1848 global $QUERY_STRING;
1849 if(isset($_SERVER['QUERY_STRING'])){
1850 $qs = $_SERVER['QUERY_STRING'];
1851 } elseif(isset($GLOBALS['QUERY_STRING'])){
1852 $qs = $GLOBALS['QUERY_STRING'];
1853 } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
1854 $qs = $QUERY_STRING;
1857 if(isset($qs) && ereg('wsdl', $qs) ){
1858 if($this->externalWSDLURL
){
1859 header('Location: '.$this->externalWSDLURL
);
1862 header("Content-Type: text/xml\r\n");
1863 print $this->wsdl
->serialize();
1868 // print web interface
1869 if($data == '' && $this->wsdl
){
1870 print $this->webDescription();
1873 // $response is the serialized response message
1874 $response = $this->parse_request($data);
1875 $this->debug('server sending...');
1876 $payload = $response;
1877 // add debug data if in debug mode
1878 if(isset($this->debug_flag
) && $this->debug_flag
== 1){
1879 $payload .= "<!--\n".str_replace('--','- -',$this->debug_str
)."\n-->";
1883 $header[] = "HTTP/1.0 500 Internal Server Error\r\n";
1884 $header[] = "Status: 500 Internal Server Error\r\n";
1886 $header[] = "Status: 200 OK\r\n";
1888 $header[] = "Server: $this->title Server v$this->version\r\n";
1889 $header[] = "Connection: Close\r\n";
1890 $header[] = "Content-Type: text/xml; charset=$this->charset_encoding\r\n";
1891 $header[] = "Content-Length: ".strlen($payload)."\r\n\r\n";
1893 foreach($header as $hdr){
1896 $this->response
= join("\r\n",$header).$payload;
1902 * parses request and posts response
1904 * @param string $data XML string
1905 * @return string XML response msg
1908 function parse_request($data='') {
1909 $this->debug('entering parseRequest() on '.date('H:i Y-m-d'));
1912 if(function_exists('getallheaders')){
1913 $this->headers
= getallheaders();
1914 foreach($this->headers
as $k=>$v){
1915 $dump .= "$k: $v\r\n";
1916 $this->debug("$k: $v");
1918 // get SOAPAction header
1919 if(isset($this->headers
['SOAPAction'])){
1920 $this->SOAPAction
= str_replace('"','',$this->headers
['SOAPAction']);
1922 // get the character encoding of the incoming request
1923 if(strpos($this->headers
['Content-Type'],'=')){
1924 $enc = str_replace('"','',substr(strstr($this->headers
["Content-Type"],'='),1));
1925 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
1926 $this->xml_encoding
= $enc;
1928 $this->xml_encoding
= 'us-ascii';
1931 $this->debug('got encoding: '.$this->charset_encoding
);
1932 } elseif(is_array($_SERVER)){
1933 $this->headers
['User-Agent'] = $_SERVER['HTTP_USER_AGENT'];
1934 $this->SOAPAction
= isset($_SERVER['SOAPAction']) ?
$_SERVER['SOAPAction'] : '';
1936 $this->request
= $dump."\r\n\r\n".$data;
1937 // parse response, get soap parser obj
1938 $parser = new soap_parser($data,$this->charset_encoding
);
1939 // if fault occurred during message parsing
1940 if($err = $parser->getError()){
1942 $this->debug("parser debug: \n".$parser->debug_str
);
1943 $this->result
= 'fault: error in msg parsing: '.$err;
1944 $this->fault('Server',"error in msg parsing:\n".$err);
1946 return $this->fault
->serialize();
1947 // else successfully parsed request into soapval object
1949 // get/set methodname
1950 $this->methodname
= $parser->root_struct_name
;
1951 $this->debug('method name: '.$this->methodname
);
1952 // does method exist?
1953 if(!function_exists($this->methodname
)){
1954 // "method not found" fault here
1955 $this->debug("method '$this->methodname' not found!");
1956 $this->debug("parser debug: \n".$parser->debug_str
);
1957 $this->result
= 'fault: method not found';
1958 $this->fault('Server',"method '$this->methodname' not defined in service '$this->service'");
1959 return $this->fault
->serialize();
1962 if(!$this->opData
= $this->wsdl
->getOperationData($this->methodname
)){
1964 $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service");
1965 return $this->fault
->serialize();
1968 $this->debug("method '$this->methodname' exists");
1969 // evaluate message, getting back parameters
1970 $this->debug('calling parser->get_response()');
1971 $request_data = $parser->get_response();
1973 $this->debug("parser debug: \n".$parser->debug_str
);
1974 // verify that request parameters match the method's signature
1975 if($this->verify_method($this->methodname
,$request_data)){
1976 // if there are parameters to pass
1977 $this->debug('params var dump '.$this->varDump($request_data));
1979 $this->debug("calling '$this->methodname' with params");
1980 if (! function_exists('call_user_func_array')) {
1981 $this->debug('calling method using eval()');
1982 $funcCall = $this->methodname
.'(';
1983 foreach($request_data as $param) {
1984 $funcCall .= "\"$param\",";
1986 $funcCall = substr($funcCall, 0, -1).')';
1987 $this->debug('function call:<br>'.$funcCall);
1988 @eval
("\$method_response = $funcCall;");
1990 $this->debug('calling method using call_user_func_array()');
1991 $method_response = call_user_func_array("$this->methodname",$request_data);
1993 $this->debug('response var dump'.$this->varDump($method_response));
1995 // call method w/ no parameters
1996 $this->debug("calling $this->methodname w/ no params");
1997 $m = $this->methodname
;
1998 $method_response = @$m();
2000 $this->debug("done calling method: $this->methodname, received $method_response of type".gettype($method_response));
2001 // if we got nothing back. this might be ok (echoVoid)
2002 if(isset($method_response) && $method_response != '' ||
is_bool($method_response)) {
2004 if(get_class($method_response) == 'soap_fault'){
2005 $this->debug('got a fault object from method');
2006 $this->fault
= $method_response;
2007 return $method_response->serialize();
2008 // if return val is soapval object
2009 } elseif(get_class($method_response) == 'soapval'){
2010 $this->debug('got a soapval object from method');
2011 $return_val = $method_response->serialize();
2014 $this->debug('got a(n) '.gettype($method_response).' from method');
2015 $this->debug('serializing return value');
2017 // weak attempt at supporting multiple output params
2018 if(sizeof($this->opData
['output']['parts']) > 1){
2019 $opParams = $method_response;
2021 $opParams = array($method_response);
2023 $return_val = $this->wsdl
->serializeRPCParameters($this->methodname
,'output',$opParams);
2025 $return_val = $this->serialize_val($method_response);
2028 $this->debug('return val:'.$this->varDump($return_val));
2031 $this->debug('got no response from method');
2033 $this->debug('serializing response');
2034 $payload = '<'.$this->methodname
."Response>".$return_val.'</'.$this->methodname
."Response>";
2035 $this->result
= 'successful';
2037 //if($this->debug_flag){
2038 $this->debug("WSDL debug data:\n".$this->wsdl
->debug_str
);
2040 // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
2041 return $this->serializeEnvelope($payload,$this->responseHeaders
,$this->wsdl
->usedNamespaces
,$this->opData
['style']);
2043 return $this->serializeEnvelope($payload,$this->responseHeaders
);
2047 $this->debug('ERROR: request not verified against method signature');
2048 $this->result
= 'fault: request failed validation against method signature';
2050 $this->fault('Server',"Operation '$this->methodname' not defined in service.");
2051 return $this->fault
->serialize();
2057 * takes the value that was created by parsing the request
2058 * and compares to the method's signature, if available.
2064 function verify_method($operation,$request){
2065 if(isset($this->wsdl
) && is_object($this->wsdl
)){
2066 if($this->wsdl
->getOperationData($operation)){
2069 } elseif(isset($this->operations
[$operation])){
2076 * add a method to the dispatch map
2078 * @param string $methodname
2079 * @param string $in array of input values
2080 * @param string $out array of output values
2083 function add_to_map($methodname,$in,$out){
2084 $this->operations
[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
2088 * register a service with the server
2090 * @param string $methodname
2091 * @param string $in assoc array of input values: key = param name, value = param type
2092 * @param string $out assoc array of output values: key = param name, value = param type
2093 * @param string $namespace
2094 * @param string $soapaction
2095 * @param string $style (rpc|literal)
2098 function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false){
2099 if($this->externalWSDLURL
){
2100 die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
2106 if(false == $namespace) {
2108 if(false == $soapaction) {
2109 global $SERVER_NAME, $SCRIPT_NAME;
2110 $soapaction = "http://$SERVER_NAME$SCRIPT_NAME";
2112 if(false == $style) {
2119 $this->operations
[$name] = array(
2123 'namespace' => $namespace,
2124 'soapaction' => $soapaction,
2127 $this->wsdl
->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use);
2133 * create a fault. this also acts as a flag to the server that a fault has occured.
2135 * @param string faultcode
2136 * @param string faultactor
2137 * @param string faultstring
2138 * @param string faultdetail
2141 function fault($faultcode,$faultactor,$faultstring='',$faultdetail=''){
2142 $this->fault
= new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
2146 * prints html description of services
2150 function webDescription(){
2152 <html><head><title>NuSOAP: '.$this->wsdl
->serviceName
.'</title>
2153 <style type="text/css">
2154 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
2155 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
2156 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
2157 ul { margin-top: 10px; margin-left: 20px; }
2158 li { list-style-type: none; margin-top: 10px; color: #000000; }
2160 margin-left: 0px; padding-bottom: 2em; }
2162 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
2163 margin-top: 10px; margin-left: 0px; color: #000000;
2164 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
2166 font-family: arial; font-size: 26px; color: #ffffff;
2167 background-color: #999999; width: 105%; margin-left: 0px;
2168 padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
2170 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
2171 font-family: arial; overflow: hidden; width: 600;
2172 padding: 20px; font-size: 10px; background-color: #999999;
2173 layer-background-color:#FFFFFF; }
2174 a,a:active { color: charcoal; font-weight: bold; }
2175 a:visited { color: #666666; font-weight: bold; }
2176 a:hover { color: cc3300; font-weight: bold; }
2178 <script language="JavaScript" type="text/javascript">
2180 // POP-UP CAPTIONS...
2181 function lib_bwcheck(){ //Browsercheck (needed)
2182 this.ver=navigator.appVersion
2183 this.agent=navigator.userAgent
2184 this.dom=document.getElementById?1:0
2185 this.opera5=this.agent.indexOf("Opera 5")>-1
2186 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
2187 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
2188 this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
2189 this.ie=this.ie4||this.ie5||this.ie6
2190 this.mac=this.agent.indexOf("Mac")>-1
2191 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
2192 this.ns4=(document.layers && !this.dom)?1:0;
2193 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
2196 var bw = new lib_bwcheck()
2197 //Makes crossbrowser object.
2198 function makeObj(obj){
2199 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
2200 if(!this.evnt) return false
2201 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
2202 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
2203 this.writeIt=b_writeIt;
2206 // A unit of measure that will be added when setting the position of a layer.
2207 //var px = bw.ns4||window.opera?"":"px";
2208 function b_writeIt(text){
2209 if (bw.ns4){this.wref.write(text);this.wref.close()}
2210 else this.wref.innerHTML = text
2212 //Shows the messages
2214 function popup(divid){
2215 if(oDesc = new makeObj(divid)){
2216 oDesc.css.visibility = "visible"
2219 function popout(){ // Hides message
2220 if(oDesc) oDesc.css.visibility = "hidden"
2228 <div class=title>'.$this->wsdl
->serviceName
.'</div>
2230 <p>View the <a href="'.$GLOBALS['PHP_SELF'].'?wsdl">WSDL</a> for the service.
2231 Click on an operation name to view it's details.</p>
2233 foreach($this->wsdl
->getOperations() as $op => $data){
2234 $b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>";
2235 // create hidden div
2236 $b .= "<div id='$op' class='hidden'>
2237 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
2238 foreach($data as $donnie => $marie){ // loop through opdata
2239 if($donnie == 'input' ||
$donnie == 'output'){ // show input/output data
2240 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
2241 foreach($marie as $captain => $tenille){ // loop through data
2242 if($captain == 'parts'){ // loop thru parts
2243 $b .= " $captain:<br>";
2244 //if(is_array($tenille)){
2245 foreach($tenille as $joanie => $chachi){
2246 $b .= " $joanie: $chachi<br>";
2250 $b .= " $captain: $tenille<br>";
2254 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
2262 </div></body></html>';
2267 * sets up wsdl object
2268 * this acts as a flag to enable internal WSDL generation
2269 * NOTE: NOT FUNCTIONAL
2271 * @param string $serviceName, name of the service
2272 * @param string $namespace, tns namespace
2274 function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http')
2276 $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ?
$_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
2277 $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ?
$_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
2278 if(false == $namespace) {
2279 $namespace = "http://$SERVER_NAME/soap/$serviceName";
2282 if(false == $endpoint) {
2283 $endpoint = "http://$SERVER_NAME$SCRIPT_NAME";
2286 $this->wsdl
= new wsdl
;
2287 $this->wsdl
->serviceName
= $serviceName;
2288 $this->wsdl
->endpoint
= $endpoint;
2289 $this->wsdl
->namespaces
['tns'] = $namespace;
2290 $this->wsdl
->namespaces
['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
2291 $this->wsdl
->namespaces
['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
2292 $this->wsdl
->bindings
[$serviceName.'Binding'] = array(
2293 'name'=>$serviceName.'Binding',
2295 'transport'=>$transport,
2296 'portType'=>$serviceName.'PortType');
2297 $this->wsdl
->ports
[$serviceName.'Port'] = array(
2298 'binding'=>$serviceName.'Binding',
2299 'location'=>$endpoint,
2300 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
2311 * parses a WSDL file, allows access to it's data, other utility methods
2313 * @author Dietrich Ayala <dietrich@ganx4.com>
2317 class wsdl
extends XMLSchema
{
2319 // define internal arrays of bindings, ports, operations, messages, etc.
2320 var $message = array();
2321 var $complexTypes = array();
2322 var $messages = array();
2323 var $currentMessage;
2324 var $currentOperation;
2325 var $portTypes = array();
2326 var $currentPortType;
2327 var $bindings = array();
2328 var $currentBinding;
2329 var $ports = array();
2331 var $opData = array();
2333 var $documentation = false;
2335 // array of wsdl docs to import
2336 var $import = array();
2341 var $depth_array = array();
2342 var $usedNamespaces = array();
2344 var $proxyhost = '';
2345 var $proxyport = '';
2350 * @param string $wsdl WSDL document URL
2353 function wsdl($wsdl = '',$proxyhost=false,$proxyport=false){
2354 $this->wsdl
= $wsdl;
2355 $this->proxyhost
= $proxyhost;
2356 $this->proxyport
= $proxyport;
2360 $this->debug('initial wsdl file: ' . $wsdl);
2361 $this->parseWSDL($wsdl);
2364 if (sizeof($this->import
) > 0) {
2365 foreach($this->import
as $ns => $url) {
2366 $this->debug('importing wsdl from ' . $url);
2367 $this->parseWSDL($url);
2373 * parses the wsdl document
2375 * @param string $wsdl path or URL
2378 function parseWSDL($wsdl = '')
2381 $this->debug('no wsdl passed to parseWSDL()!!');
2382 $this->setError('no wsdl passed to parseWSDL()!!');
2386 $this->debug('getting ' . $wsdl);
2388 // parse $wsdl for url format
2389 $wsdl_props = parse_url($wsdl);
2391 if (isset($wsdl_props['host'])) {
2394 $tr = new soap_transport_http($wsdl);
2395 $tr->request_method
= 'GET';
2396 $tr->useSOAPAction
= false;
2397 if($this->proxyhost
&& $this->proxyport
){
2398 $tr->setProxy($this->proxyhost
,$this->proxyport
);
2400 if (isset($wsdl_props['user'])) {
2401 $tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']);
2403 $wsdl_string = $tr->send('');
2405 if($err = $tr->getError() ){
2406 $this->debug('HTTP ERROR: '.$err);
2407 $this->setError('HTTP ERROR: '.$err);
2411 /* $wsdl seems to be a valid url, not a file path, do an fsockopen/HTTP GET
2412 $fsockopen_timeout = 30;
2413 // check if a port value is supplied in url
2414 if (isset($wsdl_props['port'])) {
2416 $wsdl_url_port = $wsdl_props['port'];
2418 // no, assign port number, based on url protocol (scheme)
2419 switch ($wsdl_props['scheme']) {
2423 $wsdl_url_port = 443;
2427 $wsdl_url_port = 80;
2430 // FIXME: should implement SSL/TLS support here if CURL is available
2431 if ($fp = fsockopen($wsdl_props['host'], $wsdl_url_port, $fsockopen_errnum, $fsockopen_errstr, $fsockopen_timeout)) {
2432 // perform HTTP GET for WSDL file
2433 // 10.9.02 - added poulter fix for doing this properly
2434 $sHeader = "GET " . $wsdl_props['path'];
2435 if (isset($wsdl_props['query'])) {
2436 $sHeader .= "?" . $wsdl_props['query'];
2438 $sHeader .= " HTTP/1.0\r\n";
2440 if (isset($wsdl_props['user'])) {
2441 $base64auth = base64_encode($wsdl_props['user'] . ":" . $wsdl_props['pass']);
2442 $sHeader .= "Authorization: Basic $base64auth\r\n";
2444 $sHeader .= "Host: " . $wsdl_props['host'] . ( isset($wsdl_props['port']) ? ":".$wsdl_props['port'] : "" ) . "\r\n\r\n";
2445 fputs($fp, $sHeader);
2447 while (fgets($fp, 1024) != "\r\n") {
2448 // do nothing, just read/skip past HTTP headers
2449 // FIXME: should actually detect HTTP response code, and act accordingly if error
2450 // HTTP headers end with extra CRLF before content body
2452 // read in WSDL just like regular fopen()
2454 while ($data = fread($fp, 32768)) {
2455 $wsdl_string .= $data;
2459 $this->setError('bad path to WSDL file.');
2464 // $wsdl seems to be a non-url file path, do the regular fopen
2465 if ($fp = @fopen
($wsdl, 'r')) {
2467 while ($data = fread($fp, 32768)) {
2468 $wsdl_string .= $data;
2472 $this->setError('bad path to WSDL file.');
2476 // end new code added
2477 // Create an XML parser.
2478 $this->parser
= xml_parser_create();
2479 // Set the options for parsing the XML data.
2480 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2481 xml_parser_set_option($this->parser
, XML_OPTION_CASE_FOLDING
, 0);
2482 // Set the object for the parser.
2483 xml_set_object($this->parser
, $this);
2484 // Set the element handlers for the parser.
2485 xml_set_element_handler($this->parser
, 'start_element', 'end_element');
2486 xml_set_character_data_handler($this->parser
, 'character_data');
2487 // Parse the XML file.
2488 if (!xml_parse($this->parser
, $wsdl_string, true)) {
2489 // Display an error message.
2491 'XML error on line %d: %s',
2492 xml_get_current_line_number($this->parser
),
2493 xml_error_string(xml_get_error_code($this->parser
))
2495 $this->debug('XML parse error: ' . $errstr);
2496 $this->setError('Parser error: ' . $errstr);
2500 xml_parser_free($this->parser
);
2501 // catch wsdl parse errors
2502 if($this->getError()){
2505 // add new data to operation data
2506 foreach($this->bindings
as $binding => $bindingData) {
2507 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
2508 foreach($bindingData['operations'] as $operation => $data) {
2509 $this->debug('post-parse data gathering for ' . $operation);
2510 $this->bindings
[$binding]['operations'][$operation]['input'] =
2511 isset($this->bindings
[$binding]['operations'][$operation]['input']) ?
2512 array_merge($this->bindings
[$binding]['operations'][$operation]['input'], $this->portTypes
[ $bindingData['portType'] ][$operation]['input']) :
2513 $this->portTypes
[ $bindingData['portType'] ][$operation]['input'];
2514 $this->bindings
[$binding]['operations'][$operation]['output'] =
2515 isset($this->bindings
[$binding]['operations'][$operation]['output']) ?
2516 array_merge($this->bindings
[$binding]['operations'][$operation]['output'], $this->portTypes
[ $bindingData['portType'] ][$operation]['output']) :
2517 $this->portTypes
[ $bindingData['portType'] ][$operation]['output'];
2518 if(isset($this->messages
[ $this->bindings
[$binding]['operations'][$operation]['input']['message'] ])){
2519 $this->bindings
[$binding]['operations'][$operation]['input']['parts'] = $this->messages
[ $this->bindings
[$binding]['operations'][$operation]['input']['message'] ];
2521 if(isset($this->messages
[ $this->bindings
[$binding]['operations'][$operation]['output']['message'] ])){
2522 $this->bindings
[$binding]['operations'][$operation]['output']['parts'] = $this->messages
[ $this->bindings
[$binding]['operations'][$operation]['output']['message'] ];
2524 if (isset($bindingData['style'])) {
2525 $this->bindings
[$binding]['operations'][$operation]['style'] = $bindingData['style'];
2527 $this->bindings
[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ?
$bindingData['transport'] : '';
2528 $this->bindings
[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes
[ $bindingData['portType'] ][$operation]['documentation']) ?
$this->portTypes
[ $bindingData['portType'] ][$operation]['documentation'] : '';
2529 $this->bindings
[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ?
$bindingData['endpoint'] : '';
2537 * start-element handler
2539 * @param string $parser XML parser object
2540 * @param string $name element name
2541 * @param string $attrs associative array of attributes
2544 function start_element($parser, $name, $attrs)
2546 if ($this->status
== 'schema' ||
ereg('schema$', $name)) {
2547 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
2548 $this->status
= 'schema';
2549 $this->schemaStartElement($parser, $name, $attrs);
2551 // position in the total number of elements, starting from 0
2552 $pos = $this->position++
;
2553 $depth = $this->depth++
;
2554 // set self as current value for this depth
2555 $this->depth_array
[$depth] = $pos;
2556 $this->message
[$pos] = array('cdata' => '');
2557 // get element prefix
2558 if (ereg(':', $name)) {
2560 $prefix = substr($name, 0, strpos($name, ':'));
2562 $namespace = isset($this->namespaces
[$prefix]) ?
$this->namespaces
[$prefix] : '';
2563 // get unqualified name
2564 $name = substr(strstr($name, ':'), 1);
2567 if (count($attrs) > 0) {
2568 foreach($attrs as $k => $v) {
2569 // if ns declarations, add to class level array of valid namespaces
2570 if (ereg("^xmlns", $k)) {
2571 if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
2572 $this->namespaces
[$ns_prefix] = $v;
2574 $this->namespaces
['ns' . (count($this->namespaces
) +
1)] = $v;
2576 if ($v == 'http://www.w3.org/2001/XMLSchema' ||
$v == 'http://www.w3.org/1999/XMLSchema') {
2577 $this->XMLSchemaVersion
= $v;
2578 $this->namespaces
['xsi'] = $v . '-instance';
2581 // expand each attribute
2582 $k = strpos($k, ':') ?
$this->expandQname($k) : $k;
2583 if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
2584 $v = strpos($v, ':') ?
$this->expandQname($v) : $v;
2592 // find status, register data
2593 switch ($this->status
) {
2595 if ($name == 'part') {
2596 if (isset($attrs['type'])) {
2597 $this->debug("msg " . $this->currentMessage
. ": found part $attrs[name]: " . implode(',', $attrs));
2598 $this->messages
[$this->currentMessage
][$attrs['name']] = $attrs['type'];
2600 if (isset($attrs['element'])) {
2601 $this->messages
[$this->currentMessage
][$attrs['name']] = $attrs['element'];
2608 $this->currentPortOperation
= $attrs['name'];
2609 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
2610 if (isset($attrs['parameterOrder'])) {
2611 $this->portTypes
[$this->currentPortType
][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
2614 case 'documentation':
2615 $this->documentation
= true;
2617 // merge input/output data
2619 $m = isset($attrs['message']) ?
$this->getLocalPart($attrs['message']) : '';
2620 $this->portTypes
[$this->currentPortType
][$this->currentPortOperation
][$name]['message'] = $m;
2628 if (isset($attrs['style'])) {
2629 $this->bindings
[$this->currentBinding
]['prefix'] = $prefix;
2631 $this->bindings
[$this->currentBinding
] = array_merge($this->bindings
[$this->currentBinding
], $attrs);
2634 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
][$this->opStatus
]['headers'][] = $attrs;
2637 if (isset($attrs['soapAction'])) {
2638 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
]['soapAction'] = $attrs['soapAction'];
2640 if (isset($attrs['style'])) {
2641 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
]['style'] = $attrs['style'];
2643 if (isset($attrs['name'])) {
2644 $this->currentOperation
= $attrs['name'];
2645 $this->debug("current binding operation: $this->currentOperation");
2646 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
]['name'] = $attrs['name'];
2647 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
]['binding'] = $this->currentBinding
;
2648 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
]['endpoint'] = isset($this->bindings
[$this->currentBinding
]['endpoint']) ?
$this->bindings
[$this->currentBinding
]['endpoint'] : '';
2652 $this->opStatus
= 'input';
2655 $this->opStatus
= 'output';
2658 if (isset($this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
][$this->opStatus
])) {
2659 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
][$this->opStatus
] = array_merge($this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
][$this->opStatus
], $attrs);
2661 $this->bindings
[$this->currentBinding
]['operations'][$this->currentOperation
][$this->opStatus
] = $attrs;
2669 $this->currentPort
= $attrs['name'];
2670 $this->debug('current port: ' . $this->currentPort
);
2671 $this->ports
[$this->currentPort
]['binding'] = $this->getLocalPart($attrs['binding']);
2675 $this->ports
[$this->currentPort
]['location'] = $attrs['location'];
2676 $this->ports
[$this->currentPort
]['bindingType'] = $namespace;
2677 $this->bindings
[ $this->ports
[$this->currentPort
]['binding'] ]['bindingType'] = $namespace;
2678 $this->bindings
[ $this->ports
[$this->currentPort
]['binding'] ]['endpoint'] = $attrs['location'];
2686 if (isset($attrs['location'])) {
2687 $this->import
[$attrs['namespace']] = $attrs['location'];
2691 $this->status
= 'schema';
2694 $this->status
= 'message';
2695 $this->messages
[$attrs['name']] = array();
2696 $this->currentMessage
= $attrs['name'];
2699 $this->status
= 'portType';
2700 $this->portTypes
[$attrs['name']] = array();
2701 $this->currentPortType
= $attrs['name'];
2704 if (isset($attrs['name'])) {
2706 if (strpos($attrs['name'], ':')) {
2707 $this->currentBinding
= $this->getLocalPart($attrs['name']);
2709 $this->currentBinding
= $attrs['name'];
2711 $this->status
= 'binding';
2712 $this->bindings
[$this->currentBinding
]['portType'] = $this->getLocalPart($attrs['type']);
2713 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
2717 $this->serviceName
= $attrs['name'];
2718 $this->status
= 'service';
2719 $this->debug('current service: ' . $this->serviceName
);
2722 foreach ($attrs as $name => $value) {
2723 $this->wsdl_info
[$name] = $value;
2731 * end-element handler
2733 * @param string $parser XML parser object
2734 * @param string $name element name
2737 function end_element($parser, $name){
2738 // unset schema status
2739 if (ereg('types$', $name) ||
ereg('schema$', $name)) {
2742 if ($this->status
== 'schema') {
2743 $this->schemaEndElement($parser, $name);
2745 // bring depth down a notch
2748 // end documentation
2749 if ($this->documentation
) {
2750 $this->portTypes
[$this->currentPortType
][$this->currentPortOperation
]['documentation'] = $this->documentation
;
2751 $this->documentation
= false;
2756 * element content handler
2758 * @param string $parser XML parser object
2759 * @param string $data element content
2762 function character_data($parser, $data)
2764 $pos = isset($this->depth_array
[$this->depth
]) ?
$this->depth_array
[$this->depth
] : 0;
2765 if (isset($this->message
[$pos]['cdata'])) {
2766 $this->message
[$pos]['cdata'] .= $data;
2768 if ($this->documentation
) {
2769 $this->documentation
.= $data;
2773 function getBindingData($binding)
2775 if (is_array($this->bindings
[$binding])) {
2776 return $this->bindings
[$binding];
2781 * returns an assoc array of operation names => operation data
2782 * NOTE: currently only supports multiple services of differing binding types
2783 * This method needs some work
2785 * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported)
2789 function getOperations($bindingType = 'soap')
2791 if ($bindingType == 'soap') {
2792 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
2795 foreach($this->ports
as $port => $portData) {
2796 // binding type of port matches parameter
2797 if ($portData['bindingType'] == $bindingType) {
2799 return $this->bindings
[ $portData['binding'] ]['operations'];
2806 * returns an associative array of data necessary for calling an operation
2808 * @param string $operation , name of operation
2809 * @param string $bindingType , type of binding eg: soap
2813 function getOperationData($operation, $bindingType = 'soap')
2815 if ($bindingType == 'soap') {
2816 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
2819 foreach($this->ports
as $port => $portData) {
2820 // binding type of port matches parameter
2821 if ($portData['bindingType'] == $bindingType) {
2823 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
2824 foreach(array_keys($this->bindings
[ $portData['binding'] ]['operations']) as $bOperation) {
2825 if ($operation == $bOperation) {
2826 $opData = $this->bindings
[ $portData['binding'] ]['operations'][$operation];
2835 * serialize the parsed wsdl
2837 * @return string , serialization of WSDL
2840 function serialize()
2842 $xml = '<?xml version="1.0"?><definitions';
2843 foreach($this->namespaces
as $k => $v) {
2844 $xml .= " xmlns:$k=\"$v\"";
2846 // 10.9.02 - add poulter fix for wsdl and tns declarations
2847 if (isset($this->namespaces
['wsdl'])) {
2848 $xml .= " xmlns=\"" . $this->namespaces
['wsdl'] . "\"";
2850 if (isset($this->namespaces
['tns'])) {
2851 $xml .= " targetNamespace=\"" . $this->namespaces
['tns'] . "\"";
2855 if (sizeof($this->import
) > 0) {
2856 foreach($this->import
as $ns => $url) {
2857 $xml .= '<import location="' . $url . '" namespace="' . $ns . '" />';
2861 if (count($this->complexTypes
)>=1) {
2863 $xml .= $this->serializeSchema();
2867 if (count($this->messages
) >= 1) {
2868 foreach($this->messages
as $msgName => $msgParts) {
2869 $xml .= '<message name="' . $msgName . '">';
2870 foreach($msgParts as $partName => $partType) {
2871 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
2872 if (strpos($partType, ':')) {
2873 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
2874 } elseif (isset($this->typemap
[$this->namespaces
['xsd']][$partType])) {
2875 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
2876 $typePrefix = 'xsd';
2878 foreach($this->typemap
as $ns => $types) {
2879 if (isset($types[$partType])) {
2880 $typePrefix = $this->getPrefixFromNamespace($ns);
2883 if (!isset($typePrefix)) {
2884 die("$partType has no namespace!");
2887 $xml .= '<part name="' . $partName . '" type="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
2889 $xml .= '</message>';
2892 // bindings & porttypes
2893 if (count($this->bindings
) >= 1) {
2896 foreach($this->bindings
as $bindingName => $attrs) {
2897 $binding_xml .= '<binding name="' . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
2898 $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
2899 $portType_xml .= '<portType name="' . $attrs['portType'] . '">';
2900 foreach($attrs['operations'] as $opName => $opParts) {
2901 $binding_xml .= '<operation name="' . $opName . '">';
2902 $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $attrs['style'] . '"/>';
2903 $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '" encodingStyle="' . $opParts['input']['encodingStyle'] . '"/></input>';
2904 $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '" encodingStyle="' . $opParts['output']['encodingStyle'] . '"/></output>';
2905 $binding_xml .= '</operation>';
2906 $portType_xml .= '<operation name="' . $opParts['name'] . '"';
2907 if (isset($opParts['parameterOrder'])) {
2908 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
2910 $portType_xml .= '>';
2911 $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
2912 $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
2913 $portType_xml .= '</operation>';
2915 $portType_xml .= '</portType>';
2916 $binding_xml .= '</binding>';
2918 $xml .= $portType_xml . $binding_xml;
2921 $xml .= '<service name="' . $this->serviceName
. '">';
2922 if (count($this->ports
) >= 1) {
2923 foreach($this->ports
as $pName => $attrs) {
2924 $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
2925 $xml .= '<soap:address location="' . $attrs['location'] . '"/>';
2929 $xml .= '</service>';
2930 return $xml . '</definitions>';
2934 * serialize a PHP value according to a WSDL message definition
2937 * - multi-ref serialization
2938 * - validate PHP values against type definitions, return errors if invalid
2940 * @param string $ type name
2941 * @param mixed $ param value
2942 * @return mixed new param or false if initial value didn't validate
2944 function serializeRPCParameters($operation, $direction, $parameters)
2946 $this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion
);
2948 if ($direction != 'input' && $direction != 'output') {
2949 $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
2950 $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
2953 if (!$opData = $this->getOperationData($operation)) {
2954 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
2955 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
2958 $this->debug($this->varDump($opData));
2961 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
2963 $use = $opData[$direction]['use'];
2964 $this->debug("use=$use");
2965 $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
2966 foreach($opData[$direction]['parts'] as $name => $type) {
2967 $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
2968 // NOTE: add error handling here
2969 // if serializeType returns false, then catch global error and fault
2970 if (isset($parameters[$name])) {
2971 $this->debug('calling serializeType w/ named param');
2972 $xml .= $this->serializeType($name, $type, $parameters[$name], $use);
2973 } elseif(is_array($parameters)) {
2974 $this->debug('calling serializeType w/ unnamed param');
2975 $xml .= $this->serializeType($name, $type, array_shift($parameters), $use);
2977 $this->debug('no parameters passed.');
2985 * serializes a PHP value according a given type definition
2987 * @param string $name , name of type (part)
2988 * @param string $type , type of type, heh (type or element)
2989 * @param mixed $value , a native PHP value (parameter value)
2990 * @param string $use , use for part (encoded|literal)
2991 * @return string serialization
2994 function serializeType($name, $type, $value, $use='encoded')
2996 $this->debug("in serializeType: $name, $type, $value, $use");
2998 if (strpos($type, ':')) {
2999 $uqType = substr($type, strrpos($type, ':') +
1);
3000 $ns = substr($type, 0, strrpos($type, ':'));
3001 $this->debug("got a prefixed type: $uqType, $ns");
3003 if($ns == $this->XMLSchemaVersion ||
3004 ($this->getNamespaceFromPrefix($ns)) == $this->XMLSchemaVersion
){
3006 if ($uqType == 'boolean' && !$value) {
3008 } elseif ($uqType == 'boolean') {
3011 if ($this->charencoding
&& $uqType == 'string' && gettype($value) == 'string') {
3012 $value = htmlspecialchars($value);
3015 if ($use == 'literal') {
3016 return "<$name>$value</$name>";
3018 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion
) . ":$uqType\">$value</$name>";
3024 if(!$typeDef = $this->getTypeDef($uqType)){
3025 $this->setError("$uqType is not a supported type.");
3028 //foreach($typeDef as $k => $v) {
3029 //$this->debug("typedef, $k: $v");
3032 $phpType = $typeDef['phpType'];
3033 $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ?
$typeDef['arrayType'] : '') );
3034 // if php type == struct, map value to the <all> element names
3035 if ($phpType == 'struct') {
3036 if (isset($typeDef['element']) && $typeDef['element']) {
3037 $elementName = $uqType;
3038 // TODO: use elementFormDefault="qualified|unqualified" to determine
3039 // how to scope the namespace
3040 $elementNS = " xmlns=\"$ns\"";
3042 $elementName = $name;
3045 if ($use == 'literal') {
3046 $xml = "<$elementName$elementNS>";
3048 $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
3051 if (isset($this->complexTypes
[$uqType]['elements']) && is_array($this->complexTypes
[$uqType]['elements'])) {
3053 //if (is_array($this->complexTypes[$uqType]['elements'])) {
3054 // toggle whether all elements are present - ideally should validate against schema
3055 if(count($this->complexTypes
[$uqType]['elements']) != count($value)){
3058 foreach($this->complexTypes
[$uqType]['elements'] as $eName => $attrs) {
3059 // if user took advantage of a minOccurs=0, then only serialize named parameters
3060 if(isset($optionals) && !isset($value[$eName])){
3064 if (isset($value[$eName])) {
3065 $v = $value[$eName];
3066 } elseif (is_array($value)) {
3067 $v = array_shift($value);
3069 // serialize schema-defined type
3070 if (!isset($attrs['type'])) {
3071 $xml .= $this->serializeType($eName, $attrs['name'], $v, $use);
3072 // serialize generic type
3074 $this->debug("calling serialize_val() for $eName, $v, " . $this->getLocalPart($attrs['type']), false, $use);
3075 $xml .= $this->serialize_val($v, $eName, $this->getLocalPart($attrs['type']), null, $this->getNamespaceFromPrefix($this->getPrefix($attrs['type'])), false, $use);
3080 $xml .= "</$elementName>";
3081 } elseif ($phpType == 'array') {
3082 $rows = sizeof($value);
3083 if (isset($typeDef['multidimensional'])) {
3085 foreach($value as $v) {
3086 $cols = ',' . sizeof($v);
3087 $nv = array_merge($nv, $v);
3093 if (is_array($value) && sizeof($value) >= 1) {
3095 foreach($value as $k => $v) {
3096 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
3097 //if (strpos($typeDef['arrayType'], ':') ) {
3098 if (!in_array($typeDef['arrayType'],$this->typemap
['http://www.w3.org/2001/XMLSchema'])) {
3099 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
3101 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion
, false, $use);
3104 $this->debug('contents: '.$this->varDump($contents));
3108 if ($use == 'literal') {
3113 $xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
3114 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
3116 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
3117 .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
3122 $this->debug('returning: '.$this->varDump($xml));
3127 * register a service with the server
3129 * @param string $methodname
3130 * @param string $in assoc array of input values: key = param name, value = param type
3131 * @param string $out assoc array of output values: key = param name, value = param type
3132 * @param string $namespace
3133 * @param string $soapaction
3134 * @param string $style (rpc|literal)
3137 function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '')
3139 if ($style == 'rpc' && $use == 'encoded') {
3140 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
3142 $encodingStyle = '';
3145 $this->bindings
[ $this->serviceName
. 'Binding' ]['operations'][$name] =
3148 'binding' => $this->serviceName
. 'Binding',
3149 'endpoint' => $this->endpoint
,
3150 'soapAction' => $soapaction,
3154 'namespace' => $namespace,
3155 'encodingStyle' => $encodingStyle,
3156 'message' => $name . 'Request',
3160 'namespace' => $namespace,
3161 'encodingStyle' => $encodingStyle,
3162 'message' => $name . 'Response',
3164 'namespace' => $namespace,
3165 'transport' => 'http://schemas.xmlsoap.org/soap/http',
3166 'documentation' => $documentation);
3171 foreach($in as $pName => $pType)
3173 if(strpos($pType,':')) {
3174 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
3176 $this->messages
[$name.'Request'][$pName] = $pType;
3182 foreach($out as $pName => $pType)
3184 if(strpos($pType,':')) {
3185 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
3187 $this->messages
[$name.'Response'][$pName] = $pType;
3202 * soap_parser class parses SOAP XML messages into native PHP values
3204 * @author Dietrich Ayala <dietrich@ganx4.com>
3208 class soap_parser
extends nusoap_base
{
3211 var $xml_encoding = '';
3213 var $root_struct = '';
3214 var $root_struct_name = '';
3215 var $root_header = '';
3217 // determines where in the message we are (envelope,header,body,method)
3221 var $default_namespace = '';
3222 var $namespaces = array();
3223 var $message = array();
3226 var $fault_code = '';
3227 var $fault_str = '';
3228 var $fault_detail = '';
3229 var $depth_array = array();
3230 var $debug_flag = true;
3231 var $soapresponse = NULL;
3232 var $responseHeaders = '';
3233 var $body_position = 0;
3234 // for multiref parsing:
3235 // array of id => pos
3237 // array of id => hrefs => pos
3238 var $multirefs = array();
3243 * @param string $xml SOAP message
3244 * @param string $encoding character encoding scheme of message
3247 function soap_parser($xml,$encoding='UTF-8',$method=''){
3249 $this->xml_encoding
= $encoding;
3250 $this->method
= $method;
3252 // Check whether content has been read.
3254 $this->debug('Entering soap_parser()');
3255 // Create an XML parser.
3256 $this->parser
= xml_parser_create($this->xml_encoding
);
3257 // Set the options for parsing the XML data.
3258 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
3259 xml_parser_set_option($this->parser
, XML_OPTION_CASE_FOLDING
, 0);
3260 // Set the object for the parser.
3261 xml_set_object($this->parser
, $this);
3262 // Set the element handlers for the parser.
3263 xml_set_element_handler($this->parser
, 'start_element','end_element');
3264 xml_set_character_data_handler($this->parser
,'character_data');
3266 // Parse the XML file.
3267 if(!xml_parse($this->parser
,$xml,true)){
3268 // Display an error message.
3269 $err = sprintf('XML error on line %d: %s',
3270 xml_get_current_line_number($this->parser
),
3271 xml_error_string(xml_get_error_code($this->parser
)));
3272 $this->debug('parse error: '.$err);
3273 $this->errstr
= $err;
3275 $this->debug('parsed successfully, found root struct: '.$this->root_struct
.' of name '.$this->root_struct_name
);
3277 $this->soapresponse
= $this->message
[$this->root_struct
]['result'];
3279 if($this->root_header
!= '' && isset($this->message
[$this->root_header
]['result'])){
3280 $this->responseHeaders
= $this->message
[$this->root_header
]['result'];
3282 // resolve hrefs/ids
3283 if(sizeof($this->multirefs
) > 0){
3284 foreach($this->multirefs
as $id => $hrefs){
3285 $this->debug('resolving multirefs for id: '.$id);
3286 $idVal = $this->buildVal($this->ids
[$id]);
3287 foreach($hrefs as $refPos => $ref){
3288 $this->debug('resolving href at pos '.$refPos);
3289 $this->multirefs
[$id][$refPos] = $idVal;
3294 xml_parser_free($this->parser
);
3296 $this->debug('xml was empty, didn\'t parse!');
3297 $this->errstr
= 'xml was empty, didn\'t parse!';
3302 * start-element handler
3304 * @param string $parser XML parser object
3305 * @param string $name element name
3306 * @param string $attrs associative array of attributes
3309 function start_element($parser, $name, $attrs) {
3310 // position in a total number of elements, starting from 0
3311 // update class level pos
3312 $pos = $this->position++
;
3314 $this->message
[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
3315 // depth = how many levels removed from root?
3316 // set mine as current global depth and increment global depth value
3317 $this->message
[$pos]['depth'] = $this->depth++
;
3319 // else add self as child to whoever the current parent is
3321 $this->message
[$this->parent
]['children'] .= '|'.$pos;
3324 $this->message
[$pos]['parent'] = $this->parent
;
3325 // set self as current parent
3326 $this->parent
= $pos;
3327 // set self as current value for this depth
3328 $this->depth_array
[$this->depth
] = $pos;
3329 // get element prefix
3330 if(strpos($name,':')){
3332 $prefix = substr($name,0,strpos($name,':'));
3333 // get unqualified name
3334 $name = substr(strstr($name,':'),1);
3337 if($name == 'Envelope'){
3338 $this->status
= 'envelope';
3339 } elseif($name == 'Header'){
3340 $this->root_header
= $pos;
3341 $this->status
= 'header';
3342 } elseif($name == 'Body'){
3343 $this->status
= 'body';
3344 $this->body_position
= $pos;
3346 } elseif($this->status
== 'body' && $pos == ($this->body_position+
1)){
3347 $this->status
= 'method';
3348 $this->root_struct_name
= $name;
3349 $this->root_struct
= $pos;
3350 $this->message
[$pos]['type'] = 'struct';
3351 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
3354 $this->message
[$pos]['status'] = $this->status
;
3356 $this->message
[$pos]['name'] = htmlspecialchars($name);
3358 $this->message
[$pos]['attrs'] = $attrs;
3360 // loop through atts, logging ns and type declarations
3362 foreach($attrs as $key => $value){
3363 $key_prefix = $this->getPrefix($key);
3364 $key_localpart = $this->getLocalPart($key);
3365 // if ns declarations, add to class level array of valid namespaces
3366 if($key_prefix == 'xmlns'){
3367 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
3368 $this->XMLSchemaVersion
= $value;
3369 $this->namespaces
['xsd'] = $this->XMLSchemaVersion
;
3370 $this->namespaces
['xsi'] = $this->XMLSchemaVersion
.'-instance';
3372 $this->namespaces
[$key_localpart] = $value;
3373 // set method namespace
3374 if($name == $this->root_struct_name
){
3375 $this->methodNamespace
= $value;
3377 // if it's a type declaration, set type
3378 } elseif($key_localpart == 'type'){
3379 $value_prefix = $this->getPrefix($value);
3380 $value_localpart = $this->getLocalPart($value);
3381 $this->message
[$pos]['type'] = $value_localpart;
3382 $this->message
[$pos]['typePrefix'] = $value_prefix;
3383 if(isset($this->namespaces
[$value_prefix])){
3384 $this->message
[$pos]['type_namespace'] = $this->namespaces
[$value_prefix];
3385 } else if(isset($attrs['xmlns:'.$value_prefix])) {
3386 $this->message
[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
3388 // should do something here with the namespace of specified type?
3389 } elseif($key_localpart == 'arrayType'){
3390 $this->message
[$pos]['type'] = 'array';
3391 /* do arrayType ereg here
3392 [1] arrayTypeValue ::= atype asize
3393 [2] atype ::= QName rank*
3394 [3] rank ::= '[' (',')* ']'
3395 [4] asize ::= '[' length~ ']'
3396 [5] length ::= nextDimension* Digit+
3397 [6] nextDimension ::= Digit+ ','
3399 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
3400 if(ereg($expr,$value,$regs)){
3401 $this->message
[$pos]['typePrefix'] = $regs[1];
3402 $this->message
[$pos]['arraySize'] = $regs[3];
3403 $this->message
[$pos]['arrayCols'] = $regs[4];
3408 $this->ids
[$value] = $pos;
3411 if($key_localpart == 'root' && $value == 1){
3412 $this->status
= 'method';
3413 $this->root_struct_name
= $name;
3414 $this->root_struct
= $pos;
3415 $this->debug("found root struct $this->root_struct_name, pos $pos");
3418 $attstr .= " $key=\"$value\"";
3420 // get namespace - must be done after namespace atts are processed
3422 $this->message
[$pos]['namespace'] = $this->namespaces
[$prefix];
3423 $this->default_namespace
= $this->namespaces
[$prefix];
3425 $this->message
[$pos]['namespace'] = $this->default_namespace
;
3427 if($this->status
== 'header'){
3428 $this->responseHeaders
.= "<$name$attstr>";
3429 } elseif($this->root_struct_name
!= ''){
3430 $this->document
.= "<$name$attstr>";
3435 * end-element handler
3437 * @param string $parser XML parser object
3438 * @param string $name element name
3441 function end_element($parser, $name) {
3442 // position of current element is equal to the last value left in depth_array for my depth
3443 $pos = $this->depth_array
[$this->depth
--];
3445 // get element prefix
3446 if(strpos($name,':')){
3448 $prefix = substr($name,0,strpos($name,':'));
3449 // get unqualified name
3450 $name = substr(strstr($name,':'),1);
3453 // build to native type
3454 if(isset($this->body_position
) && $pos > $this->body_position
){
3455 // deal w/ multirefs
3456 if(isset($this->message
[$pos]['attrs']['href'])){
3458 $id = substr($this->message
[$pos]['attrs']['href'],1);
3459 // add placeholder to href array
3460 $this->multirefs
[$id][$pos] = "placeholder";
3461 // add set a reference to it as the result value
3462 $this->message
[$pos]['result'] =& $this->multirefs
[$id][$pos];
3463 // build complex values
3464 } elseif($this->message
[$pos]['children'] != ""){
3465 $this->message
[$pos]['result'] = $this->buildVal($pos);
3467 $this->debug('adding data for scalar value '.$this->message
[$pos]['name'].' of value '.$this->message
[$pos]['cdata']);
3468 if(is_numeric($this->message
[$pos]['cdata']) ){
3469 if( strpos($this->message
[$pos]['cdata'],'.') ){
3470 $this->message
[$pos]['result'] = doubleval($this->message
[$pos]['cdata']);
3472 $this->message
[$pos]['result'] = intval($this->message
[$pos]['cdata']);
3475 $this->message
[$pos]['result'] = $this->message
[$pos]['cdata'];
3481 if($pos == $this->root_struct
){
3482 $this->status
= 'body';
3483 } elseif($name == 'Body'){
3484 $this->status
= 'header';
3485 } elseif($name == 'Header'){
3486 $this->status
= 'envelope';
3487 } elseif($name == 'Envelope'){
3490 // set parent back to my parent
3491 $this->parent
= $this->message
[$pos]['parent'];
3493 if($this->status
== 'header'){
3494 $this->responseHeaders
.= "</$name>";
3495 } elseif($pos >= $this->root_struct
){
3496 $this->document
.= "</$name>";
3501 * element content handler
3503 * @param string $parser XML parser object
3504 * @param string $data element content
3507 function character_data($parser, $data){
3508 $pos = $this->depth_array
[$this->depth
];
3509 if ($this->xml_encoding
=='UTF-8'){
3510 $data = utf8_decode($data);
3512 $this->message
[$pos]['cdata'] .= $data;
3514 if($this->status
== 'header'){
3515 $this->responseHeaders
.= $data;
3517 $this->document
.= $data;
3522 * get the parsed message
3527 function get_response(){
3528 return $this->soapresponse
;
3532 * get the parsed headers
3534 * @return string XML or empty if no headers
3537 function getHeaders(){
3538 return $this->responseHeaders
;
3544 * @param string $text string to translate
3547 function decode_entities($text){
3548 foreach($this->entities
as $entity => $encoded){
3549 $text = str_replace($encoded,$entity,$text);
3555 * builds response structures for compound values (arrays/structs)
3557 * @param string $pos position in node tree
3560 function buildVal($pos){
3561 if(!isset($this->message
[$pos]['type'])){
3562 $this->message
[$pos]['type'] = '';
3564 $this->debug('inside buildVal() for '.$this->message
[$pos]['name']."(pos $pos) of type ".$this->message
[$pos]['type']);
3565 // if there are children...
3566 if($this->message
[$pos]['children'] != ''){
3567 $children = explode('|',$this->message
[$pos]['children']);
3568 array_shift($children); // knock off empty
3570 if(isset($this->message
[$pos]['arrayCols']) && $this->message
[$pos]['arrayCols'] != ''){
3573 foreach($children as $child_pos){
3574 $this->debug("got an MD array element: $r, $c");
3575 $params[$r][] = $this->message
[$child_pos]['result'];
3577 if($c == $this->message
[$pos]['arrayCols']){
3583 } elseif($this->message
[$pos]['type'] == 'array' ||
$this->message
[$pos]['type'] == 'Array'){
3584 $this->debug('adding array '.$this->message
[$pos]['name']);
3585 foreach($children as $child_pos){
3586 $params[] = &$this->message
[$child_pos]['result'];
3588 // apache Map type: java hashtable
3589 } elseif($this->message
[$pos]['type'] == 'Map' && $this->message
[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
3590 foreach($children as $child_pos){
3591 $kv = explode("|",$this->message
[$child_pos]['children']);
3592 $params[$this->message
[$kv[1]]['result']] = &$this->message
[$kv[2]]['result'];
3594 // generic compound type
3595 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
3597 // is array or struct? better way to do this probably
3598 foreach($children as $child_pos){
3599 if(isset($keys) && isset($keys[$this->message
[$child_pos]['name']])){
3603 $keys[$this->message
[$child_pos]['name']] = 1;
3606 foreach($children as $child_pos){
3608 $params[] = &$this->message
[$child_pos]['result'];
3610 $params[$this->message
[$child_pos]['name']] = &$this->message
[$child_pos]['result'];
3614 return is_array($params) ?
$params : array();
3616 $this->debug('no children');
3617 if(strpos($this->message
[$pos]['cdata'],'&')){
3618 return strtr($this->message
[$pos]['cdata'],array_flip($this->entities
));
3620 return $this->message
[$pos]['cdata'];
3634 * soapclient higher level class for easy usage.
3638 * // instantiate client with server info
3639 * $soapclient = new soapclient( string path [ ,boolean wsdl] );
3641 * // call method, get results
3642 * echo $soapclient->call( string methodname [ ,array parameters] );
3645 * unset($soapclient);
3647 * @author Dietrich Ayala <dietrich@ganx4.com>
3651 class nusoap_client
extends nusoap_base
{
3655 var $requestHeaders = false;
3656 var $responseHeaders;
3658 var $error_str = false;
3659 var $proxyhost = '';
3660 var $proxyport = '';
3661 var $xml_encoding = '';
3662 var $http_encoding = false;
3664 var $endpointType = '';
3665 var $persistentConnection = false;
3666 var $defaultRpcParams = false;
3669 * fault related variables
3677 var $fault, $faultcode, $faultstring, $faultdetail;
3682 * @param string $endpoint SOAP server or WSDL URL
3683 * @param bool $wsdl optional, set to true if using WSDL
3684 * @param int $portName optional portName in WSDL document
3687 function nusoap_client($endpoint,$wsdl = false) {
3688 $this->endpoint
= $endpoint;
3692 $this->endpointType
= 'wsdl';
3693 $this->wsdlFile
= $this->endpoint
;
3695 // instantiate wsdl object and parse wsdl file
3696 $this->debug('instantiating wsdl class with doc: '.$endpoint);
3697 $this->wsdl
=& new wsdl($this->wsdlFile
,$this->proxyhost
,$this->proxyport
);
3698 $this->debug("wsdl debug: \n".$this->wsdl
->debug_str
);
3699 $this->wsdl
->debug_str
= '';
3701 if($errstr = $this->wsdl
->getError()){
3702 $this->debug('got wsdl error: '.$errstr);
3703 $this->setError('wsdl error: '.$errstr);
3704 } elseif($this->operations
= $this->wsdl
->getOperations()){
3705 $this->debug( 'got '.count($this->operations
).' operations from wsdl '.$this->wsdlFile
);
3707 $this->debug( 'getOperations returned false');
3708 $this->setError('no operations defined in the WSDL document!');
3714 * calls method, returns PHP native type
3716 * @param string $method SOAP server URL or path
3717 * @param array $params array of parameters, can be associative or not
3718 * @param string $namespace optional method namespace
3719 * @param string $soapAction optional SOAPAction value
3720 * @param boolean $headers optional array of soapval objects for headers
3721 * @param boolean $rpcParams optional treat params as RPC for use="literal"
3722 * This can be used on a per-call basis to overrider defaultRpcParams.
3726 function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null){
3727 $this->operation
= $operation;
3728 $this->fault
= false;
3729 $this->error_str
= '';
3730 $this->request
= '';
3731 $this->response
= '';
3732 $this->faultstring
= '';
3733 $this->faultcode
= '';
3734 $this->opData
= array();
3736 $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $rpcParams");
3737 $this->debug("endpointType: $this->endpointType");
3738 // if wsdl, get operation data and process parameters
3739 if($this->endpointType
== 'wsdl' && $opData = $this->getOperationData($operation)){
3741 $this->opData
= $opData;
3742 foreach($opData as $key => $value){
3743 $this->debug("$key -> $value");
3745 $soapAction = $opData['soapAction'];
3746 $this->endpoint
= $opData['endpoint'];
3747 $namespace = isset($opData['input']['namespace']) ?
$opData['input']['namespace'] : 'http://testuri.org';
3748 $style = $opData['style'];
3749 // add ns to ns array
3750 if($namespace != '' && !isset($this->wsdl
->namespaces
[$namespace])){
3751 $this->wsdl
->namespaces
['nu'] = $namespace;
3753 // serialize payload
3755 if($opData['input']['use'] == 'literal') {
3756 if (is_null($rpcParams)) {
3757 $rpcParams = $this->defaultRpcParams
;
3760 $this->debug("serializing literal params for operation $operation");
3761 $payload = $this->wsdl
->serializeRPCParameters($operation,'input',$params);
3762 $defaultNamespace = $this->wsdl
->wsdl_info
['targetNamespace'];
3764 $this->debug("serializing literal document for operation $operation");
3765 $payload = is_array($params) ?
array_shift($params) : $params;
3768 $this->debug("serializing encoded params for operation $operation");
3769 $payload = "<".$this->wsdl
->getPrefixFromNamespace($namespace).":$operation>".
3770 $this->wsdl
->serializeRPCParameters($operation,'input',$params).
3771 '</'.$this->wsdl
->getPrefixFromNamespace($namespace).":$operation>";
3773 $this->debug('payload size: '.strlen($payload));
3774 // serialize envelope
3775 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders
,$this->wsdl
->usedNamespaces
,$style);
3776 $this->debug("wsdl debug: \n".$this->wsdl
->debug_str
);
3777 $this->wsdl
->debug_str
= '';
3778 } elseif($this->endpointType
== 'wsdl') {
3779 $this->setError( 'operation '.$operation.' not present.');
3780 $this->debug("operation '$operation' not present.");
3781 $this->debug("wsdl debug: \n".$this->wsdl
->debug_str
);
3789 if($namespace == ''){
3790 $namespace = 'http://testuri.org';
3791 $this->wsdl
->namespaces
['ns1'] = $namespace;
3793 // serialize envelope
3795 foreach($params as $k => $v){
3796 $payload .= $this->serialize_val($v,$k);
3798 $payload = "<ns1:$operation xmlns:ns1=\"$namespace\">\n".$payload."</ns1:$operation>\n";
3799 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders
);
3801 $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace");
3803 $this->debug('sending msg (len: '.strlen($soapmsg).") w/ soapaction '$soapAction'...");
3804 $return = $this->send($soapmsg,$soapAction,$this->timeout
);
3805 if($errstr = $this->getError()){
3806 $this->debug('Error: '.$errstr);
3809 $this->return = $return;
3810 $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
3813 if(is_array($return) && isset($return['faultcode'])){
3814 $this->debug('got fault');
3815 $this->setError($return['faultcode'].': '.$return['faultstring']);
3816 $this->fault
= true;
3817 foreach($return as $k => $v){
3819 $this->debug("$k = $v<br>");
3823 // array of return values
3824 if(is_array($return)){
3825 // multiple 'out' parameters
3826 if(sizeof($return) > 1){
3829 // single 'out' parameter
3830 return array_shift($return);
3831 // nothing returned (ie, echoVoid)
3840 * get available data pertaining to an operation
3842 * @param string $operation operation name
3843 * @return array array of data pertaining to the operation
3846 function getOperationData($operation){
3847 if(isset($this->operations
[$operation])){
3848 return $this->operations
[$operation];
3850 $this->debug("No data for operation: $operation");
3854 * send the SOAP message
3856 * Note: if the operation has multiple return values
3857 * the return value of this method will be an array
3860 * @param string $msg a SOAPx4 soapmsg object
3861 * @param string $soapaction SOAPAction value
3862 * @param integer $timeout set timeout in seconds
3863 * @return mixed native PHP types.
3866 function send($msg, $soapaction = '', $timeout=0) {
3870 case ereg('^http',$this->endpoint
):
3871 $this->debug('transporting via HTTP');
3872 if($this->persistentConnection
&& is_object($this->persistentConnection
)){
3873 $http =& $this->persistentConnection
;
3875 $http = new soap_transport_http($this->endpoint
);
3876 // pass encoding into transport layer, so appropriate http headers are sent
3877 $http->soap_defencoding
= $this->soap_defencoding
;
3879 $http->setSOAPAction($soapaction);
3880 if($this->proxyhost
&& $this->proxyport
){
3881 $http->setProxy($this->proxyhost
,$this->proxyport
);
3883 if($this->username
!= '' && $this->password
!= '') {
3884 $http->setCredentials($this->username
,$this->password
);
3886 if($this->http_encoding
!= ''){
3887 $http->setEncoding($this->http_encoding
);
3889 $this->debug('sending message, length: '.strlen($msg));
3890 if(ereg('^http:',$this->endpoint
)){
3891 //if(strpos($this->endpoint,'http:')){
3892 $response = $http->send($msg,$timeout);
3893 } elseif(ereg('^https',$this->endpoint
)){
3894 //} elseif(strpos($this->endpoint,'https:')){
3895 //if(phpversion() == '4.3.0-dev'){
3896 //$response = $http->send($msg,$timeout);
3897 //$this->request = $http->outgoing_payload;
3898 //$this->response = $http->incoming_payload;
3900 if (extension_loaded('curl')) {
3901 $response = $http->sendHTTPS($msg,$timeout);
3903 $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
3906 $this->setError('no http/s in endpoint url');
3908 $this->request
= $http->outgoing_payload
;
3909 $this->response
= $http->incoming_payload
;
3910 $this->debug("transport debug data...\n".$http->debug_str
);
3911 // save transport object if using persistent connections
3912 if($this->persistentConnection
&& !is_object($this->persistentConnection
)){
3913 $this->persistentConnection
= $http;
3915 if($err = $http->getError()){
3916 $this->setError('HTTP Error: '.$err);
3918 } elseif($this->getError()){
3921 $this->debug('got response, length: '.strlen($response));
3922 return $this->parseResponse($response);
3926 $this->setError('no transport found, or selected transport is not yet supported!');
3933 * processes SOAP message returned from server
3935 * @param string unprocessed response data from server
3936 * @return mixed value of the message, decoded into a PHP type
3939 function parseResponse($data) {
3940 $this->debug('Entering parseResponse(), about to create soap_parser instance');
3941 $parser = new soap_parser($data,$this->xml_encoding
,$this->operation
);
3943 if($errstr = $parser->getError()){
3944 $this->setError( $errstr);
3945 // destroy the parser object
3950 $this->responseHeaders
= $parser->getHeaders();
3951 // get decoded message
3952 $return = $parser->get_response();
3953 // add parser debug data to our debug
3954 $this->debug($parser->debug_str
);
3955 // add document for doclit support
3956 $this->document
= $parser->document
;
3957 // destroy the parser object
3959 // return decode message
3965 * set the SOAP headers
3967 * @param $headers string XML
3970 function setHeaders($headers){
3971 $this->requestHeaders
= $headers;
3975 * get the response headers
3977 * @return mixed object SOAPx4 soapval object or empty if no headers
3980 function getHeaders(){
3981 if($this->responseHeaders
!= '') {
3982 return $this->responseHeaders
;
3987 * set proxy info here
3989 * @param string $proxyhost
3990 * @param string $proxyport
3993 function setHTTPProxy($proxyhost, $proxyport) {
3994 $this->proxyhost
= $proxyhost;
3995 $this->proxyport
= $proxyport;
3999 * if authenticating, set user credentials here
4001 * @param string $username
4002 * @param string $password
4005 function setCredentials($username, $password) {
4006 $this->username
= $username;
4007 $this->password
= $password;
4013 * @param string $enc
4016 function setHTTPEncoding($enc='gzip, deflate'){
4017 $this->http_encoding
= $enc;
4021 * use HTTP persistent connections if possible
4025 function useHTTPPersistentConnection(){
4026 $this->persistentConnection
= true;
4030 * gets the default RPC parameter setting.
4031 * If true, default is that call params are like RPC even for document style.
4032 * Each call() can override this value.
4036 function getDefaultRpcParams() {
4037 return $this->defaultRpcParams
;
4041 * sets the default RPC parameter setting.
4042 * If true, default is that call params are like RPC even for document style
4043 * Each call() can override this value.
4045 * @param boolean $rpcParams
4048 function setDefaultRpcParams($rpcParams) {
4049 $this->defaultRpcParams
= $rpcParams;
4053 * dynamically creates proxy class, allowing user to directly call methods from wsdl
4055 * @return object soap_proxy object
4058 function getProxy(){
4060 foreach($this->operations
as $operation => $opData){
4061 if($operation != ''){
4062 // create param string
4064 if(sizeof($opData['input']['parts']) > 0){
4065 foreach($opData['input']['parts'] as $name => $type){
4066 $paramStr .= "\$$name,";
4068 $paramStr = substr($paramStr,0,strlen($paramStr)-1);
4070 $opData['namespace'] = !isset($opData['namespace']) ?
'http://testuri.com' : $opData['namespace'];
4071 $evalStr .= "function $operation ($paramStr){
4072 // load params into array
4073 \$params = array($paramStr);
4074 return \$this->call('$operation',\$params,'".$opData['namespace']."','".$opData['soapAction']."');
4080 $evalStr = 'class soap_proxy_'.$r.' extends nusoap_client {
4083 //print "proxy class:<pre>$evalStr</pre>";
4086 // instantiate proxy object
4087 eval("\$proxy = new soap_proxy_$r('');");
4088 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
4089 $proxy->endpointType
= 'wsdl';
4090 $proxy->wsdlFile
= $this->wsdlFile
;
4091 $proxy->wsdl
= $this->wsdl
;
4092 $proxy->operations
= $this->operations
;
4093 $proxy->defaultRpcParams
= $this->defaultRpcParams
;