Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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