Issues (14)

src/Adapter/FastCGI.php (1 issue)

Labels
Severity
1
<?php
2
3
/*
4
 * This file is part of CacheTool.
5
 *
6
 * (c) Samuel Gordalina <[email protected]>
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 CacheTool\Adapter;
13
14
use CacheTool\Code;
15
use hollodotme\FastCGI\Client;
16
use hollodotme\FastCGI\Interfaces\ConfiguresSocketConnection;
17
use hollodotme\FastCGI\SocketConnections\NetworkSocket;
18
use hollodotme\FastCGI\SocketConnections\UnixDomainSocket;
19
use hollodotme\FastCGI\Requests\PostRequest;
20
21
class FastCGI extends AbstractAdapter
22
{
23
    /**
24
     * @var Client
25
     */
26
    protected $client;
27
28
    /**
29
     * @var ConfiguresSocketConnection
30
     */
31
    protected $connection;
32
33
    /**
34
     * @var Array of patterns matching php socket files
35
     */
36
    protected $possibleSocketFilePatterns = [
37
        '/var/run/php*.sock',
38
        '/var/run/php/*.sock'
39
    ];
40
41
    /**
42
     * @var string
43
     */
44
    protected $host;
45
46
    /**
47
     * @var string
48
     */
49
    protected $chroot;
50
51
    /**
52
     * @param string $host 127.0.0.1:9000 or /var/run/php5-fpm.sock
53
     * @param string $chroot
54
     */
55 10
    public function __construct($host = null, $chroot = null)
56
    {
57
        // try to guess where it is
58 10
        if ($host === null) {
59 6
            foreach ($this->possibleSocketFilePatterns as $possibleSocketFilePattern) {
60 6
                $possibleSocketFile = current(glob($possibleSocketFilePattern));
61 6
                if (file_exists($possibleSocketFile)) {
62 6
                    $host = $possibleSocketFile;
63
                    break;
64
                }
65
            }
66 6
            if ($host === null) {
67
                $host = '127.0.0.1:9000';
68
            }
69
        }
70
71 10
        $this->host = $host;
72
73 10
        if (false !== strpos($host, ':')) {
74 4
            $last = strrpos($host, ':');
75 4
            $port = substr($host, $last + 1, strlen($host));
76 4
            $host = substr($host, 0, $last);
77
78 4
            $IPv6 = '/^(?:[A-F0-9]{0,4}:){1,7}[A-F0-9]{0,4}$/';
79 4
            if (preg_match($IPv6, $host) === 1) {
80
                // IPv6 addresses need to be surrounded by brackets
81
                // see: https://www.php.net/manual/en/function.stream-socket-client.php#refsect1-function.stream-socket-client-notes
82 1
                $host = "[${host}]";
83
            }
84
85 4
            $this->connection = new NetworkSocket(
86
                $host,    # Hostname
87
                $port,    # Port
0 ignored issues
show
$port of type string is incompatible with the type integer expected by parameter $port of hollodotme\FastCGI\Socke...rkSocket::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
                /** @scrutinizer ignore-type */ $port,    # Port
Loading history...
88 4
                5000,     # Connect timeout in milliseconds (default: 5000)
89 4
                120000    # Read/write timeout in milliseconds (default: 5000)
90
            );
91
        } else {
92 6
            $this->connection = new UnixDomainSocket(
93
                $host,  # Socket path to php-fpm
94 6
                5000,   # Connect timeout in milliseconds (default: 5000)
95 6
                120000  # Read/write timeout in milliseconds (default: 5000)
96
            );
97
        }
98
99 10
        $this->client = new Client();
100
101 10
        if ($chroot !== null) {
102 3
            $this->chroot = rtrim($chroot, '/');
103
        }
104 10
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109 3
    protected function doRun(Code $code)
110
    {
111 3
        $body = $this->request($code);
112
113 1
        if (@unserialize($body) === false) {
114
            throw new \RuntimeException(sprintf("Error: %s", $body));
115
        }
116
117 1
        return $body;
118
    }
119
120 3
    protected function request(Code $code)
121
    {
122 3
        $file = $this->createTemporaryFile();
123 3
        $this->logger->info(sprintf('FastCGI: Dumped code to file: %s', $file));
124
125
        try {
126 3
            $code->writeTo($file);
127
128 1
            $this->logger->info(sprintf('FastCGI: Requesting FPM using socket: %s', $this->host));
129 1
            $request = new PostRequest($this->getScriptFileName($file), '');
130 1
            $response = $this->client->sendRequest($this->connection, $request);
131 1
            $this->logger->debug(sprintf('FastCGI: Response: %s', json_encode($response)));
132
133 1
            if (!@unlink($file)) {
134
                $this->logger->debug(sprintf('FastCGI: Could not delete file: %s', $file));
135
            }
136
137 1
            return $response->getBody();
138 2
        } catch (\Exception $e) {
139 2
            if (!@unlink($file)) {
140 2
                $this->logger->debug(sprintf('FastCGI: Could not delete file: %s', $file));
141
            }
142
143 2
            throw new \RuntimeException(
144 2
                sprintf('FastCGI error: %s (%s)', $e->getMessage(), $this->host),
145 2
                $e->getCode(),
146
                $e
147
            );
148
        }
149
    }
150
151
    /**
152
     * @param string $file
153
     * @return string
154
     * @throws \RuntimeException
155
     */
156 2
    protected function getScriptFileName($file)
157
    {
158 2
        if ($this->chroot) {
159 1
            if (substr($file, 0, strlen($this->chroot)) === $this->chroot) {
160 1
                return substr($file, strlen($this->chroot));
161
            }
162
            throw new \RuntimeException('FastCGI configured to be chrooted, but file not in chroot directory.');
163
        }
164 1
        return $file;
165
    }
166
}
167