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 string $host;
  24.     private ?LoggerInterface $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.             $this->logger?->info('Received a payload from client {clientId}', ['clientId' => $clientId]);
  50.             $payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);
  51.             // Impossible to decode the message, give up.
  52.             if (false === $payload) {
  53.                 $this->logger?->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]);
  54.                 continue;
  55.             }
  56.             if (!\is_array($payload) || \count($payload) < || !$payload[0] instanceof Data || !\is_array($payload[1])) {
  57.                 $this->logger?->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]);
  58.                 continue;
  59.             }
  60.             [$data$context] = $payload;
  61.             $callback($data$context$clientId);
  62.         }
  63.     }
  64.     public function getHost(): string
  65.     {
  66.         return $this->host;
  67.     }
  68.     private function getMessages(): iterable
  69.     {
  70.         $sockets = [(int) $this->socket => $this->socket];
  71.         $write = [];
  72.         while (true) {
  73.             $read $sockets;
  74.             stream_select($read$write$writenull);
  75.             foreach ($read as $stream) {
  76.                 if ($this->socket === $stream) {
  77.                     $stream stream_socket_accept($this->socket);
  78.                     $sockets[(int) $stream] = $stream;
  79.                 } elseif (feof($stream)) {
  80.                     unset($sockets[(int) $stream]);
  81.                     fclose($stream);
  82.                 } else {
  83.                     yield (int) $stream => fgets($stream);
  84.                 }
  85.             }
  86.         }
  87.     }
  88. }