1 <?php
2 /**
3 * This file is part of the kerio-api-php.
4 *
5 * Copyright (c) Kerio Technologies s.r.o.
6 *
7 * For the full copyright and license information, please view
8 * the file license.txt that was distributed with this source code
9 * or visit Developer Zone. (http://www.kerio.com/developers)
10 *
11 * Do not modify this source code.
12 * Any changes may be overwritten by a new version.
13 */
14
15 require_once(dirname(__FILE__) . '/KerioApiSocketInterface.php');
16
17 /**
18 * Kerio API Socket Class.
19 *
20 * This class implements basic methods used in HTTP communication.
21 *
22 * @copyright Copyright © 2012-2012 Kerio Technologies s.r.o.
23 * @license http://www.kerio.com/developers/license/sdk-agreement
24 * @version 1.3.0.62
25 */
26 class KerioApiSocket implements KerioApiSocketInterface {
27
28 /**
29 * Socket buffer size
30 */
31 const BUFFER_SIZE = 5120;
32
33 /**
34 * Socket handler
35 * @var resource
36 */
37 private $socketHandler = '';
38
39 /**
40 * Communication timeout
41 * @var integer
42 */
43 private $timeout = 3;
44
45 /**
46 * Server hostname
47 * @var string
48 */
49 private $hostname = '';
50
51 /**
52 * Server port
53 * @var integer
54 */
55 private $port = '';
56
57 /**
58 * SSL encryption
59 * @var string
60 */
61 private $cipher = 'ssl://';
62
63 /**
64 * Headers
65 * @var string
66 */
67 private $headers = '';
68
69 /**
70 * Body
71 * @var string
72 */
73 private $body = '';
74
75 /**
76 * Socker error message
77 * @var string
78 */
79 private $errorMessage = '';
80
81 /**
82 * Socker error code
83 * @var integer
84 */
85 private $errorCode = 0;
86
87 /**
88 * Class constructor.
89 *
90 * @param string Hostname
91 * @param integer Port
92 * @param integer Timeout, optional
93 * @return boolean True on success
94 */
95 public function KerioApiSocket($hostname, $port, $timeout = '') {
96 /* Set host */
97 $this->hostname = $hostname;
98 $this->port = $port;
99
100 /* Set timeout */
101 if (is_int($timeout)) {
102 $this->timeout = $timeout;
103 }
104
105 /* Open socket to server */
106 $this->open();
107 return ($this->socketHandler) ? TRUE : FALSE;
108 }
109
110 /**
111 * Class desctructor.
112 *
113 * @param void
114 * @return void
115 */
116 public function __destruct() {
117 $this->close();
118 }
119
120 /**
121 * Open socket to server.
122 *
123 * @param void
124 * @return void
125 */
126 protected function open() {
127 $this->socketHandler = @fsockopen($this->cipher . $this->hostname, $this->port, $errno, $errstr, $this->timeout);
128 $this->errorCode = $errno;
129 $this->errorMessage = $errstr;
130 }
131
132 /**
133 * Close socket to server.
134 *
135 * @param void
136 * @return void
137 */
138 protected function close() {
139 @fclose($this->socketHandler);
140 unset($this->socketHandler);
141 }
142
143 /**
144 * Send data to socket.
145 *
146 * @see class/KerioApiSocketInterface::send()
147 * @param string Data to socket
148 * @return string Data from socket
149 * @throws KerioApiException
150 */
151 public function send($data) {
152 if ($this->checkConnection()) {
153 @fwrite($this->socketHandler, $data);
154 return $this->read();
155 }
156 else {
157 throw new KerioApiException(sprintf("Cannot connect to %s using port %d.", $this->hostname, $this->port));
158 }
159 }
160
161 /**
162 * Read data from socket.
163 *
164 * @param void
165 * @return string HTTP data from socket
166 * @throws KerioApiExceptions
167 */
168 protected function read() {
169 if ($this->socketHandler) {
170 $response = '';
171 while (FALSE === feof($this->socketHandler)) {
172 $response .= fgets($this->socketHandler, self::BUFFER_SIZE);
173 }
174
175 list($this->headers, $this->body) = explode("\r\n\r\n", $response);
176
177 if (FALSE !== strpos(strtolower($this->headers), 'transfer-encoding: chunked')) {
178 $this->unchunkHttp();
179 }
180
181 return $response;
182 }
183 else {
184 throw new KerioApiException('Cannot read data from server, connection timeout.');
185 }
186 }
187
188 /**
189 * Unchunk HTTP/1.1 body.
190 *
191 * @param void
192 * @return void
193 */
194 private function unchunkHttp() {
195 $body = $this->body;
196 for ($new = ''; !empty($body); $str = trim($body)) {
197 $pos = strpos($body, "\r\n");
198 $len = hexdec(substr($body, 0, $pos));
199 $new .= substr($body, $pos + 2, $len);
200 $body = substr($body, $pos + 2 + $len);
201 }
202 $this->body = $new;
203 }
204
205 /**
206 * Set connection encryption to ssl://
207 *
208 * @param boolen True if ssl:// is used
209 * @return void
210 */
211 public function setEncryption($boolean) {
212 $this->cipher = ($boolean) ? 'ssl://' : '';
213 }
214
215 /**
216 * Check connection to server.
217 *
218 * @param void
219 * @return boolean True on success
220 */
221 public final function checkConnection() {
222 if ($this->checkHost()) {
223 $socket = @fsockopen($this->hostname, $this->port, $errno, $errstr, $this->timeout);
224 $this->errorCode = $errno;
225 $this->errorMessage = $errstr;
226 return ($socket) ? TRUE : FALSE;
227 }
228 else {
229 return FALSE;
230 }
231 }
232
233 /**
234 * Check if DNS host is valid.
235 *
236 * @param void
237 * @return boolean True on success
238 */
239 public final function checkHost() {
240 return gethostbyname($this->hostname) ? TRUE : FALSE;
241 }
242
243 /**
244 * Get headers.
245 *
246 * @param void
247 * @return string
248 */
249 public final function getHeaders() {
250 return $this->headers;
251 }
252
253 /**
254 * Get body.
255 *
256 * @param void
257 * @return string
258 */
259 public final function getBody() {
260 return $this->body;
261 }
262
263 /**
264 * Get socker error message.
265 *
266 * @param void
267 * @return string
268 */
269 public final function getErrorMessage() {
270 return $this->errorMessage;
271 }
272
273 /**
274 * Get socket error code.
275 *
276 * @param void
277 * @return integer
278 */
279 public final function getErrorCode() {
280 return $this->errorCode;
281 }
282 }
283
284