FriendsOfPHP /
pickle
| 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
|
|||
| 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 |
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.