ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 
12 namespace Monolog\Handler;
13 
14 use Monolog\Logger;
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;
33  private $lastWritingAt;
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  {
177  return $this->writingTimeout;
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 }
getConnectionString()
Get current connection string.
const DEBUG
Detailed debug information.
Definition: Logger.php:32
setTimeout($seconds)
Set write timeout.
Stores to any socket - uses fsockopen() or pfsockopen().
setWritingTimeout($seconds)
Set writing timeout.
Base Handler class providing the Handler structure.
__construct($connectionString, $level=Logger::DEBUG, $bubble=true)
fwrite($data)
Wrapper to allow mocking.
isConnected()
Check to see if the socket is currently available.
write(array $record)
Connect (if necessary) and write to the socket.
fsockopen()
Wrapper to allow mocking.
close()
We will not close a PersistentSocket instance so it can be reused in other requests.
Create styles array
The data for the language used.
streamSetTimeout()
Wrapper to allow mocking.
isPersistent()
Get persistent setting.
setConnectionTimeout($seconds)
Set connection timeout.
pfsockopen()
Wrapper to allow mocking.
getWritingTimeout()
Get current local writing timeout.
getConnectionTimeout()
Get current connection timeout setting.
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
setPersistent($persistent)
Set socket connection to nbe persistent.
getTimeout()
Get current in-transfer timeout.
closeSocket()
Close socket, if open.
streamGetMetadata()
Wrapper to allow mocking.