PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/registrar/_directi/nusoap.php

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