PageRenderTime 69ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/digidoc/include/_PEAR/SOAP/Server.php

https://bitbucket.org/elver/liituja
PHP | 795 lines | 528 code | 83 blank | 184 comment | 135 complexity | 52faa365fc319d07d3f075b09a583556 MD5 | raw file
  1. <?php
  2. /**
  3. * This file contains the code for the SOAP server.
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * LICENSE: This source file is subject to version 2.02 of the PHP license,
  8. * that is bundled with this package in the file LICENSE, and is available at
  9. * through the world-wide-web at http://www.php.net/license/2_02.txt. If you
  10. * did not receive a copy of the PHP license and are unable to obtain it
  11. * through the world-wide-web, please send a note to license@php.net so we can
  12. * mail you a copy immediately.
  13. *
  14. * @category Web Services
  15. * @package SOAP
  16. * @author Dietrich Ayala <dietrich@ganx4.com> Original Author
  17. * @author Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more
  18. * @author Chuck Hagenbuch <chuck@horde.org> Maintenance
  19. * @author Jan Schneider <jan@horde.org> Maintenance
  20. * @copyright 2003-2005 The PHP Group
  21. * @license http://www.php.net/license/2_02.txt PHP License 2.02
  22. * @link http://pear.php.net/package/SOAP
  23. */
  24. require_once PEAR_PATH.'SOAP/Base.php';
  25. require_once PEAR_PATH.'SOAP/Fault.php';
  26. require_once PEAR_PATH.'SOAP/Parser.php';
  27. require_once PEAR_PATH.'SOAP/Value.php';
  28. require_once PEAR_PATH.'SOAP/WSDL.php';
  29. /**
  30. * SOAP Server Class
  31. *
  32. * Originaly based on SOAPx4 by Dietrich Ayala
  33. * http://dietrich.ganx4.com/soapx4
  34. *
  35. * @access public
  36. * @package SOAP
  37. * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  38. * @author Dietrich Ayala <dietrich@ganx4.com> Original Author
  39. */
  40. class SOAP_Server extends SOAP_Base
  41. {
  42. /**
  43. *
  44. * @var array
  45. */
  46. var $dispatch_map = array(); // create empty dispatch map
  47. var $dispatch_objects = array();
  48. var $soapobject = null;
  49. var $call_methodname = null;
  50. var $callHandler = null;
  51. var $callValidation = true;
  52. /**
  53. * A list of headers that are going to be sent back to the client.
  54. *
  55. * @var array
  56. */
  57. var $headers = array();
  58. /**
  59. *
  60. * @var string
  61. */
  62. var $request = '';
  63. /**
  64. *
  65. * @var string XML-Encoding
  66. */
  67. var $xml_encoding = SOAP_DEFAULT_ENCODING;
  68. var $response_encoding = 'UTF-8';
  69. var $result = 'successful'; // for logging interop results to db
  70. var $endpoint = ''; // the uri to ME!
  71. var $service = ''; //soapaction header
  72. var $method_namespace = null;
  73. var $__options = array('use' => 'encoded',
  74. 'style' => 'rpc',
  75. 'parameters' => 0,
  76. 'http_status_success' => '200 OK',
  77. 'http_status_fault' => '500 SOAP Fault');
  78. function SOAP_Server($options = null)
  79. {
  80. ini_set('track_errors', 1);
  81. parent::SOAP_Base('Server');
  82. if (is_array($options)) {
  83. if (isset($options['use'])) {
  84. $this->__options['use'] = $options['use'];
  85. }
  86. if (isset($options['style'])) {
  87. $this->__options['style'] = $options['style'];
  88. }
  89. if (isset($options['parameters'])) {
  90. $this->__options['parameters'] = $options['parameters'];
  91. }
  92. }
  93. // assume we encode with section 5
  94. $this->_section5 = true;
  95. if ($this->__options['use']=='literal') {
  96. $this->_section5 = false;
  97. }
  98. }
  99. /**
  100. * Error handler for errors that happen in proxied methods.
  101. *
  102. * To always return a valid SOAP response even on errors that don't happen
  103. * in this code, the errors are catched, transformed to a SOAP fault and
  104. * immediately sent to the client.
  105. *
  106. * @see http://www.php.net/set_error_handler
  107. */
  108. function _errorHandler($errno, $errmsg, $filename, $linenum, $vars)
  109. {
  110. /* The error handler should ignore '0' errors, eg. hidden by @ - see
  111. * the set_error_handler manual page. (thanks to Alan Knowles). */
  112. if (!$errno || $errno == E_NOTICE ||
  113. (defined('E_STRICT') && $errno == constant('E_STRICT'))) {
  114. return;
  115. }
  116. $this->fault =& new SOAP_Fault($errmsg, 'Server', 'PHP', "Errno: $errno\nFilename: $filename\nLineno: $linenum\n");
  117. $this->_sendResponse();
  118. exit;
  119. }
  120. function _getContentEncoding($content_type)
  121. {
  122. /* Get the character encoding of the incoming request treat incoming
  123. * data as UTF-8 if no encoding set. */
  124. $this->xml_encoding = 'UTF-8';
  125. if (strpos($content_type, '=')) {
  126. $enc = strtoupper(str_replace('"', '', substr(strstr($content_type, '='), 1)));
  127. if (!in_array($enc, $this->_encodings)) {
  128. return false;
  129. }
  130. $this->xml_encoding = $enc;
  131. }
  132. return true;
  133. }
  134. /**
  135. * Parses request and posts response.
  136. */
  137. function service($data, $endpoint = '', $test = false)
  138. {
  139. $response = null;
  140. $attachments = array();
  141. $useEncoding = 'DIME';
  142. /* Figure out our endpoint. */
  143. $this->endpoint = $endpoint;
  144. if (!$test && !$this->endpoint) {
  145. /* We'll try to build our endpoint. */
  146. $this->endpoint = 'http://' . $_SERVER['SERVER_NAME'];
  147. if ($_SERVER['SERVER_PORT']) {
  148. $this->endpoint .= ':' . $_SERVER['SERVER_PORT'];
  149. }
  150. $this->endpoint .= $_SERVER['SCRIPT_NAME'];
  151. }
  152. /* Get the character encoding of the incoming request treat incoming
  153. * data as UTF-8 if no encoding set. */
  154. if (isset($_SERVER['CONTENT_TYPE'])) {
  155. if (strcasecmp($_SERVER['CONTENT_TYPE'], 'application/dime') == 0) {
  156. $this->_decodeDIMEMessage($data, $headers, $attachments);
  157. $useEncoding = 'DIME';
  158. } elseif (stristr($_SERVER['CONTENT_TYPE'], 'multipart/related')) {
  159. /* This is a mime message, let's decode it. */
  160. $data = 'Content-Type: ' .
  161. stripslashes($_SERVER['CONTENT_TYPE']) .
  162. "\r\n\r\n" . $data;
  163. $this->_decodeMimeMessage($data, $headers, $attachments);
  164. $useEncoding = 'Mime';
  165. }
  166. if (!isset($headers['content-type'])) {
  167. $headers['content-type'] = stripslashes($_SERVER['CONTENT_TYPE']);
  168. }
  169. if (!$this->fault &&
  170. !$this->_getContentEncoding($headers['content-type'])) {
  171. $this->xml_encoding = SOAP_DEFAULT_ENCODING;
  172. /* Found encoding we don't understand; return a fault. */
  173. $this->_raiseSoapFault('Unsupported encoding, use one of ISO-8859-1, US-ASCII, UTF-8', '', '', 'Server');
  174. }
  175. }
  176. /* If this is not a POST with Content-Type text/xml, try to return a
  177. * WSDL file. */
  178. if (!$this->fault && !$test &&
  179. ($_SERVER['REQUEST_METHOD'] != 'POST' ||
  180. strncmp($headers['content-type'], 'text/xml', 8) != 0)) {
  181. /* This is not possibly a valid SOAP request, try to return a WSDL
  182. * file. */
  183. $this->_raiseSoapFault('Invalid SOAP request, must be POST with content-type: text/xml, got: ' . (isset($headers['content-type']) ? $headers['content-type'] : 'Nothing!'), '', '', 'Server');
  184. }
  185. if (!$this->fault) {
  186. /* $response is a SOAP_Msg object. */
  187. $soap_msg = $this->parseRequest($data, $attachments);
  188. /* Handle Mime or DIME encoding. */
  189. /* TODO: DIME decoding should move to the transport, do it here
  190. * for now and for ease of getting it done. */
  191. if (count($this->__attachments)) {
  192. if ($useEncoding == 'Mime') {
  193. $soap_msg = $this->_makeMimeMessage($soap_msg);
  194. } else {
  195. // default is dime
  196. $soap_msg = $this->_makeDIMEMessage($soap_msg);
  197. $this->headers['Content-Type'] = 'application/dime';
  198. }
  199. if (PEAR::isError($soap_msg)) {
  200. return $this->_raiseSoapFault($soap_msg);
  201. }
  202. }
  203. if (is_array($soap_msg)) {
  204. $response = $soap_msg['body'];
  205. if (count($soap_msg['headers'])) {
  206. $this->headers = $soap_msg['headers'];
  207. }
  208. } else {
  209. $response = $soap_msg;
  210. }
  211. }
  212. $this->_sendResponse($response);
  213. }
  214. /**
  215. * Sends the final HTTP response to the client, including the HTTP header
  216. * and the HTTP body.
  217. *
  218. * If an error happened, it returns a SOAP fault instead of the response
  219. * body.
  220. *
  221. * @param string $response The response body.
  222. */
  223. function _sendResponse($response = '')
  224. {
  225. /* Make distinction between the different SAPIs, running PHP as CGI or
  226. * as a module. */
  227. if (stristr(php_sapi_name(), 'cgi') === 0) {
  228. $hdrs_type = 'Status:';
  229. } else {
  230. $hdrs_type = 'HTTP/1.1';
  231. }
  232. if ($this->fault) {
  233. $hdrs = $hdrs_type . ' ' . $this->__options['http_status_fault'] . "\r\n";
  234. $response = $this->fault->message();
  235. } else {
  236. $hdrs = $hdrs_type . ' ' . $this->__options['http_status_success'] . "\r\n";
  237. }
  238. header($hdrs);
  239. $this->headers['Server'] = SOAP_LIBRARY_NAME;
  240. if (!isset($this->headers['Content-Type'])) {
  241. $this->headers['Content-Type'] = 'text/xml; charset=' .
  242. $this->response_encoding;
  243. }
  244. $this->headers['Content-Length'] = strlen($response);
  245. foreach ($this->headers as $k => $v) {
  246. header("$k: $v");
  247. $hdrs .= "$k: $v\r\n";
  248. }
  249. $this->response = $hdrs . "\r\n" . $response;
  250. print $response;
  251. }
  252. function &callMethod($methodname, &$args)
  253. {
  254. if ($this->callHandler) {
  255. $ret = @call_user_func_array($this->callHandler, array($methodname, $args));
  256. return $ret;
  257. }
  258. set_error_handler(array($this, '_errorHandler'));
  259. if ($args) {
  260. /* Call method with parameters. */
  261. if (isset($this->soapobject) && is_object($this->soapobject)) {
  262. $ret = @call_user_func_array(array(&$this->soapobject, $methodname), $args);
  263. } else {
  264. $ret = @call_user_func_array($methodname, $args);
  265. }
  266. } else {
  267. /* Call method withour parameters. */
  268. if (is_object($this->soapobject)) {
  269. $ret = @call_user_func(array(&$this->soapobject, $methodname));
  270. } else {
  271. $ret = @call_user_func($methodname);
  272. }
  273. }
  274. restore_error_handler();
  275. return $ret;
  276. }
  277. /**
  278. * Creates SOAP_Value objects with return values from method.
  279. * Uses method signature to determine type.
  280. *
  281. * @param mixed $method_response The result(s).
  282. * @param array|string $type The type(s) of the return value(s).
  283. * @param string $return_name The name of the return value.
  284. * @param string $namespace The namespace of the return value.
  285. *
  286. * @return array List of SOAP_Value objects.
  287. */
  288. function buildResult(&$method_response, &$return_type,
  289. $return_name = 'return', $namespace = '')
  290. {
  291. if (is_a($method_response, 'SOAP_Value')) {
  292. $return_val = array($method_response);
  293. } else {
  294. if (is_array($return_type) && is_array($method_response)) {
  295. $i = 0;
  296. foreach ($return_type as $key => $type) {
  297. if (is_numeric($key)) {
  298. $key = 'item';
  299. }
  300. if (is_a($method_response[$i], 'SOAP_Value')) {
  301. $return_val[] =& $method_response[$i++];
  302. } else {
  303. $qn =& new QName($key, $namespace);
  304. $return_val[] =& new SOAP_Value($qn->fqn(), $type, $method_response[$i++]);
  305. }
  306. }
  307. } else {
  308. if (is_array($return_type)) {
  309. $keys = array_keys($return_type);
  310. if (!is_numeric($keys[0])) {
  311. $return_name = $keys[0];
  312. }
  313. $values = array_values($return_type);
  314. $return_type = $values[0];
  315. }
  316. $qn =& new QName($return_name, $namespace);
  317. $return_val = array(new SOAP_Value($qn->fqn(), $return_type, $method_response));
  318. }
  319. }
  320. return $return_val;
  321. }
  322. function parseRequest($data = '', $attachments = null)
  323. {
  324. /* Parse response, get SOAP_Parser object. */
  325. $parser =& new SOAP_Parser($data, $this->xml_encoding, $attachments);
  326. /* If fault occurred during message parsing. */
  327. if ($parser->fault) {
  328. $this->fault = $parser->fault;
  329. return null;
  330. }
  331. /* Handle message headers. */
  332. $request_headers = $parser->getHeaders();
  333. $header_results = array();
  334. if ($request_headers) {
  335. if (!is_a($request_headers, 'SOAP_Value')) {
  336. $this->_raiseSoapFault('Parser did not return SOAP_Value object: ' . $request_headers, '', '', 'Server');
  337. return null;
  338. }
  339. if ($request_headers->value) {
  340. /* Handle headers now. */
  341. foreach ($request_headers->value as $header_val) {
  342. $f_exists = $this->validateMethod($header_val->name, $header_val->namespace);
  343. /* TODO: this does not take into account message routing
  344. * yet. */
  345. $myactor = !$header_val->actor ||
  346. $header_val->actor == 'http://schemas.xmlsoap.org/soap/actor/next' ||
  347. $header_val->actor == $this->endpoint;
  348. if (!$f_exists && $header_val->mustunderstand && $myactor) {
  349. $this->_raiseSoapFault('I don\'t understand header ' . $header_val->name, '', '', 'MustUnderstand');
  350. return null;
  351. }
  352. /* We only handle the header if it's for us. */
  353. $isok = $f_exists && $myactor;
  354. if ($isok) {
  355. /* Call our header now! */
  356. $header_method = $header_val->name;
  357. $header_data = array($this->_decode($header_val));
  358. /* If there are parameters to pass. */
  359. $hr =& $this->callMethod($header_method, $header_data);
  360. if (PEAR::isError($hr)) {
  361. $this->_raiseSoapDefault($hr);
  362. return null;
  363. }
  364. $results = $this->buildResult($hr, $this->return_type, $header_method, $header_val->namespace);
  365. $header_results[] = $results[0];
  366. }
  367. }
  368. }
  369. }
  370. /* Handle the method call. */
  371. /* Evaluate message, getting back a SOAP_Value object. */
  372. $this->call_methodname = $this->methodname = $parser->root_struct_name[0];
  373. /* Figure out the method namespace. */
  374. $this->method_namespace = $parser->message[$parser->root_struct[0]]['namespace'];
  375. if ($this->_wsdl) {
  376. $this->_setSchemaVersion($this->_wsdl->xsd);
  377. $dataHandler = $this->_wsdl->getDataHandler($this->methodname, $this->method_namespace);
  378. if ($dataHandler)
  379. $this->call_methodname = $this->methodname = $dataHandler;
  380. $this->_portName = $this->_wsdl->getPortName($this->methodname);
  381. if (PEAR::isError($this->_portName)) {
  382. $this->_raiseSoapFault($this->_portName);
  383. return null;
  384. }
  385. $opData = $this->_wsdl->getOperationData($this->_portName, $this->methodname);
  386. if (PEAR::isError($opData)) {
  387. $this->_raiseSoapFault($opData);
  388. return null;
  389. }
  390. $this->__options['style'] = $opData['style'];
  391. $this->__options['use'] = $opData['output']['use'];
  392. $this->__options['parameters'] = $opData['parameters'];
  393. }
  394. /* Does method exist? */
  395. if (!$this->methodname ||
  396. !$this->validateMethod($this->methodname, $this->method_namespace)) {
  397. $this->_raiseSoapFault('method "' . $this->method_namespace . $this->methodname . '" not defined in service', '', '', 'Server');
  398. return null;
  399. }
  400. if (!$request_val = $parser->getResponse()) {
  401. return null;
  402. }
  403. if (!is_a($request_val, 'SOAP_Value')) {
  404. $this->_raiseSoapFault('Parser did not return SOAP_Value object: ' . $request_val, '', '', 'Server');
  405. return null;
  406. }
  407. /* Verify that SOAP_Value objects in request match the methods
  408. * signature. */
  409. if (!$this->verifyMethod($request_val)) {
  410. /* verifyMethod() creates the fault. */
  411. return null;
  412. }
  413. /* Need to set special error detection inside the value class to
  414. * differentiate between no params passed, and an error decoding. */
  415. $request_data = $this->__decodeRequest($request_val);
  416. if (PEAR::isError($request_data)) {
  417. $this->_raiseSoapFault($request_data);
  418. return null;
  419. }
  420. $method_response =& $this->callMethod($this->call_methodname, $request_data);
  421. if (PEAR::isError($method_response)) {
  422. $this->_raiseSoapFault($method_response);
  423. return null;
  424. }
  425. if ($this->__options['parameters'] ||
  426. !$method_response ||
  427. $this->__options['style']=='rpc') {
  428. /* Get the method result. */
  429. if (is_null($method_response)) {
  430. $return_val = null;
  431. } else {
  432. $return_val = $this->buildResult($method_response, $this->return_type);
  433. }
  434. $qn =& new QName($this->methodname . 'Response', $this->method_namespace);
  435. $methodValue =& new SOAP_Value($qn->fqn(), 'Struct', $return_val);
  436. } else {
  437. $methodValue =& $method_response;
  438. }
  439. return $this->_makeEnvelope($methodValue, $header_results, $this->response_encoding);
  440. }
  441. function &__decodeRequest($request, $shift = false)
  442. {
  443. if (!$request) {
  444. $decoded = null;
  445. return $decoded;
  446. }
  447. /* Check for valid response. */
  448. if (PEAR::isError($request)) {
  449. $fault = &$this->_raiseSoapFault($request);
  450. return $fault;
  451. } else if (!is_a($request, 'SOAP_Value')) {
  452. $fault = &$this->_raiseSoapFault('Invalid data in server::__decodeRequest');
  453. return $fault;
  454. }
  455. /* Decode to native php datatype. */
  456. $requestArray = $this->_decode($request);
  457. /* Fault? */
  458. if (PEAR::isError($requestArray)) {
  459. $fault = &$this->_raiseSoapFault($requestArray);
  460. return $fault;
  461. }
  462. if (is_object($requestArray) &&
  463. get_class($requestArray) == 'stdClass') {
  464. $requestArray = get_object_vars($requestArray);
  465. } elseif ($this->__options['style'] == 'document') {
  466. $requestArray = array($requestArray);
  467. }
  468. if (is_array($requestArray)) {
  469. if (isset($requestArray['faultcode']) ||
  470. isset($requestArray['SOAP-ENV:faultcode'])) {
  471. $faultcode = $faultstring = $faultdetail = $faultactor = '';
  472. foreach ($requestArray as $k => $v) {
  473. if (stristr($k, 'faultcode')) {
  474. $faultcode = $v;
  475. }
  476. if (stristr($k, 'faultstring')) {
  477. $faultstring = $v;
  478. }
  479. if (stristr($k, 'detail')) {
  480. $faultdetail = $v;
  481. }
  482. if (stristr($k, 'faultactor')) {
  483. $faultactor = $v;
  484. }
  485. }
  486. $fault = &$this->_raiseSoapFault($faultstring, $faultdetail, $faultactor, $faultcode);
  487. return $fault;
  488. }
  489. /* Return array of return values. */
  490. if ($shift && count($requestArray) == 1) {
  491. $decoded = array_shift($requestArray);
  492. return $decoded;
  493. }
  494. return $requestArray;
  495. }
  496. return $requestArray;
  497. }
  498. function verifyMethod($request)
  499. {
  500. if (!$this->callValidation) {
  501. return true;
  502. }
  503. $params = $request->value;
  504. /* Get the dispatch map if one exists. */
  505. $map = null;
  506. if (array_key_exists($this->methodname, $this->dispatch_map)) {
  507. $map = $this->dispatch_map[$this->methodname];
  508. } elseif (isset($this->soapobject)) {
  509. if (method_exists($this->soapobject, '__dispatch')) {
  510. $map = $this->soapobject->__dispatch($this->methodname);
  511. } elseif (method_exists($this->soapobject, $this->methodname)) {
  512. /* No map, all public functions are SOAP functions. */
  513. return true;
  514. }
  515. }
  516. if (!$map) {
  517. $this->_raiseSoapFault('SOAP request specified an unhandled method "' . $this->methodname . '"', '', '', 'Client');
  518. return false;
  519. }
  520. /* If we aliased the SOAP method name to a PHP function, change
  521. * call_methodname so we do the right thing. */
  522. if (array_key_exists('alias', $map) && !empty($map['alias'])) {
  523. $this->call_methodname = $map['alias'];
  524. }
  525. /* If there are input parameters required. */
  526. if ($sig = $map['in']) {
  527. $this->input_value = count($sig);
  528. $this->return_type = false;
  529. if (is_array($map['out'])) {
  530. $this->return_type = count($map['out']) > 1
  531. ? $map['out']
  532. : array_shift($map['out']);
  533. }
  534. if (is_array($params)) {
  535. /* Validate the number of parameters. */
  536. if (count($params) == count($sig)) {
  537. /* Make array of param types. */
  538. foreach ($params as $param) {
  539. $p[] = strtolower($param->type);
  540. }
  541. $sig_t = array_values($sig);
  542. /* Validate each param's type. */
  543. for ($i = 0; $i < count($p); $i++) {
  544. /* If SOAP types do not match, it's still fine if the
  545. * mapped php types match this allows using plain PHP
  546. * variables to work (i.e. stuff like Decimal would
  547. * fail otherwise). We consider this only error if the
  548. * types exist in our type maps, and they differ. */
  549. if (strcasecmp($sig_t[$i], $p[$i]) != 0 &&
  550. isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$sig_t[$i]]) &&
  551. strcasecmp($this->_typemap[SOAP_XML_SCHEMA_VERSION][$sig_t[$i]], $this->_typemap[SOAP_XML_SCHEMA_VERSION][$p[$i]]) != 0) {
  552. $param = $params[$i];
  553. $this->_raiseSoapFault("SOAP request contained mismatching parameters of name $param->name had type [{$p[$i]}], which did not match signature's type: [{$sig_t[$i]}], matched? " . (strcasecmp($sig_t[$i], $p[$i])), '', '', 'Client');
  554. return false;
  555. }
  556. }
  557. return true;
  558. } else {
  559. /* Wrong number of params. */
  560. $this->_raiseSoapFault('SOAP request contained incorrect number of parameters. method "' . $this->methodname . '" required ' . count($sig) . ' and request provided ' . count($params), '', '', 'Client');
  561. return false;
  562. }
  563. } else {
  564. /* No params. */
  565. $this->_raiseSoapFault('SOAP request contained incorrect number of parameters. method "' . $this->methodname . '" requires ' . count($sig) . ' parameters, and request provided none.', '', '', 'Client');
  566. return false;
  567. }
  568. }
  569. /* We'll try it anyway. */
  570. return true;
  571. }
  572. function validateMethod($methodname, $namespace = null)
  573. {
  574. unset($this->soapobject);
  575. if (!$this->callValidation) {
  576. return true;
  577. }
  578. /* No SOAP access to private functions. */
  579. if ($methodname[0] == '_') {
  580. return false;
  581. }
  582. /* if it's in our function list, ok */
  583. if (array_key_exists($methodname, $this->dispatch_map) &&
  584. (!$namespace ||
  585. !array_key_exists('namespace', $this->dispatch_map[$methodname]) ||
  586. $namespace == $this->dispatch_map[$methodname]['namespace'])) {
  587. if (array_key_exists('namespace', $this->dispatch_map[$methodname]))
  588. $this->method_namespace = $this->dispatch_map[$methodname]['namespace'];
  589. return true;
  590. }
  591. /* if it's in an object, it's ok */
  592. if (isset($this->dispatch_objects[$namespace])) {
  593. $c = count($this->dispatch_objects[$namespace]);
  594. for ($i = 0; $i < $c; $i++) {
  595. $obj =& $this->dispatch_objects[$namespace][$i];
  596. /* If we have a dispatch map, and the function is not in the
  597. * dispatch map, then it is not callable! */
  598. if (method_exists($obj, '__dispatch')) {
  599. if ($obj->__dispatch($methodname)) {
  600. $this->method_namespace = $namespace;
  601. $this->soapobject =& $obj;
  602. return true;
  603. }
  604. } elseif (method_exists($obj, $methodname)) {
  605. $this->method_namespace = $namespace;
  606. $this->soapobject =& $obj;
  607. return true;
  608. }
  609. }
  610. }
  611. return false;
  612. }
  613. function addObjectMap(&$obj, $namespace = null, $service_name = 'Default',
  614. $service_desc = '')
  615. {
  616. if (!$namespace) {
  617. if (isset($obj->namespace)) {
  618. // XXX a bit of backwards compatibility
  619. $namespace = $obj->namespace;
  620. } else {
  621. $this->_raiseSoapFault('No namespace provided for class!', '', '', 'Server');
  622. return false;
  623. }
  624. }
  625. if (!isset($this->dispatch_objects[$namespace])) {
  626. $this->dispatch_objects[$namespace] = array();
  627. }
  628. $this->dispatch_objects[$namespace][] =& $obj;
  629. // Create internal WSDL structures for object
  630. // XXX Because some internal workings of PEAR::SOAP decide whether to
  631. // do certain things by the presence or absence of _wsdl, we should
  632. // only create a _wsdl structure if we know we can fill it; if
  633. // __dispatch_map or __typedef for the object is missing, we should
  634. // avoid creating it. Later, when we are using PHP 5 introspection, we
  635. // will be able to make the data for all objects without any extra
  636. // information from the developers, and this condition should be
  637. // dropped.
  638. // XXX Known issue: if imported WSDL (bindWSDL) or another WSDL source
  639. // is used to add _wsdl structure information, then addObjectWSDL is
  640. // used, there is a high possibility of _wsdl data corruption;
  641. // therefore you should avoid using __dispatch_map/__typedef
  642. // definitions AND other WSDL data sources in the same service. We
  643. // exclude classes that don't have __typedefs to allow external WSDL
  644. // files to be used with classes with no internal type definitions
  645. // (the types are defined in the WSDL file). When addObjectWSDL is
  646. // refactored to not cause corruption, this restriction can be
  647. // relaxed.
  648. // In summary, if you add an object with both a dispatch map and type
  649. // definitions, then previous WSDL file operation and type definitions
  650. // will be overwritten.
  651. if (isset($obj->__dispatch_map) && isset($obj->__typedef)) {
  652. $this->addObjectWSDL($obj, $namespace, $service_name, $service_desc);
  653. }
  654. return true;
  655. }
  656. /**
  657. * Adds a method to the dispatch map.
  658. */
  659. function addToMap($methodname, $in, $out, $namespace = null, $alias = null)
  660. {
  661. if (!function_exists($methodname)) {
  662. $this->_raiseSoapFault('Error mapping function', '', '', 'Server');
  663. return false;
  664. }
  665. $this->dispatch_map[$methodname]['in'] = $in;
  666. $this->dispatch_map[$methodname]['out'] = $out;
  667. $this->dispatch_map[$methodname]['alias'] = $alias;
  668. if ($namespace) {
  669. $this->dispatch_map[$methodname]['namespace'] = $namespace;
  670. }
  671. return true;
  672. }
  673. function setCallHandler($callHandler, $validation = true)
  674. {
  675. $this->callHandler = $callHandler;
  676. $this->callValidation = $validation;
  677. }
  678. /**
  679. * @deprecated use bindWSDL from now on
  680. */
  681. function bind($wsdl_url)
  682. {
  683. $this->bindWSDL($wsdl_url);
  684. }
  685. /**
  686. * @param string a url to a WSDL resource
  687. * @return void
  688. */
  689. function bindWSDL($wsdl_url)
  690. {
  691. /* Instantiate WSDL class. */
  692. $this->_wsdl =& new SOAP_WSDL($wsdl_url);
  693. if ($this->_wsdl->fault) {
  694. $this->_raiseSoapFault($this->_wsdl->fault);
  695. }
  696. }
  697. /**
  698. * @return void
  699. */
  700. function addObjectWSDL(&$wsdl_obj, $targetNamespace, $service_name,
  701. $service_desc = '')
  702. {
  703. if (!isset($this->_wsdl)) {
  704. $this->_wsdl =& new SOAP_WSDL;
  705. }
  706. $this->_wsdl->parseObject($wsdl_obj, $targetNamespace, $service_name, $service_desc);
  707. if ($this->_wsdl->fault) {
  708. $this->_raiseSoapFault($this->_wsdl->fault);
  709. }
  710. }
  711. }