1: <?php
2:
3: /**
4: * Jyxo PHP Library
5: *
6: * LICENSE
7: *
8: * This source file is subject to the new BSD license that is bundled
9: * with this package in the file license.txt.
10: * It is also available through the world-wide-web at this URL:
11: * https://github.com/jyxo/php/blob/master/license.txt
12: */
13:
14: /**
15: * Abstract class for sending RPC requests.
16: *
17: * @category Jyxo
18: * @package Jyxo_Rpc
19: * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
20: * @license https://github.com/jyxo/php/blob/master/license.txt
21: * @author Jaroslav HanslĂk
22: */
23: abstract class Jyxo_Rpc_Client
24: {
25: /**
26: * Server address.
27: *
28: * @var string
29: */
30: protected $url = '';
31:
32: /**
33: * Time limit for communication with RPC server (seconds).
34: *
35: * @var integer
36: */
37: protected $timeout = 5;
38:
39: /**
40: * Parameters for creating RPC requests.
41: *
42: * @var array
43: */
44: protected $options = array();
45:
46: /**
47: * Timer name.
48: *
49: * @var string
50: */
51: private $timer = '';
52:
53: /**
54: * Whether to use request profiler.
55: *
56: * @var boolean
57: */
58: private $profiler = false;
59:
60: /**
61: * Creates client instance and eventually sets server address.
62: *
63: * @param string $url Server address
64: */
65: public function __construct($url = '')
66: {
67: if (!empty($url)) {
68: $this->setUrl($url);
69: }
70: }
71:
72: /**
73: * Sets server address.
74: *
75: * @param string $url Server address
76: * @return Jyxo_Rpc_Client
77: */
78: public function setUrl($url)
79: {
80: $this->url = (string) $url;
81:
82: return $this;
83: }
84:
85: /**
86: * Sets timeout.
87: *
88: * @param integer $timeout Call timeout
89: * @return Jyxo_Rpc_Client
90: */
91: public function setTimeout($timeout)
92: {
93: $this->timeout = (int) $timeout;
94:
95: return $this;
96: }
97:
98: /**
99: * Changes client settings.
100: *
101: * @param string $key Parameter name
102: * @param mixed $value Parameter value
103: * @return Jyxo_Rpc_Client
104: */
105: public function setOption($key, $value)
106: {
107: if (isset($this->options[$key])) {
108: $this->options[$key] = $value;
109: }
110: return $this;
111: }
112:
113: /**
114: * Returns certain parameter or whole array of parameters if no parameter name is provided.
115: *
116: * @param string $key Parameter name
117: * @return mixed
118: */
119: public function getOption($key = '')
120: {
121: if (isset($this->options[$key])) {
122: return $this->options[$key];
123: }
124: return $this->options;
125: }
126:
127: /**
128: * Turns request profiler on.
129: *
130: * @return Jyxo_Rpc_Client
131: */
132: public function enableProfiler()
133: {
134: $this->profiler = true;
135: return $this;
136: }
137:
138: /**
139: * Turns request profiler off.
140: *
141: * @return Jyxo_Rpc_Client
142: */
143: public function disableProfiler()
144: {
145: $this->profiler = false;
146: return $this;
147: }
148:
149: /**
150: * Sends a request and fetches a response from the server.
151: *
152: * @param string $method Method name
153: * @param array $params Method parameters
154: * @return mixed
155: * @throws BadMethodCallException If no server address was provided
156: * @throws Jyxo_Rpc_Exception On error
157: */
158: abstract public function send($method, array $params);
159:
160: /**
161: * Processes request data and fetches response.
162: *
163: * @param string $contentType Request content-type
164: * @param string $data Request data
165: * @return string
166: * @throws BadMethodCallException If no server address was provided
167: * @throws Jyxo_Rpc_Exception On error
168: */
169: protected function process($contentType, $data)
170: {
171: // Server address must be defined
172: if (empty($this->url)) {
173: throw new BadMethodCallException('No server address was provided.');
174: }
175:
176: // Headers
177: $headers = array(
178: 'Content-Type: ' . $contentType,
179: 'Content-Length: ' . strlen($data)
180: );
181:
182: // Open a HTTP channel
183: $channel = curl_init();
184: curl_setopt($channel, CURLOPT_URL, $this->url);
185: curl_setopt($channel, CURLOPT_RETURNTRANSFER, true);
186: curl_setopt($channel, CURLOPT_CONNECTTIMEOUT, 0);
187: curl_setopt($channel, CURLOPT_TIMEOUT, $this->timeout);
188: curl_setopt($channel, CURLOPT_HTTPHEADER, $headers);
189: curl_setopt($channel, CURLOPT_POSTFIELDS, $data);
190:
191: // Send a request
192: $response = curl_exec($channel);
193:
194: // Error sending the request
195: if (0 !== curl_errno($channel)) {
196: $error = curl_error($channel);
197: curl_close($channel);
198:
199: throw new Jyxo_Rpc_Exception($error);
200: }
201:
202: // Wrong code
203: $code = curl_getinfo($channel, CURLINFO_HTTP_CODE);
204: if ($code >= 300) {
205: $error = sprintf('Response error from %s, code %d.', $this->url, $code);
206: curl_close($channel);
207:
208: throw new Jyxo_Rpc_Exception($error);
209: }
210:
211: // Close the channel
212: curl_close($channel);
213:
214: // Return the response
215: return $response;
216: }
217:
218: /**
219: * Starts profiling.
220: *
221: * @return Jyxo_Rpc_Client
222: */
223: protected function profileStart()
224: {
225: // Set start time
226: if ($this->profiler) {
227: $this->timer = Jyxo_Timer::start();
228: }
229:
230: return $this;
231: }
232:
233: /**
234: * Finishes profiling.
235: *
236: * @param string $type Request type
237: * @param string $method Method name
238: * @param array $params Method parameters
239: * @param mixed $response Server response
240: * @return Jyxo_Rpc_Client
241: */
242: protected function profileEnd($type, $method, array $params, $response)
243: {
244: // Profiling has to be turned on
245: if ($this->profiler) {
246: static $totalTime = 0;
247: static $requests = array();
248:
249: // Get elapsed time
250: $time = Jyxo_Timer::stop($this->timer);
251:
252: $totalTime += $time;
253: $requests[] = array(strtoupper($type), (string) $method, $params, $response, sprintf('%0.3f', $time * 1000));
254:
255: // Send to FirePHP
256: Jyxo_FirePhp::table(
257: sprintf('Jyxo RPC Profiler (%d requests took %0.3f ms)', count($requests), sprintf('%0.3f', $totalTime * 1000)),
258: array('Type', 'Method', 'Request', 'Response', 'Time'),
259: $requests,
260: 'Rpc'
261: );
262: }
263:
264: return $this;
265: }
266: }
267: