ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
SocketHandler.php
Go to the documentation of this file.
1<?php
2
3/*
4 * This file is part of the Monolog package.
5 *
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Monolog\Handler;
13
15
23{
26 private $resource;
27 private $timeout = 0;
28 private $writingTimeout = 10;
29 private $lastSentBytes = null;
30 private $persistent = false;
31 private $errno;
32 private $errstr;
34
41 {
42 parent::__construct($level, $bubble);
43 $this->connectionString = $connectionString;
44 $this->connectionTimeout = (float) ini_get('default_socket_timeout');
45 }
46
55 protected function write(array $record)
56 {
57 $this->connectIfNotConnected();
58 $data = $this->generateDataStream($record);
59 $this->writeToSocket($data);
60 }
61
65 public function close()
66 {
67 if (!$this->isPersistent()) {
68 $this->closeSocket();
69 }
70 }
71
75 public function closeSocket()
76 {
77 if (is_resource($this->resource)) {
78 fclose($this->resource);
79 $this->resource = null;
80 }
81 }
82
88 public function setPersistent($persistent)
89 {
90 $this->persistent = (boolean) $persistent;
91 }
92
100 public function setConnectionTimeout($seconds)
101 {
102 $this->validateTimeout($seconds);
103 $this->connectionTimeout = (float) $seconds;
104 }
105
113 public function setTimeout($seconds)
114 {
115 $this->validateTimeout($seconds);
116 $this->timeout = (float) $seconds;
117 }
118
124 public function setWritingTimeout($seconds)
125 {
126 $this->validateTimeout($seconds);
127 $this->writingTimeout = (float) $seconds;
128 }
129
135 public function getConnectionString()
136 {
138 }
139
145 public function isPersistent()
146 {
147 return $this->persistent;
148 }
149
155 public function getConnectionTimeout()
156 {
158 }
159
165 public function getTimeout()
166 {
167 return $this->timeout;
168 }
169
175 public function getWritingTimeout()
176 {
178 }
179
187 public function isConnected()
188 {
189 return is_resource($this->resource)
190 && !feof($this->resource); // on TCP - other party can close connection.
191 }
192
196 protected function pfsockopen()
197 {
198 return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
199 }
200
204 protected function fsockopen()
205 {
206 return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
207 }
208
214 protected function streamSetTimeout()
215 {
216 $seconds = floor($this->timeout);
217 $microseconds = round(($this->timeout - $seconds) * 1e6);
218
219 return stream_set_timeout($this->resource, $seconds, $microseconds);
220 }
221
225 protected function fwrite($data)
226 {
227 return @fwrite($this->resource, $data);
228 }
229
233 protected function streamGetMetadata()
234 {
235 return stream_get_meta_data($this->resource);
236 }
237
238 private function validateTimeout($value)
239 {
240 $ok = filter_var($value, FILTER_VALIDATE_FLOAT);
241 if ($ok === false || $value < 0) {
242 throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
243 }
244 }
245
246 private function connectIfNotConnected()
247 {
248 if ($this->isConnected()) {
249 return;
250 }
251 $this->connect();
252 }
253
254 protected function generateDataStream($record)
255 {
256 return (string) $record['formatted'];
257 }
258
262 protected function getResource()
263 {
264 return $this->resource;
265 }
266
267 private function connect()
268 {
269 $this->createSocketResource();
270 $this->setSocketTimeout();
271 }
272
273 private function createSocketResource()
274 {
275 if ($this->isPersistent()) {
276 $resource = $this->pfsockopen();
277 } else {
278 $resource = $this->fsockopen();
279 }
280 if (!$resource) {
281 throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
282 }
283 $this->resource = $resource;
284 }
285
286 private function setSocketTimeout()
287 {
288 if (!$this->streamSetTimeout()) {
289 throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
290 }
291 }
292
293 private function writeToSocket($data)
294 {
295 $length = strlen($data);
296 $sent = 0;
297 $this->lastSentBytes = $sent;
298 while ($this->isConnected() && $sent < $length) {
299 if (0 == $sent) {
300 $chunk = $this->fwrite($data);
301 } else {
302 $chunk = $this->fwrite(substr($data, $sent));
303 }
304 if ($chunk === false) {
305 throw new \RuntimeException("Could not write to socket");
306 }
307 $sent += $chunk;
308 $socketInfo = $this->streamGetMetadata();
309 if ($socketInfo['timed_out']) {
310 throw new \RuntimeException("Write timed-out");
311 }
312
313 if ($this->writingIsTimedOut($sent)) {
314 throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent $sent of $length)");
315 }
316 }
317 if (!$this->isConnected() && $sent < $length) {
318 throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
319 }
320 }
321
322 private function writingIsTimedOut($sent)
323 {
324 $writingTimeout = (int) floor($this->writingTimeout);
325 if (0 === $writingTimeout) {
326 return false;
327 }
328
329 if ($sent !== $this->lastSentBytes) {
330 $this->lastWritingAt = time();
331 $this->lastSentBytes = $sent;
332
333 return false;
334 } else {
335 usleep(100);
336 }
337
338 if ((time() - $this->lastWritingAt) >= $writingTimeout) {
339 $this->closeSocket();
340
341 return true;
342 }
343
344 return false;
345 }
346}
An exception for terminatinating execution or to throw for unit testing.
Base Handler class providing the Handler structure.
Stores to any socket - uses fsockopen() or pfsockopen().
setTimeout($seconds)
Set write timeout.
streamSetTimeout()
Wrapper to allow mocking.
fwrite($data)
Wrapper to allow mocking.
write(array $record)
Connect (if necessary) and write to the socket.
getWritingTimeout()
Get current local writing timeout.
isConnected()
Check to see if the socket is currently available.
pfsockopen()
Wrapper to allow mocking.
fsockopen()
Wrapper to allow mocking.
getConnectionString()
Get current connection string.
setConnectionTimeout($seconds)
Set connection timeout.
close()
We will not close a PersistentSocket instance so it can be reused in other requests.
getConnectionTimeout()
Get current connection timeout setting.
streamGetMetadata()
Wrapper to allow mocking.
setPersistent($persistent)
Set socket connection to nbe persistent.
__construct($connectionString, $level=Logger::DEBUG, $bubble=true)
isPersistent()
Get persistent setting.
getTimeout()
Get current in-transfer timeout.
setWritingTimeout($seconds)
Set writing timeout.
closeSocket()
Close socket, if open.
Monolog log channel.
Definition: Logger.php:28
const DEBUG
Detailed debug information.
Definition: Logger.php:32