Issues (67)

src/Engine/PHP.php (1 issue)

1
<?php
2
3
/*
4
 * Pickle
5
 *
6
 *
7
 * @license
8
 *
9
 * New BSD License
10
 *
11
 * Copyright © 2015-2015, Pickle community. All rights reserved.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions are met:
15
 *     * Redistributions of source code must retain the above copyright
16
 *       notice, this list of conditions and the following disclaimer.
17
 *     * Redistributions in binary form must reproduce the above copyright
18
 *       notice, this list of conditions and the following disclaimer in the
19
 *       documentation and/or other materials provided with the distribution.
20
 *     * Neither the name of the Hoa nor the names of its contributors may be
21
 *       used to endorse or promote products derived from this software without
22
 *       specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
 * POSSIBILITY OF SUCH DAMAGE.
35
 */
36
37
namespace Pickle\Engine;
38
39
use Exception;
40
use Pickle\Base\Abstracts;
41
use Pickle\Base\Interfaces;
42
43
class PHP extends Abstracts\Engine implements Interfaces\Engine
44
{
45
    private $phpCliEscaped;
46
47
    private $phpCli;
48
49
    private $phpize;
50
51
    private $version;
52
53
    private $major;
54
55
    private $minor;
56
57
    private $release;
58
59
    private $extra;
60
61
    private $compiler;
62
63
    private $architecture;
64
65
    private $zts;
66
67
    private $debug;
68
69
    private $iniPath;
70
71
    private $extensionDir;
72
73
    private $hasSdk;
74
75
    public function __construct($phpCli = PHP_BINARY)
76
    {
77
        if (!(is_file($phpCli) && is_executable($phpCli))) {
78
            throw new Exception("Invalid php executable: {$phpCli}");
79
        }
80
        $this->phpCliEscaped = escapeshellcmd($phpCli);
81
        $this->phpCli = $phpCli;
82
        $this->getFromConstants();
83
    }
84
85
    public function getName()
86
    {
87
        return 'php';
88
    }
89
90
    public function hasSdk()
91
    {
92
        if (isset($this->hasSdk)) {
93
            return $this->hasSdk;
94
        }
95
        $cliDir = dirname($this->phpCli);
96
        $res = glob($cliDir . DIRECTORY_SEPARATOR . 'phpize*');
97
        if (!$res) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $res of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
98
            $this->hasSdk = false;
99
        }
100
        $this->phpize = $res[0];
101
102
        return $this->hasSdk = false;
103
    }
104
105
    public function getArchitecture()
106
    {
107
        return $this->architecture;
108
    }
109
110
    public function getCompiler()
111
    {
112
        return $this->compiler;
113
    }
114
115
    public function getPath()
116
    {
117
        return $this->phpCli;
118
    }
119
120
    public function getMajorVersion()
121
    {
122
        return $this->major;
123
    }
124
125
    public function getMinorVersion()
126
    {
127
        return $this->minor;
128
    }
129
130
    public function getReleaseVersion()
131
    {
132
        return $this->release;
133
    }
134
135
    public function getVersion()
136
    {
137
        return $this->version;
138
    }
139
140
    public function getZts()
141
    {
142
        return $this->zts;
143
    }
144
145
    public function getExtensionDir()
146
    {
147
        return $this->extensionDir;
148
    }
149
150
    public function getIniPath()
151
    {
152
        return $this->iniPath;
153
    }
154
155
    protected function getFullPathExtDir($dir)
156
    {
157
        $realpathDir = realpath($dir);
158
        $baseDir = dirname($realpathDir);
159
        $baseDirPhp = dirname($this->phpCli);
160
        if (empty($baseDir)) {
161
            if (empty($dir)) {
162
                return $baseDirPhp . 'ext';
163
            }
164
            return $baseDirPhp . '\\' . $dir;
165
        }
166
167
        if ($baseDir == $baseDirPhp) {
168
            return $realpathDir;
169
        }
170
    }
171
172
    protected function getExtensionDirFromPhpInfo($info)
173
    {
174
        $extensionDir = '';
175
176
        foreach ($info as $s) {
177
            $pos_ext_dir = strpos($s, 'extension_dir');
178
            if ($pos_ext_dir !== false && substr($s, $pos_ext_dir - 1, 1) != '.') {
179
                [, $extensionDir] = explode('=>', $s);
180
                break;
181
            }
182
        }
183
184
        $extensionDir = trim($extensionDir);
185
        if ($extensionDir == '') {
186
            throw new Exception('Cannot detect PHP extension directory');
187
        }
188
        return $this->getFullPathExtDir($extensionDir);
189
    }
190
191
    protected function getArchFromPhpInfo($info)
192
    {
193
        $arch = '';
194
195
        foreach ($info as $s) {
196
            if (strpos($s, 'Architecture') !== false) {
197
                [, $arch] = explode('=>', $s);
198
                break;
199
            }
200
        }
201
202
        $arch = trim($arch);
203
        if ($arch == '') {
204
            throw new Exception('Cannot detect PHP build architecture');
205
        }
206
207
        return $arch;
208
    }
209
210
    protected function getIniPathFromPhpInfo($info)
211
    {
212
        $iniPath = '';
213
214
        foreach ($info as $s) {
215
            if (strpos($s, 'Loaded Configuration File') !== false) {
216
                [, $iniPath] = explode('=>', $s);
217
                if ($iniPath === '(None)') {
218
                    $iniPath = '';
219
                }
220
221
                break;
222
            }
223
        }
224
225
        $iniPath = trim($iniPath);
226
        if ($iniPath == '') {
227
            throw new Exception('Cannot detect php.ini directory');
228
        }
229
230
        return $iniPath;
231
    }
232
233
    protected function getCompilerFromPhpInfo($info)
234
    {
235
        $compiler = '';
236
237
        foreach ($info as $s) {
238
            if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
239
                if (strpos($s, 'PHP Extension Build') !== false) {
240
                    [, $build] = explode('=>', $s);
241
                    [, , $compiler] = explode(',', $build);
242
                    $compiler = strtolower($compiler);
243
                    break;
244
                }
245
            } else {
246
                if (strpos($s, 'Compiler') !== false) {
247
                    [, $compiler] = explode('=>', $s);
248
                    break;
249
                }
250
            }
251
        }
252
253
        $compiler = trim($compiler);
254
        if ($compiler == '') {
255
            throw new Exception('Cannot detect PHP build compiler version');
256
        }
257
258
        return $compiler;
259
    }
260
261
    private function getFromConstants()
262
    {
263
        $script = 'echo PHP_VERSION . \"\n\"; '
264
                . 'echo PHP_MAJOR_VERSION . \"\n\"; '
265
                . 'echo PHP_MINOR_VERSION . \"\n\"; '
266
                . 'echo PHP_RELEASE_VERSION . \"\n\"; '
267
                . 'echo PHP_EXTRA_VERSION . \"\n\"; '
268
                . 'echo PHP_ZTS . \"\n\"; '
269
                . 'echo PHP_DEBUG . \"\n\"; ';
270
271
        $cmd = $this->phpCliEscaped . ' -n -r ' . '"' . str_replace("\n", '', $script) . '"';
272
        if (DIRECTORY_SEPARATOR === '\\') {
273
            $cmd .= ' 2>NUL';
274
        } else {
275
            $cmd .= ' 2>/dev/null';
276
        }
277
278
        $info = null;
279
        exec($cmd, $info);
280
        if (count($info) !== 7) {
281
            throw new Exception('Could not determine info from the PHP binary');
282
        }
283
284
        [$this->version, $this->major, $this->minor, $this->release, $this->extra, $this->zts, $this->debug] = $info;
285
        $this->zts = (bool) $this->zts;
286
287
        if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
288
            [$this->compiler, $this->architecture, $this->iniPath, $this->extensionDir] = $this->getFromPhpInfo();
289
        }
290
    }
291
292
    private function getFromPhpInfo()
293
    {
294
        $cmd = $this->phpCliEscaped . ' -i';
295
        $info = null;
296
        exec($cmd, $info);
297
298
        if (!is_array($info)) {
299
            throw new Exception('Cannot parse phpinfo output');
300
        }
301
302
        $arch = $this->getArchFromPhpInfo($info);
303
        $iniPath = $this->getIniPathFromPhpInfo($info);
304
        $extensionDir = $this->getExtensionDirFromPhpInfo($info);
305
306
        $compiler = strtolower($this->getCompilerFromPhpInfo($info));
307
        return [$compiler, $arch, $iniPath, $extensionDir];
308
    }
309
}
310
311
/* vim: set tabstop=4 shiftwidth=4 expandtab: fdm=marker */
312