class.soapclient.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. <?php
  2. /**
  3. *
  4. * [nu]soapclient higher level class for easy usage.
  5. *
  6. * usage:
  7. *
  8. * // instantiate client with server info
  9. * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
  10. *
  11. * // call method, get results
  12. * echo $soapclient->call( string methodname [ ,array parameters] );
  13. *
  14. * // bye bye client
  15. * unset($soapclient);
  16. *
  17. * @author Dietrich Ayala <dietrich@ganx4.com>
  18. * @author Scott Nichol <snichol@users.sourceforge.net>
  19. * @access public
  20. */
  21. class nusoap_client extends nusoap_base {
  22. var $username = ''; // Username for HTTP authentication
  23. var $password = ''; // Password for HTTP authentication
  24. var $authtype = ''; // Type of HTTP authentication
  25. var $certRequest = array(); // Certificate for HTTP SSL authentication
  26. var $requestHeaders = false; // SOAP headers in request (text)
  27. var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
  28. var $responseHeader = NULL; // SOAP Header from response (parsed)
  29. var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
  30. var $endpoint;
  31. var $forceEndpoint = ''; // overrides WSDL endpoint
  32. var $proxyhost = '';
  33. var $proxyport = '';
  34. var $proxyusername = '';
  35. var $proxypassword = '';
  36. var $portName = ''; // port name to use in WSDL
  37. var $xml_encoding = ''; // character set encoding of incoming (response) messages
  38. var $http_encoding = false;
  39. var $timeout = 0; // HTTP connection timeout
  40. var $response_timeout = 30; // HTTP response timeout
  41. var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
  42. var $persistentConnection = false;
  43. var $defaultRpcParams = false; // This is no longer used
  44. var $request = ''; // HTTP request
  45. var $response = ''; // HTTP response
  46. var $responseData = ''; // SOAP payload of response
  47. var $cookies = array(); // Cookies from response or for request
  48. var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
  49. var $operations = array(); // WSDL operations, empty for WSDL initialization error
  50. var $curl_options = array(); // User-specified cURL options
  51. var $bindingType = ''; // WSDL operation binding type
  52. var $use_curl = false; // whether to always try to use cURL
  53. /*
  54. * fault related variables
  55. */
  56. /**
  57. * @var fault
  58. * @access public
  59. */
  60. var $fault;
  61. /**
  62. * @var faultcode
  63. * @access public
  64. */
  65. var $faultcode;
  66. /**
  67. * @var faultstring
  68. * @access public
  69. */
  70. var $faultstring;
  71. /**
  72. * @var faultdetail
  73. * @access public
  74. */
  75. var $faultdetail;
  76. /**
  77. * constructor
  78. *
  79. * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
  80. * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL
  81. * @param string $proxyhost optional
  82. * @param string $proxyport optional
  83. * @param string $proxyusername optional
  84. * @param string $proxypassword optional
  85. * @param integer $timeout set the connection timeout
  86. * @param integer $response_timeout set the response timeout
  87. * @param string $portName optional portName in WSDL document
  88. * @access public
  89. */
  90. function __construct($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){
  91. parent::__construct();
  92. $this->endpoint = $endpoint;
  93. $this->proxyhost = $proxyhost;
  94. $this->proxyport = $proxyport;
  95. $this->proxyusername = $proxyusername;
  96. $this->proxypassword = $proxypassword;
  97. $this->timeout = $timeout;
  98. $this->response_timeout = $response_timeout;
  99. $this->portName = $portName;
  100. $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
  101. $this->appendDebug('endpoint=' . $this->varDump($endpoint));
  102. // make values
  103. if($wsdl){
  104. if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
  105. $this->wsdl = $endpoint;
  106. $this->endpoint = $this->wsdl->wsdl;
  107. $this->wsdlFile = $this->endpoint;
  108. $this->debug('existing wsdl instance created from ' . $this->endpoint);
  109. $this->checkWSDL();
  110. } else {
  111. $this->wsdlFile = $this->endpoint;
  112. $this->wsdl = null;
  113. $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
  114. }
  115. $this->endpointType = 'wsdl';
  116. } else {
  117. $this->debug("instantiate SOAP with endpoint at $endpoint");
  118. $this->endpointType = 'soap';
  119. }
  120. }
  121. /**
  122. * calls method, returns PHP native type
  123. *
  124. * @param string $operation SOAP server URL or path
  125. * @param mixed $params An array, associative or simple, of the parameters
  126. * for the method call, or a string that is the XML
  127. * for the call. For rpc style, this call will
  128. * wrap the XML in a tag named after the method, as
  129. * well as the SOAP Envelope and Body. For document
  130. * style, this will only wrap with the Envelope and Body.
  131. * IMPORTANT: when using an array with document style,
  132. * in which case there
  133. * is really one parameter, the root of the fragment
  134. * used in the call, which encloses what programmers
  135. * normally think of parameters. A parameter array
  136. * *must* include the wrapper.
  137. * @param string $namespace optional method namespace (WSDL can override)
  138. * @param string $soapAction optional SOAPAction value (WSDL can override)
  139. * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
  140. * @param boolean $rpcParams optional (no longer used)
  141. * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
  142. * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
  143. * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
  144. * @access public
  145. */
  146. function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
  147. $this->operation = $operation;
  148. $this->fault = false;
  149. $this->setError('');
  150. $this->request = '';
  151. $this->response = '';
  152. $this->responseData = '';
  153. $this->faultstring = '';
  154. $this->faultcode = '';
  155. $this->opData = array();
  156. $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
  157. $this->appendDebug('params=' . $this->varDump($params));
  158. $this->appendDebug('headers=' . $this->varDump($headers));
  159. if ($headers) {
  160. $this->requestHeaders = $headers;
  161. }
  162. if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
  163. $this->loadWSDL();
  164. if ($this->getError())
  165. return false;
  166. }
  167. // serialize parameters
  168. if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
  169. // use WSDL for operation
  170. $this->opData = $opData;
  171. $this->debug("found operation");
  172. $this->appendDebug('opData=' . $this->varDump($opData));
  173. if (isset($opData['soapAction'])) {
  174. $soapAction = $opData['soapAction'];
  175. }
  176. if (! $this->forceEndpoint) {
  177. $this->endpoint = $opData['endpoint'];
  178. } else {
  179. $this->endpoint = $this->forceEndpoint;
  180. }
  181. $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
  182. $style = $opData['style'];
  183. $use = $opData['input']['use'];
  184. // add ns to ns array
  185. if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
  186. $nsPrefix = 'ns' . rand(1000, 9999);
  187. $this->wsdl->namespaces[$nsPrefix] = $namespace;
  188. }
  189. $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
  190. // serialize payload
  191. if (is_string($params)) {
  192. $this->debug("serializing param string for WSDL operation $operation");
  193. $payload = $params;
  194. } elseif (is_array($params)) {
  195. $this->debug("serializing param array for WSDL operation $operation");
  196. $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
  197. } else {
  198. $this->debug('params must be array or string');
  199. $this->setError('params must be array or string');
  200. return false;
  201. }
  202. $usedNamespaces = $this->wsdl->usedNamespaces;
  203. if (isset($opData['input']['encodingStyle'])) {
  204. $encodingStyle = $opData['input']['encodingStyle'];
  205. } else {
  206. $encodingStyle = '';
  207. }
  208. $this->appendDebug($this->wsdl->getDebug());
  209. $this->wsdl->clearDebug();
  210. if ($errstr = $this->wsdl->getError()) {
  211. $this->debug('got wsdl error: '.$errstr);
  212. $this->setError('wsdl error: '.$errstr);
  213. return false;
  214. }
  215. } elseif($this->endpointType == 'wsdl') {
  216. // operation not in WSDL
  217. $this->appendDebug($this->wsdl->getDebug());
  218. $this->wsdl->clearDebug();
  219. $this->setError('operation '.$operation.' not present in WSDL.');
  220. $this->debug("operation '$operation' not present in WSDL.");
  221. return false;
  222. } else {
  223. // no WSDL
  224. //$this->namespaces['ns1'] = $namespace;
  225. $nsPrefix = 'ns' . rand(1000, 9999);
  226. // serialize
  227. $payload = '';
  228. if (is_string($params)) {
  229. $this->debug("serializing param string for operation $operation");
  230. $payload = $params;
  231. } elseif (is_array($params)) {
  232. $this->debug("serializing param array for operation $operation");
  233. foreach($params as $k => $v){
  234. $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
  235. }
  236. } else {
  237. $this->debug('params must be array or string');
  238. $this->setError('params must be array or string');
  239. return false;
  240. }
  241. $usedNamespaces = array();
  242. if ($use == 'encoded') {
  243. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
  244. } else {
  245. $encodingStyle = '';
  246. }
  247. }
  248. // wrap RPC calls with method element
  249. if ($style == 'rpc') {
  250. if ($use == 'literal') {
  251. $this->debug("wrapping RPC request with literal method element");
  252. if ($namespace) {
  253. // 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
  254. $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
  255. $payload .
  256. "</$nsPrefix:$operation>";
  257. } else {
  258. $payload = "<$operation>" . $payload . "</$operation>";
  259. }
  260. } else {
  261. $this->debug("wrapping RPC request with encoded method element");
  262. if ($namespace) {
  263. $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
  264. $payload .
  265. "</$nsPrefix:$operation>";
  266. } else {
  267. $payload = "<$operation>" .
  268. $payload .
  269. "</$operation>";
  270. }
  271. }
  272. }
  273. // serialize envelope
  274. $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
  275. $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
  276. $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
  277. // send
  278. $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
  279. if($errstr = $this->getError()){
  280. $this->debug('Error: '.$errstr);
  281. return false;
  282. } else {
  283. $this->return = $return;
  284. $this->debug('sent message successfully and got a(n) '.gettype($return));
  285. $this->appendDebug('return=' . $this->varDump($return));
  286. // fault?
  287. if(is_array($return) && isset($return['faultcode'])){
  288. $this->debug('got fault');
  289. $this->setError($return['faultcode'].': '.$return['faultstring']);
  290. $this->fault = true;
  291. foreach($return as $k => $v){
  292. $this->$k = $v;
  293. $this->debug("$k = $v<br>");
  294. }
  295. return $return;
  296. } elseif ($style == 'document') {
  297. // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
  298. // we are only going to return the first part here...sorry about that
  299. return $return;
  300. } else {
  301. // array of return values
  302. if(is_array($return)){
  303. // multiple 'out' parameters, which we return wrapped up
  304. // in the array
  305. if(sizeof($return) > 1){
  306. return $return;
  307. }
  308. // single 'out' parameter (normally the return value)
  309. $return = array_shift($return);
  310. $this->debug('return shifted value: ');
  311. $this->appendDebug($this->varDump($return));
  312. return $return;
  313. // nothing returned (ie, echoVoid)
  314. } else {
  315. return "";
  316. }
  317. }
  318. }
  319. }
  320. /**
  321. * check WSDL passed as an instance or pulled from an endpoint
  322. *
  323. * @access private
  324. */
  325. function checkWSDL() {
  326. $this->appendDebug($this->wsdl->getDebug());
  327. $this->wsdl->clearDebug();
  328. $this->debug('checkWSDL');
  329. // catch errors
  330. if ($errstr = $this->wsdl->getError()) {
  331. $this->appendDebug($this->wsdl->getDebug());
  332. $this->wsdl->clearDebug();
  333. $this->debug('got wsdl error: '.$errstr);
  334. $this->setError('wsdl error: '.$errstr);
  335. } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
  336. $this->appendDebug($this->wsdl->getDebug());
  337. $this->wsdl->clearDebug();
  338. $this->bindingType = 'soap';
  339. $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
  340. } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
  341. $this->appendDebug($this->wsdl->getDebug());
  342. $this->wsdl->clearDebug();
  343. $this->bindingType = 'soap12';
  344. $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
  345. $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
  346. } else {
  347. $this->appendDebug($this->wsdl->getDebug());
  348. $this->wsdl->clearDebug();
  349. $this->debug('getOperations returned false');
  350. $this->setError('no operations defined in the WSDL document!');
  351. }
  352. }
  353. /**
  354. * instantiate wsdl object and parse wsdl file
  355. *
  356. * @access public
  357. */
  358. function loadWSDL() {
  359. $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
  360. $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
  361. $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
  362. $this->wsdl->fetchWSDL($this->wsdlFile);
  363. $this->checkWSDL();
  364. }
  365. /**
  366. * get available data pertaining to an operation
  367. *
  368. * @param string $operation operation name
  369. * @return array array of data pertaining to the operation
  370. * @access public
  371. */
  372. function getOperationData($operation){
  373. if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
  374. $this->loadWSDL();
  375. if ($this->getError())
  376. return false;
  377. }
  378. if(isset($this->operations[$operation])){
  379. return $this->operations[$operation];
  380. }
  381. $this->debug("No data for operation: $operation");
  382. }
  383. /**
  384. * send the SOAP message
  385. *
  386. * Note: if the operation has multiple return values
  387. * the return value of this method will be an array
  388. * of those values.
  389. *
  390. * @param string $msg a SOAPx4 soapmsg object
  391. * @param string $soapaction SOAPAction value
  392. * @param integer $timeout set connection timeout in seconds
  393. * @param integer $response_timeout set response timeout in seconds
  394. * @return mixed native PHP types.
  395. * @access private
  396. */
  397. function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
  398. $this->checkCookies();
  399. // detect transport
  400. switch(true){
  401. // http(s)
  402. case preg_match('/^http/',$this->endpoint):
  403. $this->debug('transporting via HTTP');
  404. if($this->persistentConnection == true && is_object($this->persistentConnection)){
  405. $http =& $this->persistentConnection;
  406. } else {
  407. $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
  408. if ($this->persistentConnection) {
  409. $http->usePersistentConnection();
  410. }
  411. }
  412. $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
  413. $http->setSOAPAction($soapaction);
  414. if($this->proxyhost && $this->proxyport){
  415. $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
  416. }
  417. if($this->authtype != '') {
  418. $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
  419. }
  420. if($this->http_encoding != ''){
  421. $http->setEncoding($this->http_encoding);
  422. }
  423. $this->debug('sending message, length='.strlen($msg));
  424. if(preg_match('/^http:/',$this->endpoint)){
  425. //if(strpos($this->endpoint,'http:')){
  426. $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
  427. } elseif(preg_match('/^https/',$this->endpoint)){
  428. //} elseif(strpos($this->endpoint,'https:')){
  429. //if(phpversion() == '4.3.0-dev'){
  430. //$response = $http->send($msg,$timeout,$response_timeout);
  431. //$this->request = $http->outgoing_payload;
  432. //$this->response = $http->incoming_payload;
  433. //} else
  434. $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
  435. } else {
  436. $this->setError('no http/s in endpoint url');
  437. }
  438. $this->request = $http->outgoing_payload;
  439. $this->response = $http->incoming_payload;
  440. $this->appendDebug($http->getDebug());
  441. $this->UpdateCookies($http->incoming_cookies);
  442. // save transport object if using persistent connections
  443. if ($this->persistentConnection) {
  444. $http->clearDebug();
  445. if (!is_object($this->persistentConnection)) {
  446. $this->persistentConnection = $http;
  447. }
  448. }
  449. if($err = $http->getError()){
  450. $this->setError('HTTP Error: '.$err);
  451. return false;
  452. } elseif($this->getError()){
  453. return false;
  454. } else {
  455. $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
  456. return $this->parseResponse($http->incoming_headers, $this->responseData);
  457. }
  458. break;
  459. default:
  460. $this->setError('no transport found, or selected transport is not yet supported!');
  461. return false;
  462. break;
  463. }
  464. }
  465. /**
  466. * processes SOAP message returned from server
  467. *
  468. * @param array $headers The HTTP headers
  469. * @param string $data unprocessed response data from server
  470. * @return mixed value of the message, decoded into a PHP type
  471. * @access private
  472. */
  473. function parseResponse($headers, $data) {
  474. $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
  475. $this->appendDebug($this->varDump($headers));
  476. if (!isset($headers['content-type'])) {
  477. $this->setError('Response not of type text/xml (no content-type header)');
  478. return false;
  479. }
  480. if (!strstr($headers['content-type'], 'text/xml')) {
  481. $this->setError('Response not of type text/xml: ' . $headers['content-type']);
  482. return false;
  483. }
  484. if (strpos($headers['content-type'], '=')) {
  485. $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
  486. $this->debug('Got response encoding: ' . $enc);
  487. if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
  488. $this->xml_encoding = strtoupper($enc);
  489. } else {
  490. $this->xml_encoding = 'US-ASCII';
  491. }
  492. } else {
  493. // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
  494. $this->xml_encoding = 'ISO-8859-1';
  495. }
  496. $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
  497. $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
  498. // add parser debug data to our debug
  499. $this->appendDebug($parser->getDebug());
  500. // if parse errors
  501. if($errstr = $parser->getError()){
  502. $this->setError( $errstr);
  503. // destroy the parser object
  504. unset($parser);
  505. return false;
  506. } else {
  507. // get SOAP headers
  508. $this->responseHeaders = $parser->getHeaders();
  509. // get SOAP headers
  510. $this->responseHeader = $parser->get_soapheader();
  511. // get decoded message
  512. $return = $parser->get_soapbody();
  513. // add document for doclit support
  514. $this->document = $parser->document;
  515. // destroy the parser object
  516. unset($parser);
  517. // return decode message
  518. return $return;
  519. }
  520. }
  521. /**
  522. * sets user-specified cURL options
  523. *
  524. * @param mixed $option The cURL option (always integer?)
  525. * @param mixed $value The cURL option value
  526. * @access public
  527. */
  528. function setCurlOption($option, $value) {
  529. $this->debug("setCurlOption option=$option, value=");
  530. $this->appendDebug($this->varDump($value));
  531. $this->curl_options[$option] = $value;
  532. }
  533. /**
  534. * sets the SOAP endpoint, which can override WSDL
  535. *
  536. * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
  537. * @access public
  538. */
  539. function setEndpoint($endpoint) {
  540. $this->debug("setEndpoint(\"$endpoint\")");
  541. $this->forceEndpoint = $endpoint;
  542. }
  543. /**
  544. * set the SOAP headers
  545. *
  546. * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
  547. * @access public
  548. */
  549. function setHeaders($headers){
  550. $this->debug("setHeaders headers=");
  551. $this->appendDebug($this->varDump($headers));
  552. $this->requestHeaders = $headers;
  553. }
  554. /**
  555. * get the SOAP response headers (namespace resolution incomplete)
  556. *
  557. * @return string
  558. * @access public
  559. */
  560. function getHeaders(){
  561. return $this->responseHeaders;
  562. }
  563. /**
  564. * get the SOAP response Header (parsed)
  565. *
  566. * @return mixed
  567. * @access public
  568. */
  569. function getHeader(){
  570. return $this->responseHeader;
  571. }
  572. /**
  573. * set proxy info here
  574. *
  575. * @param string $proxyhost
  576. * @param string $proxyport
  577. * @param string $proxyusername
  578. * @param string $proxypassword
  579. * @access public
  580. */
  581. function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
  582. $this->proxyhost = $proxyhost;
  583. $this->proxyport = $proxyport;
  584. $this->proxyusername = $proxyusername;
  585. $this->proxypassword = $proxypassword;
  586. }
  587. /**
  588. * if authenticating, set user credentials here
  589. *
  590. * @param string $username
  591. * @param string $password
  592. * @param string $authtype (basic|digest|certificate|ntlm)
  593. * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
  594. * @access public
  595. */
  596. function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
  597. $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
  598. $this->appendDebug($this->varDump($certRequest));
  599. $this->username = $username;
  600. $this->password = $password;
  601. $this->authtype = $authtype;
  602. $this->certRequest = $certRequest;
  603. }
  604. /**
  605. * use HTTP encoding
  606. *
  607. * @param string $enc HTTP encoding
  608. * @access public
  609. */
  610. function setHTTPEncoding($enc='gzip, deflate'){
  611. $this->debug("setHTTPEncoding(\"$enc\")");
  612. $this->http_encoding = $enc;
  613. }
  614. /**
  615. * Set whether to try to use cURL connections if possible
  616. *
  617. * @param boolean $use Whether to try to use cURL
  618. * @access public
  619. */
  620. function setUseCURL($use) {
  621. $this->debug("setUseCURL($use)");
  622. $this->use_curl = $use;
  623. }
  624. /**
  625. * use HTTP persistent connections if possible
  626. *
  627. * @access public
  628. */
  629. function useHTTPPersistentConnection(){
  630. $this->debug("useHTTPPersistentConnection");
  631. $this->persistentConnection = true;
  632. }
  633. /**
  634. * gets the default RPC parameter setting.
  635. * If true, default is that call params are like RPC even for document style.
  636. * Each call() can override this value.
  637. *
  638. * This is no longer used.
  639. *
  640. * @return boolean
  641. * @access public
  642. * @deprecated
  643. */
  644. function getDefaultRpcParams() {
  645. return $this->defaultRpcParams;
  646. }
  647. /**
  648. * sets the default RPC parameter setting.
  649. * If true, default is that call params are like RPC even for document style
  650. * Each call() can override this value.
  651. *
  652. * This is no longer used.
  653. *
  654. * @param boolean $rpcParams
  655. * @access public
  656. * @deprecated
  657. */
  658. function setDefaultRpcParams($rpcParams) {
  659. $this->defaultRpcParams = $rpcParams;
  660. }
  661. /**
  662. * dynamically creates an instance of a proxy class,
  663. * allowing user to directly call methods from wsdl
  664. *
  665. * @return object soap_proxy object
  666. * @access public
  667. */
  668. function getProxy() {
  669. $r = rand();
  670. $evalStr = $this->_getProxyClassCode($r);
  671. //$this->debug("proxy class: $evalStr");
  672. if ($this->getError()) {
  673. $this->debug("Error from _getProxyClassCode, so return NULL");
  674. return null;
  675. }
  676. // eval the class
  677. eval($evalStr);
  678. // instantiate proxy object
  679. eval("\$proxy = new nusoap_proxy_$r('');");
  680. // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
  681. $proxy->endpointType = 'wsdl';
  682. $proxy->wsdlFile = $this->wsdlFile;
  683. $proxy->wsdl = $this->wsdl;
  684. $proxy->operations = $this->operations;
  685. $proxy->defaultRpcParams = $this->defaultRpcParams;
  686. // transfer other state
  687. $proxy->soap_defencoding = $this->soap_defencoding;
  688. $proxy->username = $this->username;
  689. $proxy->password = $this->password;
  690. $proxy->authtype = $this->authtype;
  691. $proxy->certRequest = $this->certRequest;
  692. $proxy->requestHeaders = $this->requestHeaders;
  693. $proxy->endpoint = $this->endpoint;
  694. $proxy->forceEndpoint = $this->forceEndpoint;
  695. $proxy->proxyhost = $this->proxyhost;
  696. $proxy->proxyport = $this->proxyport;
  697. $proxy->proxyusername = $this->proxyusername;
  698. $proxy->proxypassword = $this->proxypassword;
  699. $proxy->http_encoding = $this->http_encoding;
  700. $proxy->timeout = $this->timeout;
  701. $proxy->response_timeout = $this->response_timeout;
  702. $proxy->persistentConnection = &$this->persistentConnection;
  703. $proxy->decode_utf8 = $this->decode_utf8;
  704. $proxy->curl_options = $this->curl_options;
  705. $proxy->bindingType = $this->bindingType;
  706. $proxy->use_curl = $this->use_curl;
  707. return $proxy;
  708. }
  709. /**
  710. * dynamically creates proxy class code
  711. *
  712. * @return string PHP/NuSOAP code for the proxy class
  713. * @access private
  714. */
  715. function _getProxyClassCode($r) {
  716. $this->debug("in getProxy endpointType=$this->endpointType");
  717. $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
  718. if ($this->endpointType != 'wsdl') {
  719. $evalStr = 'A proxy can only be created for a WSDL client';
  720. $this->setError($evalStr);
  721. $evalStr = "echo \"$evalStr\";";
  722. return $evalStr;
  723. }
  724. if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
  725. $this->loadWSDL();
  726. if ($this->getError()) {
  727. return "echo \"" . $this->getError() . "\";";
  728. }
  729. }
  730. $evalStr = '';
  731. foreach ($this->operations as $operation => $opData) {
  732. if ($operation != '') {
  733. // create param string and param comment string
  734. if (sizeof($opData['input']['parts']) > 0) {
  735. $paramStr = '';
  736. $paramArrayStr = '';
  737. $paramCommentStr = '';
  738. foreach ($opData['input']['parts'] as $name => $type) {
  739. $paramStr .= "\$$name, ";
  740. $paramArrayStr .= "'$name' => \$$name, ";
  741. $paramCommentStr .= "$type \$$name, ";
  742. }
  743. $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
  744. $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
  745. $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
  746. } else {
  747. $paramStr = '';
  748. $paramArrayStr = '';
  749. $paramCommentStr = 'void';
  750. }
  751. $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
  752. $evalStr .= "// $paramCommentStr
  753. function " . str_replace('.', '__', $operation) . "($paramStr) {
  754. \$params = array($paramArrayStr);
  755. return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
  756. }
  757. ";
  758. unset($paramStr);
  759. unset($paramCommentStr);
  760. }
  761. }
  762. $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
  763. '.$evalStr.'
  764. }';
  765. return $evalStr;
  766. }
  767. /**
  768. * dynamically creates proxy class code
  769. *
  770. * @return string PHP/NuSOAP code for the proxy class
  771. * @access public
  772. */
  773. function getProxyClassCode() {
  774. $r = rand();
  775. return $this->_getProxyClassCode($r);
  776. }
  777. /**
  778. * gets the HTTP body for the current request.
  779. *
  780. * @param string $soapmsg The SOAP payload
  781. * @return string The HTTP body, which includes the SOAP payload
  782. * @access private
  783. */
  784. function getHTTPBody($soapmsg) {
  785. return $soapmsg;
  786. }
  787. /**
  788. * gets the HTTP content type for the current request.
  789. *
  790. * Note: getHTTPBody must be called before this.
  791. *
  792. * @return string the HTTP content type for the current request.
  793. * @access private
  794. */
  795. function getHTTPContentType() {
  796. return 'text/xml';
  797. }
  798. /**
  799. * gets the HTTP content type charset for the current request.
  800. * returns false for non-text content types.
  801. *
  802. * Note: getHTTPBody must be called before this.
  803. *
  804. * @return string the HTTP content type charset for the current request.
  805. * @access private
  806. */
  807. function getHTTPContentTypeCharset() {
  808. return $this->soap_defencoding;
  809. }
  810. /*
  811. * whether or not parser should decode utf8 element content
  812. *
  813. * @return always returns true
  814. * @access public
  815. */
  816. function decodeUTF8($bool){
  817. $this->decode_utf8 = $bool;
  818. return true;
  819. }
  820. /**
  821. * adds a new Cookie into $this->cookies array
  822. *
  823. * @param string $name Cookie Name
  824. * @param string $value Cookie Value
  825. * @return boolean if cookie-set was successful returns true, else false
  826. * @access public
  827. */
  828. function setCookie($name, $value) {
  829. if (strlen($name) == 0) {
  830. return false;
  831. }
  832. $this->cookies[] = array('name' => $name, 'value' => $value);
  833. return true;
  834. }
  835. /**
  836. * gets all Cookies
  837. *
  838. * @return array with all internal cookies
  839. * @access public
  840. */
  841. function getCookies() {
  842. return $this->cookies;
  843. }
  844. /**
  845. * checks all Cookies and delete those which are expired
  846. *
  847. * @return boolean always return true
  848. * @access private
  849. */
  850. function checkCookies() {
  851. if (sizeof($this->cookies) == 0) {
  852. return true;
  853. }
  854. $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
  855. $curr_cookies = $this->cookies;
  856. $this->cookies = array();
  857. foreach ($curr_cookies as $cookie) {
  858. if (! is_array($cookie)) {
  859. $this->debug('Remove cookie that is not an array');
  860. continue;
  861. }
  862. if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
  863. if (strtotime($cookie['expires']) > time()) {
  864. $this->cookies[] = $cookie;
  865. } else {
  866. $this->debug('Remove expired cookie ' . $cookie['name']);
  867. }
  868. } else {
  869. $this->cookies[] = $cookie;
  870. }
  871. }
  872. $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
  873. return true;
  874. }
  875. /**
  876. * updates the current cookies with a new set
  877. *
  878. * @param array $cookies new cookies with which to update current ones
  879. * @return boolean always return true
  880. * @access private
  881. */
  882. function UpdateCookies($cookies) {
  883. if (sizeof($this->cookies) == 0) {
  884. // no existing cookies: take whatever is new
  885. if (sizeof($cookies) > 0) {
  886. $this->debug('Setting new cookie(s)');
  887. $this->cookies = $cookies;
  888. }
  889. return true;
  890. }
  891. if (sizeof($cookies) == 0) {
  892. // no new cookies: keep what we've got
  893. return true;
  894. }
  895. // merge
  896. foreach ($cookies as $newCookie) {
  897. if (!is_array($newCookie)) {
  898. continue;
  899. }
  900. if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
  901. continue;
  902. }
  903. $newName = $newCookie['name'];
  904. $found = false;
  905. for ($i = 0; $i < count($this->cookies); $i++) {
  906. $cookie = $this->cookies[$i];
  907. if (!is_array($cookie)) {
  908. continue;
  909. }
  910. if (!isset($cookie['name'])) {
  911. continue;
  912. }
  913. if ($newName != $cookie['name']) {
  914. continue;
  915. }
  916. $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
  917. $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
  918. if ($newDomain != $domain) {
  919. continue;
  920. }
  921. $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
  922. $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
  923. if ($newPath != $path) {
  924. continue;
  925. }
  926. $this->cookies[$i] = $newCookie;
  927. $found = true;
  928. $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
  929. break;
  930. }
  931. if (! $found) {
  932. $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
  933. $this->cookies[] = $newCookie;
  934. }
  935. }
  936. return true;
  937. }
  938. }
  939. if (!extension_loaded('soap')) {
  940. /**
  941. * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
  942. */
  943. class soapclient extends nusoap_client {
  944. }
  945. }
  946. ?>