Completed
Push — master ( 35b4ac...79eb59 )
by Samuel
04:15 queued 03:10
created

FastCGI   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 92.98%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 4
dl 0
loc 138
ccs 53
cts 57
cp 0.9298
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 34 7
A doRun() 0 15 2
A request() 0 38 4
A getScriptFileName() 0 10 3
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 Adoy\FastCGI\Client;
16
17
class FastCGI extends AbstractAdapter
18
{
19
    /**
20
     * @var Client
21
     */
22
    protected $client;
23
24
    /**
25
     * @var Array of patterns matching php socket files
26
     */
27
    protected $possibleSocketFilePatterns = [
28
        '/var/run/php*.sock',
29
        '/var/run/php/*.sock'
30
    ];
31
32
    /**
33
     * @var string
34
     */
35
    protected $host;
36
37
    /**
38
     * @var string
39
     */
40
    protected $chroot;
41
42
    /**
43
     * @param string $host 127.0.0.1:9000 or /var/run/php5-fpm.sock
44
     * @param string $chroot
45
     */
46 9
    public function __construct($host = null, $chroot = null)
47
    {
48
        // try to guess where it is
49 9
        if ($host === null) {
50 8
            foreach ($this->possibleSocketFilePatterns as $possibleSocketFilePattern) {
51 8
                $possibleSocketFile = current(glob($possibleSocketFilePattern));
52 8
                if (file_exists($possibleSocketFile)) {
53 8
                    $host = $possibleSocketFile;
54 8
                    break;
55
                }
56
            }
57 8
            if ($host === null) {
58
                $host = '127.0.0.1:9000';
59
            }
60
        }
61
62 9
        $this->host = $host;
63
64 9
        if (false !== strpos($host, ':')) {
65 1
            [$host, $port] = explode(':', $host);
0 ignored issues
show
Bug introduced by
The variable $port does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
66 1
            $this->client = new Client($host, $port);
67
        } else {
68
            // socket
69 8
            $this->client = new Client('unix://' . $host, -1);
70
        }
71
72 9
        $this->client->setReadWriteTimeout(60 * 1000);
73 9
        $this->client->setPersistentSocket(false);
74 9
        $this->client->setKeepAlive(true);
75
76 9
        if ($chroot !== null) {
77 3
            $this->chroot = rtrim($chroot, '/');
78
        }
79 9
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 3
    protected function doRun(Code $code)
85
    {
86 3
        $response = $this->request($code);
87 1
        $parts = explode("\r\n\r\n", $response);
88
89
        // remove headers
90 1
        array_shift($parts);
91 1
        $body = implode("\r\n\r\n", $parts);
92
93 1
        if (@unserialize($body) === false) {
94
            throw new \RuntimeException(sprintf("Error: %s", $response));
95
        }
96
97 1
        return $body;
98
    }
99
100 3
    protected function request(Code $code)
101
    {
102 3
        $file = $this->createTemporaryFile();
103 3
        $this->logger->info(sprintf('FastCGI: Dumped code to file: %s', $file));
104
105
        try {
106 3
            $code->writeTo($file);
107
108
            $environment = [
109 1
                'SERVER_ADDR'     => '127.0.0.1',
110 1
                'REMOTE_ADDR'     => '127.0.0.1',
111 1
                'REMOTE_PORT'     => '65000',
112 1
                'REQUEST_METHOD'  => 'POST',
113 1
                'REQUEST_URI'     => '/',
114 1
                'SCRIPT_FILENAME' => $this->getScriptFileName($file),
115
            ];
116
117 1
            $this->logger->info(sprintf('FastCGI: Requesting FPM using socket: %s', $this->host));
118 1
            $response = $this->client->request($environment, '');
119 1
            $this->logger->debug(sprintf('FastCGI: Response: %s', json_encode($response)));
120
121 1
            if (!@unlink($file)) {
122
                $this->logger->debug(sprintf('FastCGI: Could not delete file: %s', $file));
123
            }
124
125 1
            return $response;
126 2
        } catch (\Exception $e) {
127 2
            if (!@unlink($file)) {
128 2
                $this->logger->debug(sprintf('FastCGI: Could not delete file: %s', $file));
129
            }
130
131 2
            throw new \RuntimeException(
132 2
                sprintf('FastCGI error: %s (%s)', $e->getMessage(), $this->host),
133 2
                $e->getCode(),
134 2
                $e
135
            );
136
        }
137
    }
138
139
    /**
140
     * @param string $file
141
     * @return string
142
     * @throws \RuntimeException
143
     */
144 2
    protected function getScriptFileName($file)
145
    {
146 2
        if ($this->chroot) {
147 1
            if (substr($file, 0, strlen($this->chroot)) === $this->chroot) {
148 1
                return substr($file, strlen($this->chroot));
149
            }
150
            throw new \RuntimeException('FastCGI configured to be chrooted, but file not in chroot directory.');
151
        }
152 1
        return $file;
153
    }
154
}
155