vendor/symfony/var-dumper/Server/DumpServer.php line 35

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  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 Symfony\Component\VarDumper\Server;
  11. use Psr\Log\LoggerInterface;
  12. use Symfony\Component\VarDumper\Cloner\Data;
  13. use Symfony\Component\VarDumper\Cloner\Stub;
  14. /**
  15.  * A server collecting Data clones sent by a ServerDumper.
  16.  *
  17.  * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
  18.  *
  19.  * @final
  20.  */
  21. class DumpServer
  22. {
  23.     private $host;
  24.     private $logger;
  25.     /**
  26.      * @var resource|null
  27.      */
  28.     private $socket;
  29.     public function __construct(string $hostLoggerInterface $logger null)
  30.     {
  31.         if (!str_contains($host'://')) {
  32.             $host 'tcp://'.$host;
  33.         }
  34.         $this->host $host;
  35.         $this->logger $logger;
  36.     }
  37.     public function start(): void
  38.     {
  39.         if (!$this->socket stream_socket_server($this->host$errno$errstr)) {
  40.             throw new \RuntimeException(sprintf('Server start failed on "%s": '$this->host).$errstr.' '.$errno);
  41.         }
  42.     }
  43.     public function listen(callable $callback): void
  44.     {
  45.         if (null === $this->socket) {
  46.             $this->start();
  47.         }
  48.         foreach ($this->getMessages() as $clientId => $message) {
  49.             if ($this->logger) {
  50.                 $this->logger->info('Received a payload from client {clientId}', ['clientId' => $clientId]);
  51.             }
  52.             $payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);
  53.             // Impossible to decode the message, give up.
  54.             if (false === $payload) {
  55.                 if ($this->logger) {
  56.                     $this->logger->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]);
  57.                 }
  58.                 continue;
  59.             }
  60.             if (!\is_array($payload) || \count($payload) < || !$payload[0] instanceof Data || !\is_array($payload[1])) {
  61.                 if ($this->logger) {
  62.                     $this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]);
  63.                 }
  64.                 continue;
  65.             }
  66.             [$data$context] = $payload;
  67.             $callback($data$context$clientId);
  68.         }
  69.     }
  70.     public function getHost(): string
  71.     {
  72.         return $this->host;
  73.     }
  74.     private function getMessages(): iterable
  75.     {
  76.         $sockets = [(int) $this->socket => $this->socket];
  77.         $write = [];
  78.         while (true) {
  79.             $read $sockets;
  80.             stream_select($read$write$writenull);
  81.             foreach ($read as $stream) {
  82.                 if ($this->socket === $stream) {
  83.                     $stream stream_socket_accept($this->socket);
  84.                     $sockets[(int) $stream] = $stream;
  85.                 } elseif (feof($stream)) {
  86.                     unset($sockets[(int) $stream]);
  87.                     fclose($stream);
  88.                 } else {
  89.                     yield (int) $stream => fgets($stream);
  90.                 }
  91.             }
  92.         }
  93.     }
  94. }