class.soap_server.php 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. <?php
  2. /**
  3. *
  4. * nusoap_server allows the user to create a SOAP server
  5. * that is capable of receiving messages and returning responses
  6. *
  7. * @author Dietrich Ayala <dietrich@ganx4.com>
  8. * @author Scott Nichol <snichol@users.sourceforge.net>
  9. * @version $Id: class.soap_server.php,v 1.63 2010/04/26 20:15:08 snichol Exp $
  10. * @access public
  11. */
  12. class nusoap_server extends nusoap_base {
  13. /**
  14. * HTTP headers of request
  15. * @var array
  16. * @access private
  17. */
  18. var $headers = array();
  19. /**
  20. * HTTP request
  21. * @var string
  22. * @access private
  23. */
  24. var $request = '';
  25. /**
  26. * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
  27. * @var string
  28. * @access public
  29. */
  30. var $requestHeaders = '';
  31. /**
  32. * SOAP Headers from request (parsed)
  33. * @var mixed
  34. * @access public
  35. */
  36. var $requestHeader = NULL;
  37. /**
  38. * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
  39. * @var string
  40. * @access public
  41. */
  42. var $document = '';
  43. /**
  44. * SOAP payload for request (text)
  45. * @var string
  46. * @access public
  47. */
  48. var $requestSOAP = '';
  49. /**
  50. * requested method namespace URI
  51. * @var string
  52. * @access private
  53. */
  54. var $methodURI = '';
  55. /**
  56. * name of method requested
  57. * @var string
  58. * @access private
  59. */
  60. var $methodname = '';
  61. /**
  62. * method parameters from request
  63. * @var array
  64. * @access private
  65. */
  66. var $methodparams = array();
  67. /**
  68. * SOAP Action from request
  69. * @var string
  70. * @access private
  71. */
  72. var $SOAPAction = '';
  73. /**
  74. * character set encoding of incoming (request) messages
  75. * @var string
  76. * @access public
  77. */
  78. var $xml_encoding = '';
  79. /**
  80. * toggles whether the parser decodes element content w/ utf8_decode()
  81. * @var boolean
  82. * @access public
  83. */
  84. var $decode_utf8 = true;
  85. /**
  86. * HTTP headers of response
  87. * @var array
  88. * @access public
  89. */
  90. var $outgoing_headers = array();
  91. /**
  92. * HTTP response
  93. * @var string
  94. * @access private
  95. */
  96. var $response = '';
  97. /**
  98. * SOAP headers for response (text or array of soapval or associative array)
  99. * @var mixed
  100. * @access public
  101. */
  102. var $responseHeaders = '';
  103. /**
  104. * SOAP payload for response (text)
  105. * @var string
  106. * @access private
  107. */
  108. var $responseSOAP = '';
  109. /**
  110. * method return value to place in response
  111. * @var mixed
  112. * @access private
  113. */
  114. var $methodreturn = false;
  115. /**
  116. * whether $methodreturn is a string of literal XML
  117. * @var boolean
  118. * @access public
  119. */
  120. var $methodreturnisliteralxml = false;
  121. /**
  122. * SOAP fault for response (or false)
  123. * @var mixed
  124. * @access private
  125. */
  126. var $fault = false;
  127. /**
  128. * text indication of result (for debugging)
  129. * @var string
  130. * @access private
  131. */
  132. var $result = 'successful';
  133. /**
  134. * assoc array of operations => opData; operations are added by the register()
  135. * method or by parsing an external WSDL definition
  136. * @var array
  137. * @access private
  138. */
  139. var $operations = array();
  140. /**
  141. * wsdl instance (if one)
  142. * @var mixed
  143. * @access private
  144. */
  145. var $wsdl = false;
  146. /**
  147. * URL for WSDL (if one)
  148. * @var mixed
  149. * @access private
  150. */
  151. var $externalWSDLURL = false;
  152. /**
  153. * whether to append debug to response as XML comment
  154. * @var boolean
  155. * @access public
  156. */
  157. var $debug_flag = false;
  158. /**
  159. * constructor
  160. * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
  161. *
  162. * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
  163. * @access public
  164. */
  165. function nusoap_server($wsdl=false){
  166. parent::nusoap_base();
  167. // turn on debugging?
  168. global $debug;
  169. global $HTTP_SERVER_VARS;
  170. if (isset($_SERVER)) {
  171. $this->debug("_SERVER is defined:");
  172. $this->appendDebug($this->varDump($_SERVER));
  173. } elseif (isset($HTTP_SERVER_VARS)) {
  174. $this->debug("HTTP_SERVER_VARS is defined:");
  175. $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
  176. } else {
  177. $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
  178. }
  179. if (isset($debug)) {
  180. $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
  181. $this->debug_flag = $debug;
  182. } elseif (isset($_SERVER['QUERY_STRING'])) {
  183. $qs = explode('&', $_SERVER['QUERY_STRING']);
  184. foreach ($qs as $v) {
  185. if (substr($v, 0, 6) == 'debug=') {
  186. $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
  187. $this->debug_flag = substr($v, 6);
  188. }
  189. }
  190. } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
  191. $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
  192. foreach ($qs as $v) {
  193. if (substr($v, 0, 6) == 'debug=') {
  194. $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
  195. $this->debug_flag = substr($v, 6);
  196. }
  197. }
  198. }
  199. // wsdl
  200. if($wsdl){
  201. $this->debug("In nusoap_server, WSDL is specified");
  202. if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
  203. $this->wsdl = $wsdl;
  204. $this->externalWSDLURL = $this->wsdl->wsdl;
  205. $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
  206. } else {
  207. $this->debug('Create wsdl from ' . $wsdl);
  208. $this->wsdl = new wsdl($wsdl);
  209. $this->externalWSDLURL = $wsdl;
  210. }
  211. $this->appendDebug($this->wsdl->getDebug());
  212. $this->wsdl->clearDebug();
  213. if($err = $this->wsdl->getError()){
  214. die('WSDL ERROR: '.$err);
  215. }
  216. }
  217. }
  218. /**
  219. * processes request and returns response
  220. *
  221. * @param string $data usually is the value of $HTTP_RAW_POST_DATA
  222. * @access public
  223. */
  224. function service($data){
  225. global $HTTP_SERVER_VARS;
  226. if (isset($_SERVER['REQUEST_METHOD'])) {
  227. $rm = $_SERVER['REQUEST_METHOD'];
  228. } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
  229. $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
  230. } else {
  231. $rm = '';
  232. }
  233. if (isset($_SERVER['QUERY_STRING'])) {
  234. $qs = $_SERVER['QUERY_STRING'];
  235. } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
  236. $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
  237. } else {
  238. $qs = '';
  239. }
  240. $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
  241. if ($rm == 'POST') {
  242. $this->debug("In service, invoke the request");
  243. $this->parse_request($data);
  244. if (! $this->fault) {
  245. $this->invoke_method();
  246. }
  247. if (! $this->fault) {
  248. $this->serialize_return();
  249. }
  250. $this->send_response();
  251. } elseif (preg_match('/wsdl/', $qs) ){
  252. $this->debug("In service, this is a request for WSDL");
  253. if ($this->externalWSDLURL){
  254. if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
  255. $this->debug("In service, re-direct for WSDL");
  256. header('Location: '.$this->externalWSDLURL);
  257. } else { // assume file
  258. $this->debug("In service, use file passthru for WSDL");
  259. header("Content-Type: text/xml\r\n");
  260. $pos = strpos($this->externalWSDLURL, "file://");
  261. if ($pos === false) {
  262. $filename = $this->externalWSDLURL;
  263. } else {
  264. $filename = substr($this->externalWSDLURL, $pos + 7);
  265. }
  266. $fp = fopen($this->externalWSDLURL, 'r');
  267. fpassthru($fp);
  268. }
  269. } elseif ($this->wsdl) {
  270. $this->debug("In service, serialize WSDL");
  271. header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
  272. print $this->wsdl->serialize($this->debug_flag);
  273. if ($this->debug_flag) {
  274. $this->debug('wsdl:');
  275. $this->appendDebug($this->varDump($this->wsdl));
  276. print $this->getDebugAsXMLComment();
  277. }
  278. } else {
  279. $this->debug("In service, there is no WSDL");
  280. header("Content-Type: text/html; charset=ISO-8859-1\r\n");
  281. print "This service does not provide WSDL";
  282. }
  283. } elseif ($this->wsdl) {
  284. $this->debug("In service, return Web description");
  285. print $this->wsdl->webDescription();
  286. } else {
  287. $this->debug("In service, no Web description");
  288. header("Content-Type: text/html; charset=ISO-8859-1\r\n");
  289. print "This service does not provide a Web description";
  290. }
  291. }
  292. /**
  293. * parses HTTP request headers.
  294. *
  295. * The following fields are set by this function (when successful)
  296. *
  297. * headers
  298. * request
  299. * xml_encoding
  300. * SOAPAction
  301. *
  302. * @access private
  303. */
  304. function parse_http_headers() {
  305. global $HTTP_SERVER_VARS;
  306. $this->request = '';
  307. $this->SOAPAction = '';
  308. if(function_exists('getallheaders')){
  309. $this->debug("In parse_http_headers, use getallheaders");
  310. $headers = getallheaders();
  311. foreach($headers as $k=>$v){
  312. $k = strtolower($k);
  313. $this->headers[$k] = $v;
  314. $this->request .= "$k: $v\r\n";
  315. $this->debug("$k: $v");
  316. }
  317. // get SOAPAction header
  318. if(isset($this->headers['soapaction'])){
  319. $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
  320. }
  321. // get the character encoding of the incoming request
  322. if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
  323. $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
  324. if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
  325. $this->xml_encoding = strtoupper($enc);
  326. } else {
  327. $this->xml_encoding = 'US-ASCII';
  328. }
  329. } else {
  330. // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
  331. $this->xml_encoding = 'ISO-8859-1';
  332. }
  333. } elseif(isset($_SERVER) && is_array($_SERVER)){
  334. $this->debug("In parse_http_headers, use _SERVER");
  335. foreach ($_SERVER as $k => $v) {
  336. if (substr($k, 0, 5) == 'HTTP_') {
  337. $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
  338. } else {
  339. $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
  340. }
  341. if ($k == 'soapaction') {
  342. // get SOAPAction header
  343. $k = 'SOAPAction';
  344. $v = str_replace('"', '', $v);
  345. $v = str_replace('\\', '', $v);
  346. $this->SOAPAction = $v;
  347. } else if ($k == 'content-type') {
  348. // get the character encoding of the incoming request
  349. if (strpos($v, '=')) {
  350. $enc = substr(strstr($v, '='), 1);
  351. $enc = str_replace('"', '', $enc);
  352. $enc = str_replace('\\', '', $enc);
  353. if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
  354. $this->xml_encoding = strtoupper($enc);
  355. } else {
  356. $this->xml_encoding = 'US-ASCII';
  357. }
  358. } else {
  359. // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
  360. $this->xml_encoding = 'ISO-8859-1';
  361. }
  362. }
  363. $this->headers[$k] = $v;
  364. $this->request .= "$k: $v\r\n";
  365. $this->debug("$k: $v");
  366. }
  367. } elseif (is_array($HTTP_SERVER_VARS)) {
  368. $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
  369. foreach ($HTTP_SERVER_VARS as $k => $v) {
  370. if (substr($k, 0, 5) == 'HTTP_') {
  371. $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5));
  372. } else {
  373. $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k);
  374. }
  375. if ($k == 'soapaction') {
  376. // get SOAPAction header
  377. $k = 'SOAPAction';
  378. $v = str_replace('"', '', $v);
  379. $v = str_replace('\\', '', $v);
  380. $this->SOAPAction = $v;
  381. } else if ($k == 'content-type') {
  382. // get the character encoding of the incoming request
  383. if (strpos($v, '=')) {
  384. $enc = substr(strstr($v, '='), 1);
  385. $enc = str_replace('"', '', $enc);
  386. $enc = str_replace('\\', '', $enc);
  387. if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
  388. $this->xml_encoding = strtoupper($enc);
  389. } else {
  390. $this->xml_encoding = 'US-ASCII';
  391. }
  392. } else {
  393. // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
  394. $this->xml_encoding = 'ISO-8859-1';
  395. }
  396. }
  397. $this->headers[$k] = $v;
  398. $this->request .= "$k: $v\r\n";
  399. $this->debug("$k: $v");
  400. }
  401. } else {
  402. $this->debug("In parse_http_headers, HTTP headers not accessible");
  403. $this->setError("HTTP headers not accessible");
  404. }
  405. }
  406. /**
  407. * parses a request
  408. *
  409. * The following fields are set by this function (when successful)
  410. *
  411. * headers
  412. * request
  413. * xml_encoding
  414. * SOAPAction
  415. * request
  416. * requestSOAP
  417. * methodURI
  418. * methodname
  419. * methodparams
  420. * requestHeaders
  421. * document
  422. *
  423. * This sets the fault field on error
  424. *
  425. * @param string $data XML string
  426. * @access private
  427. */
  428. function parse_request($data='') {
  429. $this->debug('entering parse_request()');
  430. $this->parse_http_headers();
  431. $this->debug('got character encoding: '.$this->xml_encoding);
  432. // uncompress if necessary
  433. if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
  434. $this->debug('got content encoding: ' . $this->headers['content-encoding']);
  435. if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
  436. // if decoding works, use it. else assume data wasn't gzencoded
  437. if (function_exists('gzuncompress')) {
  438. if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
  439. $data = $degzdata;
  440. } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
  441. $data = $degzdata;
  442. } else {
  443. $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
  444. return;
  445. }
  446. } else {
  447. $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
  448. return;
  449. }
  450. }
  451. }
  452. $this->request .= "\r\n".$data;
  453. $data = $this->parseRequest($this->headers, $data);
  454. $this->requestSOAP = $data;
  455. $this->debug('leaving parse_request');
  456. }
  457. /**
  458. * invokes a PHP function for the requested SOAP method
  459. *
  460. * The following fields are set by this function (when successful)
  461. *
  462. * methodreturn
  463. *
  464. * Note that the PHP function that is called may also set the following
  465. * fields to affect the response sent to the client
  466. *
  467. * responseHeaders
  468. * outgoing_headers
  469. *
  470. * This sets the fault field on error
  471. *
  472. * @access private
  473. */
  474. function invoke_method() {
  475. $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
  476. //
  477. // if you are debugging in this area of the code, your service uses a class to implement methods,
  478. // you use SOAP RPC, and the client is .NET, please be aware of the following...
  479. // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
  480. // method name. that is fine for naming the .NET methods. it is not fine for properly constructing
  481. // the XML request and reading the XML response. you need to add the RequestElementName and
  482. // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
  483. // generates for the method. these parameters are used to specify the correct XML element names
  484. // for .NET to use, i.e. the names with the '.' in them.
  485. //
  486. $orig_methodname = $this->methodname;
  487. if ($this->wsdl) {
  488. if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
  489. $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
  490. $this->appendDebug('opData=' . $this->varDump($this->opData));
  491. } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
  492. // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
  493. $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
  494. $this->appendDebug('opData=' . $this->varDump($this->opData));
  495. $this->methodname = $this->opData['name'];
  496. } else {
  497. $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
  498. $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
  499. return;
  500. }
  501. } else {
  502. $this->debug('in invoke_method, no WSDL to validate method');
  503. }
  504. // if a . is present in $this->methodname, we see if there is a class in scope,
  505. // which could be referred to. We will also distinguish between two deliminators,
  506. // to allow methods to be called a the class or an instance
  507. if (strpos($this->methodname, '..') > 0) {
  508. $delim = '..';
  509. } else if (strpos($this->methodname, '.') > 0) {
  510. $delim = '.';
  511. } else {
  512. $delim = '';
  513. }
  514. $this->debug("in invoke_method, delim=$delim");
  515. $class = '';
  516. $method = '';
  517. if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
  518. $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
  519. if (class_exists($try_class)) {
  520. // get the class and method name
  521. $class = $try_class;
  522. $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
  523. $this->debug("in invoke_method, class=$class method=$method delim=$delim");
  524. } else {
  525. $this->debug("in invoke_method, class=$try_class not found");
  526. }
  527. } else {
  528. $try_class = '';
  529. $this->debug("in invoke_method, no class to try");
  530. }
  531. // does method exist?
  532. if ($class == '') {
  533. if (!function_exists($this->methodname)) {
  534. $this->debug("in invoke_method, function '$this->methodname' not found!");
  535. $this->result = 'fault: method not found';
  536. $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
  537. return;
  538. }
  539. } else {
  540. $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
  541. if (!in_array($method_to_compare, get_class_methods($class))) {
  542. $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
  543. $this->result = 'fault: method not found';
  544. $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
  545. return;
  546. }
  547. }
  548. // evaluate message, getting back parameters
  549. // verify that request parameters match the method's signature
  550. if(! $this->verify_method($this->methodname,$this->methodparams)){
  551. // debug
  552. $this->debug('ERROR: request not verified against method signature');
  553. $this->result = 'fault: request failed validation against method signature';
  554. // return fault
  555. $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
  556. return;
  557. }
  558. // if there are parameters to pass
  559. $this->debug('in invoke_method, params:');
  560. $this->appendDebug($this->varDump($this->methodparams));
  561. $this->debug("in invoke_method, calling '$this->methodname'");
  562. if (!function_exists('call_user_func_array')) {
  563. if ($class == '') {
  564. $this->debug('in invoke_method, calling function using eval()');
  565. $funcCall = "\$this->methodreturn = $this->methodname(";
  566. } else {
  567. if ($delim == '..') {
  568. $this->debug('in invoke_method, calling class method using eval()');
  569. $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
  570. } else {
  571. $this->debug('in invoke_method, calling instance method using eval()');
  572. // generate unique instance name
  573. $instname = "\$inst_".time();
  574. $funcCall = $instname." = new ".$class."(); ";
  575. $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
  576. }
  577. }
  578. if ($this->methodparams) {
  579. foreach ($this->methodparams as $param) {
  580. if (is_array($param) || is_object($param)) {
  581. $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
  582. return;
  583. }
  584. $funcCall .= "\"$param\",";
  585. }
  586. $funcCall = substr($funcCall, 0, -1);
  587. }
  588. $funcCall .= ');';
  589. $this->debug('in invoke_method, function call: '.$funcCall);
  590. @eval($funcCall);
  591. } else {
  592. if ($class == '') {
  593. $this->debug('in invoke_method, calling function using call_user_func_array()');
  594. $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
  595. } elseif ($delim == '..') {
  596. $this->debug('in invoke_method, calling class method using call_user_func_array()');
  597. $call_arg = array ($class, $method);
  598. } else {
  599. $this->debug('in invoke_method, calling instance method using call_user_func_array()');
  600. $instance = new $class ();
  601. $call_arg = array(&$instance, $method);
  602. }
  603. if (is_array($this->methodparams)) {
  604. $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
  605. } else {
  606. $this->methodreturn = call_user_func_array($call_arg, array());
  607. }
  608. }
  609. $this->debug('in invoke_method, methodreturn:');
  610. $this->appendDebug($this->varDump($this->methodreturn));
  611. $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
  612. }
  613. /**
  614. * serializes the return value from a PHP function into a full SOAP Envelope
  615. *
  616. * The following fields are set by this function (when successful)
  617. *
  618. * responseSOAP
  619. *
  620. * This sets the fault field on error
  621. *
  622. * @access private
  623. */
  624. function serialize_return() {
  625. $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
  626. // if fault
  627. if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
  628. $this->debug('got a fault object from method');
  629. $this->fault = $this->methodreturn;
  630. return;
  631. } elseif ($this->methodreturnisliteralxml) {
  632. $return_val = $this->methodreturn;
  633. // returned value(s)
  634. } else {
  635. $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
  636. $this->debug('serializing return value');
  637. if($this->wsdl){
  638. $opParams = "";
  639. if (sizeof($this->opData['output']['parts']) > 1) {
  640. $this->debug('more than one output part, so use the method return unchanged');
  641. $opParams = $this->methodreturn;
  642. } elseif (sizeof($this->opData['output']['parts']) == 1) {
  643. $this->debug('exactly one output part, so wrap the method return in a simple array');
  644. // TODO: verify that it is not already wrapped!
  645. //foreach ($this->opData['output']['parts'] as $name => $type) {
  646. // $this->debug('wrap in element named ' . $name);
  647. //}
  648. $opParams = array($this->methodreturn);
  649. }
  650. $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
  651. $this->appendDebug($this->wsdl->getDebug());
  652. $this->wsdl->clearDebug();
  653. if($errstr = $this->wsdl->getError()){
  654. $this->debug('got wsdl error: '.$errstr);
  655. $this->fault('SOAP-ENV:Server', 'unable to serialize result');
  656. return;
  657. }
  658. } else {
  659. if (isset($this->methodreturn)) {
  660. $return_val = $this->serialize_val($this->methodreturn, 'return');
  661. } else {
  662. $return_val = '';
  663. $this->debug('in absence of WSDL, assume void return for backward compatibility');
  664. }
  665. }
  666. }
  667. $this->debug('return value:');
  668. $this->appendDebug($this->varDump($return_val));
  669. $this->debug('serializing response');
  670. if ($this->wsdl) {
  671. $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
  672. if ($this->opData['style'] == 'rpc') {
  673. $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
  674. if ($this->opData['output']['use'] == 'literal') {
  675. // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
  676. if ($this->methodURI) {
  677. $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
  678. } else {
  679. $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
  680. }
  681. } else {
  682. if ($this->methodURI) {
  683. $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
  684. } else {
  685. $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
  686. }
  687. }
  688. } else {
  689. $this->debug('style is not rpc for serialization: assume document');
  690. $payload = $return_val;
  691. }
  692. } else {
  693. $this->debug('do not have WSDL for serialization: assume rpc/encoded');
  694. $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
  695. }
  696. $this->result = 'successful';
  697. if($this->wsdl){
  698. //if($this->debug_flag){
  699. $this->appendDebug($this->wsdl->getDebug());
  700. // }
  701. if (isset($this->opData['output']['encodingStyle'])) {
  702. $encodingStyle = $this->opData['output']['encodingStyle'];
  703. } else {
  704. $encodingStyle = '';
  705. }
  706. // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
  707. $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
  708. } else {
  709. $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
  710. }
  711. $this->debug("Leaving serialize_return");
  712. }
  713. /**
  714. * sends an HTTP response
  715. *
  716. * The following fields are set by this function (when successful)
  717. *
  718. * outgoing_headers
  719. * response
  720. *
  721. * @access private
  722. */
  723. function send_response() {
  724. $this->debug('Enter send_response');
  725. if ($this->fault) {
  726. $payload = $this->fault->serialize();
  727. $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
  728. $this->outgoing_headers[] = "Status: 500 Internal Server Error";
  729. } else {
  730. $payload = $this->responseSOAP;
  731. // Some combinations of PHP+Web server allow the Status
  732. // to come through as a header. Since OK is the default
  733. // just do nothing.
  734. // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
  735. // $this->outgoing_headers[] = "Status: 200 OK";
  736. }
  737. // add debug data if in debug mode
  738. if(isset($this->debug_flag) && $this->debug_flag){
  739. $payload .= $this->getDebugAsXMLComment();
  740. }
  741. $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
  742. preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
  743. $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
  744. // Let the Web server decide about this
  745. //$this->outgoing_headers[] = "Connection: Close\r\n";
  746. $payload = $this->getHTTPBody($payload);
  747. $type = $this->getHTTPContentType();
  748. $charset = $this->getHTTPContentTypeCharset();
  749. $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
  750. //begin code to compress payload - by John
  751. // NOTE: there is no way to know whether the Web server will also compress
  752. // this data.
  753. if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
  754. if (strstr($this->headers['accept-encoding'], 'gzip')) {
  755. if (function_exists('gzencode')) {
  756. if (isset($this->debug_flag) && $this->debug_flag) {
  757. $payload .= "<!-- Content being gzipped -->";
  758. }
  759. $this->outgoing_headers[] = "Content-Encoding: gzip";
  760. $payload = gzencode($payload);
  761. } else {
  762. if (isset($this->debug_flag) && $this->debug_flag) {
  763. $payload .= "<!-- Content will not be gzipped: no gzencode -->";
  764. }
  765. }
  766. } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
  767. // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
  768. // instead of gzcompress output,
  769. // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
  770. if (function_exists('gzdeflate')) {
  771. if (isset($this->debug_flag) && $this->debug_flag) {
  772. $payload .= "<!-- Content being deflated -->";
  773. }
  774. $this->outgoing_headers[] = "Content-Encoding: deflate";
  775. $payload = gzdeflate($payload);
  776. } else {
  777. if (isset($this->debug_flag) && $this->debug_flag) {
  778. $payload .= "<!-- Content will not be deflated: no gzcompress -->";
  779. }
  780. }
  781. }
  782. }
  783. //end code
  784. $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
  785. reset($this->outgoing_headers);
  786. foreach($this->outgoing_headers as $hdr){
  787. header($hdr, false);
  788. }
  789. print $payload;
  790. $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
  791. }
  792. /**
  793. * takes the value that was created by parsing the request
  794. * and compares to the method's signature, if available.
  795. *
  796. * @param string $operation The operation to be invoked
  797. * @param array $request The array of parameter values
  798. * @return boolean Whether the operation was found
  799. * @access private
  800. */
  801. function verify_method($operation,$request){
  802. if(isset($this->wsdl) && is_object($this->wsdl)){
  803. if($this->wsdl->getOperationData($operation)){
  804. return true;
  805. }
  806. } elseif(isset($this->operations[$operation])){
  807. return true;
  808. }
  809. return false;
  810. }
  811. /**
  812. * processes SOAP message received from client
  813. *
  814. * @param array $headers The HTTP headers
  815. * @param string $data unprocessed request data from client
  816. * @return mixed value of the message, decoded into a PHP type
  817. * @access private
  818. */
  819. function parseRequest($headers, $data) {
  820. $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
  821. $this->appendDebug($this->varDump($headers));
  822. if (!isset($headers['content-type'])) {
  823. $this->setError('Request not of type text/xml (no content-type header)');
  824. return false;
  825. }
  826. if (!strstr($headers['content-type'], 'text/xml')) {
  827. $this->setError('Request not of type text/xml');
  828. return false;
  829. }
  830. if (strpos($headers['content-type'], '=')) {
  831. $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
  832. $this->debug('Got response encoding: ' . $enc);
  833. if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
  834. $this->xml_encoding = strtoupper($enc);
  835. } else {
  836. $this->xml_encoding = 'US-ASCII';
  837. }
  838. } else {
  839. // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
  840. $this->xml_encoding = 'ISO-8859-1';
  841. }
  842. $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
  843. // parse response, get soap parser obj
  844. $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
  845. // parser debug
  846. $this->debug("parser debug: \n".$parser->getDebug());
  847. // if fault occurred during message parsing
  848. if($err = $parser->getError()){
  849. $this->result = 'fault: error in msg parsing: '.$err;
  850. $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
  851. // else successfully parsed request into soapval object
  852. } else {
  853. // get/set methodname
  854. $this->methodURI = $parser->root_struct_namespace;
  855. $this->methodname = $parser->root_struct_name;
  856. $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
  857. $this->debug('calling parser->get_soapbody()');
  858. $this->methodparams = $parser->get_soapbody();
  859. // get SOAP headers
  860. $this->requestHeaders = $parser->getHeaders();
  861. // get SOAP Header
  862. $this->requestHeader = $parser->get_soapheader();
  863. // add document for doclit support
  864. $this->document = $parser->document;
  865. }
  866. }
  867. /**
  868. * gets the HTTP body for the current response.
  869. *
  870. * @param string $soapmsg The SOAP payload
  871. * @return string The HTTP body, which includes the SOAP payload
  872. * @access private
  873. */
  874. function getHTTPBody($soapmsg) {
  875. return $soapmsg;
  876. }
  877. /**
  878. * gets the HTTP content type for the current response.
  879. *
  880. * Note: getHTTPBody must be called before this.
  881. *
  882. * @return string the HTTP content type for the current response.
  883. * @access private
  884. */
  885. function getHTTPContentType() {
  886. return 'text/xml';
  887. }
  888. /**
  889. * gets the HTTP content type charset for the current response.
  890. * returns false for non-text content types.
  891. *
  892. * Note: getHTTPBody must be called before this.
  893. *
  894. * @return string the HTTP content type charset for the current response.
  895. * @access private
  896. */
  897. function getHTTPContentTypeCharset() {
  898. return $this->soap_defencoding;
  899. }
  900. /**
  901. * add a method to the dispatch map (this has been replaced by the register method)
  902. *
  903. * @param string $methodname
  904. * @param string $in array of input values
  905. * @param string $out array of output values
  906. * @access public
  907. * @deprecated
  908. */
  909. function add_to_map($methodname,$in,$out){
  910. $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
  911. }
  912. /**
  913. * register a service function with the server
  914. *
  915. * @param string $name the name of the PHP function, class.method or class..method
  916. * @param array $in assoc array of input values: key = param name, value = param type
  917. * @param array $out assoc array of output values: key = param name, value = param type
  918. * @param mixed $namespace the element namespace for the method or false
  919. * @param mixed $soapaction the soapaction for the method or false
  920. * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
  921. * @param mixed $use optional (encoded|literal) or false
  922. * @param string $documentation optional Description to include in WSDL
  923. * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
  924. * @access public
  925. */
  926. function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
  927. global $HTTP_SERVER_VARS;
  928. if($this->externalWSDLURL){
  929. die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
  930. }
  931. if (! $name) {
  932. die('You must specify a name when you register an operation');
  933. }
  934. if (!is_array($in)) {
  935. die('You must provide an array for operation inputs');
  936. }
  937. if (!is_array($out)) {
  938. die('You must provide an array for operation outputs');
  939. }
  940. if(false == $namespace) {
  941. }
  942. if(false == $soapaction) {
  943. if (isset($_SERVER)) {
  944. $SERVER_NAME = $_SERVER['SERVER_NAME'];
  945. $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
  946. $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
  947. } elseif (isset($HTTP_SERVER_VARS)) {
  948. $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
  949. $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
  950. $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
  951. } else {
  952. $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
  953. }
  954. if ($HTTPS == '1' || $HTTPS == 'on') {
  955. $SCHEME = 'https';
  956. } else {
  957. $SCHEME = 'http';
  958. }
  959. $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
  960. }
  961. if(false == $style) {
  962. $style = "rpc";
  963. }
  964. if(false == $use) {
  965. $use = "encoded";
  966. }
  967. if ($use == 'encoded' && $encodingStyle == '') {
  968. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
  969. }
  970. $this->operations[$name] = array(
  971. 'name' => $name,
  972. 'in' => $in,
  973. 'out' => $out,
  974. 'namespace' => $namespace,
  975. 'soapaction' => $soapaction,
  976. 'style' => $style);
  977. if($this->wsdl){
  978. $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
  979. }
  980. return true;
  981. }
  982. /**
  983. * Specify a fault to be returned to the client.
  984. * This also acts as a flag to the server that a fault has occured.
  985. *
  986. * @param string $faultcode
  987. * @param string $faultstring
  988. * @param string $faultactor
  989. * @param string $faultdetail
  990. * @access public
  991. */
  992. function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
  993. if ($faultdetail == '' && $this->debug_flag) {
  994. $faultdetail = $this->getDebug();
  995. }
  996. $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
  997. $this->fault->soap_defencoding = $this->soap_defencoding;
  998. }
  999. /**
  1000. * Sets up wsdl object.
  1001. * Acts as a flag to enable internal WSDL generation
  1002. *
  1003. * @param string $serviceName, name of the service
  1004. * @param mixed $namespace optional 'tns' service namespace or false
  1005. * @param mixed $endpoint optional URL of service endpoint or false
  1006. * @param string $style optional (rpc|document) WSDL style (also specified by operation)
  1007. * @param string $transport optional SOAP transport
  1008. * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
  1009. */
  1010. function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
  1011. {
  1012. global $HTTP_SERVER_VARS;
  1013. if (isset($_SERVER)) {
  1014. $SERVER_NAME = $_SERVER['SERVER_NAME'];
  1015. $SERVER_PORT = $_SERVER['SERVER_PORT'];
  1016. $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
  1017. $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
  1018. } elseif (isset($HTTP_SERVER_VARS)) {
  1019. $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
  1020. $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
  1021. $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
  1022. $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
  1023. } else {
  1024. $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
  1025. }
  1026. // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
  1027. $colon = strpos($SERVER_NAME,":");
  1028. if ($colon) {
  1029. $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
  1030. }
  1031. if ($SERVER_PORT == 80) {
  1032. $SERVER_PORT = '';
  1033. } else {
  1034. $SERVER_PORT = ':' . $SERVER_PORT;
  1035. }
  1036. if(false == $namespace) {
  1037. $namespace = "http://$SERVER_NAME/soap/$serviceName";
  1038. }
  1039. if(false == $endpoint) {
  1040. if ($HTTPS == '1' || $HTTPS == 'on') {
  1041. $SCHEME = 'https';
  1042. } else {
  1043. $SCHEME = 'http';
  1044. }
  1045. $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
  1046. }
  1047. if(false == $schemaTargetNamespace) {
  1048. $schemaTargetNamespace = $namespace;
  1049. }
  1050. $this->wsdl = new wsdl;
  1051. $this->wsdl->serviceName = $serviceName;
  1052. $this->wsdl->endpoint = $endpoint;
  1053. $this->wsdl->namespaces['tns'] = $namespace;
  1054. $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
  1055. $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
  1056. if ($schemaTargetNamespace != $namespace) {
  1057. $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
  1058. }
  1059. $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
  1060. if ($style == 'document') {
  1061. $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
  1062. }
  1063. $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
  1064. $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
  1065. $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
  1066. $this->wsdl->bindings[$serviceName.'Binding'] = array(
  1067. 'name'=>$serviceName.'Binding',
  1068. 'style'=>$style,
  1069. 'transport'=>$transport,
  1070. 'portType'=>$serviceName.'PortType');
  1071. $this->wsdl->ports[$serviceName.'Port'] = array(
  1072. 'binding'=>$serviceName.'Binding',
  1073. 'location'=>$endpoint,
  1074. 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
  1075. }
  1076. }
  1077. /**
  1078. * Backward compatibility
  1079. */
  1080. class soap_server extends nusoap_server {
  1081. }