PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/application/third_party/google-api/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php

https://gitlab.com/Anas7232/Layout-Changes
PHP | 379 lines | 223 code | 48 blank | 108 comment | 27 complexity | c7c1c6d6a65149b55b06c51158b90521 MD5 | raw file
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of the Monolog package.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Monolog\Handler;
  11. use Monolog\Logger;
  12. /**
  13. * Stores to any socket - uses fsockopen() or pfsockopen().
  14. *
  15. * @author Pablo de Leon Belloc <pablolb@gmail.com>
  16. * @see http://php.net/manual/en/function.fsockopen.php
  17. */
  18. class SocketHandler extends AbstractProcessingHandler
  19. {
  20. private $connectionString;
  21. private $connectionTimeout;
  22. /** @var resource|null */
  23. private $resource;
  24. /** @var float */
  25. private $timeout = 0;
  26. /** @var float */
  27. private $writingTimeout = 10;
  28. private $lastSentBytes = null;
  29. /** @var int */
  30. private $chunkSize = null;
  31. private $persistent = false;
  32. private $errno;
  33. private $errstr;
  34. private $lastWritingAt;
  35. /**
  36. * @param string $connectionString Socket connection string
  37. * @param int|string $level The minimum logging level at which this handler will be triggered
  38. * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
  39. */
  40. public function __construct(string $connectionString, $level = Logger::DEBUG, bool $bubble = true)
  41. {
  42. parent::__construct($level, $bubble);
  43. $this->connectionString = $connectionString;
  44. $this->connectionTimeout = (float) ini_get('default_socket_timeout');
  45. }
  46. /**
  47. * Connect (if necessary) and write to the socket
  48. *
  49. * @param array $record
  50. *
  51. * @throws \UnexpectedValueException
  52. * @throws \RuntimeException
  53. */
  54. protected function write(array $record): void
  55. {
  56. $this->connectIfNotConnected();
  57. $data = $this->generateDataStream($record);
  58. $this->writeToSocket($data);
  59. }
  60. /**
  61. * We will not close a PersistentSocket instance so it can be reused in other requests.
  62. */
  63. public function close(): void
  64. {
  65. if (!$this->isPersistent()) {
  66. $this->closeSocket();
  67. }
  68. }
  69. /**
  70. * Close socket, if open
  71. */
  72. public function closeSocket(): void
  73. {
  74. if (is_resource($this->resource)) {
  75. fclose($this->resource);
  76. $this->resource = null;
  77. }
  78. }
  79. /**
  80. * Set socket connection to be persistent. It only has effect before the connection is initiated.
  81. */
  82. public function setPersistent(bool $persistent): self
  83. {
  84. $this->persistent = $persistent;
  85. return $this;
  86. }
  87. /**
  88. * Set connection timeout. Only has effect before we connect.
  89. *
  90. * @see http://php.net/manual/en/function.fsockopen.php
  91. */
  92. public function setConnectionTimeout(float $seconds): self
  93. {
  94. $this->validateTimeout($seconds);
  95. $this->connectionTimeout = $seconds;
  96. return $this;
  97. }
  98. /**
  99. * Set write timeout. Only has effect before we connect.
  100. *
  101. * @see http://php.net/manual/en/function.stream-set-timeout.php
  102. */
  103. public function setTimeout(float $seconds): self
  104. {
  105. $this->validateTimeout($seconds);
  106. $this->timeout = $seconds;
  107. return $this;
  108. }
  109. /**
  110. * Set writing timeout. Only has effect during connection in the writing cycle.
  111. *
  112. * @param float $seconds 0 for no timeout
  113. */
  114. public function setWritingTimeout(float $seconds): self
  115. {
  116. $this->validateTimeout($seconds);
  117. $this->writingTimeout = $seconds;
  118. return $this;
  119. }
  120. /**
  121. * Set chunk size. Only has effect during connection in the writing cycle.
  122. */
  123. public function setChunkSize(int $bytes): self
  124. {
  125. $this->chunkSize = $bytes;
  126. return $this;
  127. }
  128. /**
  129. * Get current connection string
  130. */
  131. public function getConnectionString(): string
  132. {
  133. return $this->connectionString;
  134. }
  135. /**
  136. * Get persistent setting
  137. */
  138. public function isPersistent(): bool
  139. {
  140. return $this->persistent;
  141. }
  142. /**
  143. * Get current connection timeout setting
  144. */
  145. public function getConnectionTimeout(): float
  146. {
  147. return $this->connectionTimeout;
  148. }
  149. /**
  150. * Get current in-transfer timeout
  151. */
  152. public function getTimeout(): float
  153. {
  154. return $this->timeout;
  155. }
  156. /**
  157. * Get current local writing timeout
  158. *
  159. * @return float
  160. */
  161. public function getWritingTimeout(): float
  162. {
  163. return $this->writingTimeout;
  164. }
  165. /**
  166. * Get current chunk size
  167. */
  168. public function getChunkSize(): int
  169. {
  170. return $this->chunkSize;
  171. }
  172. /**
  173. * Check to see if the socket is currently available.
  174. *
  175. * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details.
  176. */
  177. public function isConnected(): bool
  178. {
  179. return is_resource($this->resource)
  180. && !feof($this->resource); // on TCP - other party can close connection.
  181. }
  182. /**
  183. * Wrapper to allow mocking
  184. */
  185. protected function pfsockopen()
  186. {
  187. return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
  188. }
  189. /**
  190. * Wrapper to allow mocking
  191. */
  192. protected function fsockopen()
  193. {
  194. return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
  195. }
  196. /**
  197. * Wrapper to allow mocking
  198. *
  199. * @see http://php.net/manual/en/function.stream-set-timeout.php
  200. */
  201. protected function streamSetTimeout()
  202. {
  203. $seconds = floor($this->timeout);
  204. $microseconds = round(($this->timeout - $seconds) * 1e6);
  205. return stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds);
  206. }
  207. /**
  208. * Wrapper to allow mocking
  209. *
  210. * @see http://php.net/manual/en/function.stream-set-chunk-size.php
  211. */
  212. protected function streamSetChunkSize()
  213. {
  214. return stream_set_chunk_size($this->resource, $this->chunkSize);
  215. }
  216. /**
  217. * Wrapper to allow mocking
  218. */
  219. protected function fwrite($data)
  220. {
  221. return @fwrite($this->resource, $data);
  222. }
  223. /**
  224. * Wrapper to allow mocking
  225. */
  226. protected function streamGetMetadata()
  227. {
  228. return stream_get_meta_data($this->resource);
  229. }
  230. private function validateTimeout($value)
  231. {
  232. $ok = filter_var($value, FILTER_VALIDATE_FLOAT);
  233. if ($ok === false || $value < 0) {
  234. throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
  235. }
  236. }
  237. private function connectIfNotConnected()
  238. {
  239. if ($this->isConnected()) {
  240. return;
  241. }
  242. $this->connect();
  243. }
  244. protected function generateDataStream(array $record): string
  245. {
  246. return (string) $record['formatted'];
  247. }
  248. /**
  249. * @return resource|null
  250. */
  251. protected function getResource()
  252. {
  253. return $this->resource;
  254. }
  255. private function connect(): void
  256. {
  257. $this->createSocketResource();
  258. $this->setSocketTimeout();
  259. $this->setStreamChunkSize();
  260. }
  261. private function createSocketResource(): void
  262. {
  263. if ($this->isPersistent()) {
  264. $resource = $this->pfsockopen();
  265. } else {
  266. $resource = $this->fsockopen();
  267. }
  268. if (!$resource) {
  269. throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
  270. }
  271. $this->resource = $resource;
  272. }
  273. private function setSocketTimeout(): void
  274. {
  275. if (!$this->streamSetTimeout()) {
  276. throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
  277. }
  278. }
  279. private function setStreamChunkSize(): void
  280. {
  281. if ($this->chunkSize && !$this->streamSetChunkSize()) {
  282. throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()");
  283. }
  284. }
  285. private function writeToSocket(string $data): void
  286. {
  287. $length = strlen($data);
  288. $sent = 0;
  289. $this->lastSentBytes = $sent;
  290. while ($this->isConnected() && $sent < $length) {
  291. if (0 == $sent) {
  292. $chunk = $this->fwrite($data);
  293. } else {
  294. $chunk = $this->fwrite(substr($data, $sent));
  295. }
  296. if ($chunk === false) {
  297. throw new \RuntimeException("Could not write to socket");
  298. }
  299. $sent += $chunk;
  300. $socketInfo = $this->streamGetMetadata();
  301. if ($socketInfo['timed_out']) {
  302. throw new \RuntimeException("Write timed-out");
  303. }
  304. if ($this->writingIsTimedOut($sent)) {
  305. throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent $sent of $length)");
  306. }
  307. }
  308. if (!$this->isConnected() && $sent < $length) {
  309. throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
  310. }
  311. }
  312. private function writingIsTimedOut(int $sent): bool
  313. {
  314. $writingTimeout = (int) floor($this->writingTimeout);
  315. if (0 === $writingTimeout) {
  316. return false;
  317. }
  318. if ($sent !== $this->lastSentBytes) {
  319. $this->lastWritingAt = time();
  320. $this->lastSentBytes = $sent;
  321. return false;
  322. } else {
  323. usleep(100);
  324. }
  325. if ((time() - $this->lastWritingAt) >= $writingTimeout) {
  326. $this->closeSocket();
  327. return true;
  328. }
  329. return false;
  330. }
  331. }