ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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 $chunkSize = null;
31 private $persistent = false;
32 private $errno;
33 private $errstr;
35
42 {
43 parent::__construct($level, $bubble);
44 $this->connectionString = $connectionString;
45 $this->connectionTimeout = (float) ini_get('default_socket_timeout');
46 }
47
56 protected function write(array $record)
57 {
58 $this->connectIfNotConnected();
59 $data = $this->generateDataStream($record);
60 $this->writeToSocket($data);
61 }
62
66 public function close()
67 {
68 if (!$this->isPersistent()) {
69 $this->closeSocket();
70 }
71 }
72
76 public function closeSocket()
77 {
78 if (is_resource($this->resource)) {
79 fclose($this->resource);
80 $this->resource = null;
81 }
82 }
83
89 public function setPersistent($persistent)
90 {
91 $this->persistent = (bool) $persistent;
92 }
93
101 public function setConnectionTimeout($seconds)
102 {
103 $this->validateTimeout($seconds);
104 $this->connectionTimeout = (float) $seconds;
105 }
106
114 public function setTimeout($seconds)
115 {
116 $this->validateTimeout($seconds);
117 $this->timeout = (float) $seconds;
118 }
119
125 public function setWritingTimeout($seconds)
126 {
127 $this->validateTimeout($seconds);
128 $this->writingTimeout = (float) $seconds;
129 }
130
136 public function setChunkSize($bytes)
137 {
138 $this->chunkSize = $bytes;
139 }
140
146 public function getConnectionString()
147 {
149 }
150
156 public function isPersistent()
157 {
158 return $this->persistent;
159 }
160
166 public function getConnectionTimeout()
167 {
169 }
170
176 public function getTimeout()
177 {
178 return $this->timeout;
179 }
180
186 public function getWritingTimeout()
187 {
189 }
190
196 public function getChunkSize()
197 {
198 return $this->chunkSize;
199 }
200
208 public function isConnected()
209 {
210 return is_resource($this->resource)
211 && !feof($this->resource); // on TCP - other party can close connection.
212 }
213
217 protected function pfsockopen()
218 {
219 return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
220 }
221
225 protected function fsockopen()
226 {
227 return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
228 }
229
235 protected function streamSetTimeout()
236 {
237 $seconds = floor($this->timeout);
238 $microseconds = round(($this->timeout - $seconds) * 1e6);
239
240 return stream_set_timeout($this->resource, $seconds, $microseconds);
241 }
242
248 protected function streamSetChunkSize()
249 {
250 return stream_set_chunk_size($this->resource, $this->chunkSize);
251 }
252
256 protected function fwrite($data)
257 {
258 return @fwrite($this->resource, $data);
259 }
260
264 protected function streamGetMetadata()
265 {
266 return stream_get_meta_data($this->resource);
267 }
268
269 private function validateTimeout($value)
270 {
271 $ok = filter_var($value, FILTER_VALIDATE_FLOAT);
272 if ($ok === false || $value < 0) {
273 throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
274 }
275 }
276
277 private function connectIfNotConnected()
278 {
279 if ($this->isConnected()) {
280 return;
281 }
282 $this->connect();
283 }
284
285 protected function generateDataStream($record)
286 {
287 return (string) $record['formatted'];
288 }
289
293 protected function getResource()
294 {
295 return $this->resource;
296 }
297
298 private function connect()
299 {
300 $this->createSocketResource();
301 $this->setSocketTimeout();
302 $this->setStreamChunkSize();
303 }
304
305 private function createSocketResource()
306 {
307 if ($this->isPersistent()) {
308 $resource = $this->pfsockopen();
309 } else {
310 $resource = $this->fsockopen();
311 }
312 if (!$resource) {
313 throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
314 }
315 $this->resource = $resource;
316 }
317
318 private function setSocketTimeout()
319 {
320 if (!$this->streamSetTimeout()) {
321 throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
322 }
323 }
324
325 private function setStreamChunkSize()
326 {
327 if ($this->chunkSize && !$this->streamSetChunkSize()) {
328 throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()");
329 }
330 }
331
332 private function writeToSocket($data)
333 {
334 $length = strlen($data);
335 $sent = 0;
336 $this->lastSentBytes = $sent;
337 while ($this->isConnected() && $sent < $length) {
338 if (0 == $sent) {
339 $chunk = $this->fwrite($data);
340 } else {
341 $chunk = $this->fwrite(substr($data, $sent));
342 }
343 if ($chunk === false) {
344 throw new \RuntimeException("Could not write to socket");
345 }
346 $sent += $chunk;
347 $socketInfo = $this->streamGetMetadata();
348 if ($socketInfo['timed_out']) {
349 throw new \RuntimeException("Write timed-out");
350 }
351
352 if ($this->writingIsTimedOut($sent)) {
353 throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent $sent of $length)");
354 }
355 }
356 if (!$this->isConnected() && $sent < $length) {
357 throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
358 }
359 }
360
361 private function writingIsTimedOut($sent)
362 {
363 $writingTimeout = (int) floor($this->writingTimeout);
364 if (0 === $writingTimeout) {
365 return false;
366 }
367
368 if ($sent !== $this->lastSentBytes) {
369 $this->lastWritingAt = time();
370 $this->lastSentBytes = $sent;
371
372 return false;
373 } else {
374 usleep(100);
375 }
376
377 if ((time() - $this->lastWritingAt) >= $writingTimeout) {
378 $this->closeSocket();
379
380 return true;
381 }
382
383 return false;
384 }
385}
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.
streamSetChunkSize()
Wrapper to allow mocking.
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.
setChunkSize($bytes)
Set chunk size.
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.
getChunkSize()
Get current chunk size.
closeSocket()
Close socket, if open.
Monolog log channel.
Definition: Logger.php:29
const DEBUG
Detailed debug information.
Definition: Logger.php:33
$data
Definition: bench.php:6