1: <?php
2: /**
3: * The Horde_Rpc_Soap class provides a PHP 5 Soap implementation
4: * of the Horde RPC system.
5: *
6: * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
7: *
8: * See the enclosed file COPYING for license information (LGPL). If you
9: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
10: *
11: * @author Chuck Hagenbuch <chuck@horde.org>
12: * @package Rpc
13: */
14: class Horde_Rpc_Soap extends Horde_Rpc
15: {
16: /**
17: * Resource handler for the SOAP server.
18: *
19: * @var object
20: */
21: var $_server;
22:
23: /**
24: * List of types to emit in the WSDL.
25: *
26: * @var array
27: */
28: var $_allowedTypes = array();
29:
30: /**
31: * List of method names to allow.
32: *
33: * @var array
34: */
35: var $_allowedMethods = array();
36:
37: /**
38: * Name of the SOAP service to use in the WSDL.
39: *
40: * @var string
41: */
42: var $_serviceName = null;
43:
44: /**
45: * SOAP server constructor
46: *
47: * @access private
48: */
49: public function __construct($request, $params = array())
50: {
51: parent::__construct($request, $params);
52:
53: if (!empty($params['allowedTypes'])) {
54: $this->_allowedTypes = $params['allowedTypes'];
55: }
56: if (!empty($params['allowedMethods'])) {
57: $this->_allowedMethods = $params['allowedMethods'];
58: }
59: if (!empty($params['serviceName'])) {
60: $this->_serviceName = $params['serviceName'];
61: }
62:
63: $this->_server = new SoapServer(null, array('uri' => (string)Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/rpc.php', true, -1)));
64: $this->_server->addFunction(SOAP_FUNCTIONS_ALL);
65: $this->_server->setClass('Horde_Rpc_Soap_Caller', $params);
66: }
67:
68: /**
69: * Takes a SOAP request and returns the result.
70: *
71: * @param string The raw request string.
72: *
73: * @return string The XML encoded response from the server.
74: */
75: function getResponse($request)
76: {
77: if ($request == 'disco' || $request == 'wsdl') {
78: /*@TODO Replace with subcalls for disco and wsdl generation from the old SOAP driver. */
79: //$handler = new Horde_Rpc_Soap($this->_params);
80: //return $handler->getResponse($request);
81: }
82:
83: /* We can't use Horde_Util::bufferOutput() here for some reason. */
84: $beginTime = time();
85: ob_start();
86: $this->_server->handle($request);
87: Horde::logMessage(
88: sprintf('SOAP call: %s(%s) by %s serviced in %d seconds, sent %d bytes in response',
89: $GLOBALS['__horde_rpc_PhpSoap']['lastMethodCalled'],
90: implode(', ', array_map(create_function('$a', 'return is_array($a) ? "Array" : $a;'),
91: $GLOBALS['__horde_rpc_PhpSoap']['lastMethodParams'])),
92: $GLOBALS['registry']->getAuth(),
93: time() - $beginTime,
94: ob_get_length()),
95: 'INFO');
96: return ob_get_clean();
97: }
98:
99: /**
100: * Builds a SOAP request and sends it to the SOAP server.
101: *
102: * This statically called method is actually the SOAP client.
103: *
104: * @param string|Horde_Url $url The path to the SOAP server on the called
105: * host.
106: * @param string $method The method to call.
107: * @param array $params A hash containing any necessary parameters
108: * for the method call.
109: * @param $options Optional associative array of parameters which can be:
110: * - user: Basic Auth username
111: * - pass: Basic Auth password
112: * - proxy_host: Proxy server host
113: * - proxy_port: Proxy server port
114: * - proxy_user: Proxy auth username
115: * - proxy_pass: Proxy auth password
116: * - timeout: Connection timeout in seconds.
117: * - allowRedirects: Whether to follow redirects or not
118: * - maxRedirects: Max number of redirects to follow
119: * - namespace:
120: * - soapaction:
121: * - from: SMTP, from address
122: * - transfer-encoding: SMTP, sets the
123: * Content-Transfer-Encoding header
124: * - subject: SMTP, subject header
125: * - headers: SMTP, array-hash of extra smtp
126: * headers
127: *
128: * @return mixed The returned result from the method
129: * @throws Horde_Rpc_Exception
130: */
131: public static function request($url, $method, $params = null, $soap)
132: {
133: try {
134: return $soap->__soapCall($method, $params);
135: } catch (Exception $e) {
136: throw new Horde_Rpc_Exception($e);
137: }
138: }
139:
140: }
141:
142: class Horde_Rpc_Soap_Caller {
143:
144: /**
145: * List of method names to allow.
146: *
147: * @var array
148: */
149: protected $_allowedMethods = array();
150:
151: /**
152: */
153: public function __construct($params = array())
154: {
155: if (!empty($params['allowedMethods'])) {
156: $this->_allowedMethods = $params['allowedMethods'];
157: }
158: }
159:
160: /**
161: * Will be registered as the handler for all methods called in the
162: * SOAP server and will call the appropriate function through the registry.
163: *
164: * @todo PEAR SOAP operates on a copy of this object at some unknown
165: * point and therefore doesn't have access to instance
166: * variables if they're set here. Instead, globals are used
167: * to track the method name and args for the logging code.
168: * Once this is PHP 5-only, the globals can go in favor of
169: * instance variables.
170: *
171: * @access private
172: *
173: * @param string $method The name of the method called by the RPC request.
174: * @param array $params The passed parameters.
175: * @param mixed $data Unknown.
176: *
177: * @return mixed The result of the called registry method.
178: */
179: public function __call($method, $params)
180: {
181: $method = str_replace('.', '/', $method);
182:
183: if (!empty($this->_params['allowedMethods']) &&
184: !in_array($method, $this->_params['allowedMethods'])) {
185: return sprintf(Horde_Rpc_Translation::t("Method \"%s\" is not defined"), $method);
186: }
187:
188: $GLOBALS['__horde_rpc_PhpSoap']['lastMethodCalled'] = $method;
189: $GLOBALS['__horde_rpc_PhpSoap']['lastMethodParams'] =
190: !empty($params) ? $params : array();
191:
192: if (!$GLOBALS['registry']->hasMethod($method)) {
193: return sprintf(Horde_Rpc_Translation::t("Method \"%s\" is not defined"), $method);
194: }
195:
196: return $GLOBALS['registry']->call($method, $params);
197: }
198:
199: }
200: