lib/php/libsdk/SDK/Build/PGO/Abstracts/PHP.php (185 lines of code) (raw):

<?php namespace SDK\Build\PGO\Abstracts; use SDK\Build\PGO\PHP\CLI; use SDK\{Config as SDKConfig, Exception}; abstract class PHP { protected $php_root; protected $php_ext_root; protected $opcache_file_cache; protected $id; protected $scenario; protected $conf; protected function setupPaths() { $this->php_root = $this->getRootDir(); if ($this->isDist()) { $this->php_ext_root = $this->php_root . DIRECTORY_SEPARATOR . "ext"; if (!file_exists($this->php_ext_root)) { throw new Exception("Extension dir '{$this->php_ext_root}' doesn't exist."); } } else { $this->php_ext_root = $this->php_root; } if ("cache" == $this->scenario) { $this->opcache_file_cache = SDKConfig::getTmpDir() . DIRECTORY_SEPARATOR . $this->id; } } /* TODO Might be improved. */ public function isDist() : bool { return !file_exists("Makefile") && file_exists("php.exe"); } protected function createEnv() : array { $env = getenv(); if (!$this->isDist()) { $deps_root = SDKConfig::getDepsLocalPath(); foreach ($env as $k => $v) { if (strtoupper($k) == "PATH") { $env[$k] = $deps_root . DIRECTORY_SEPARATOR . "bin;" . $env[$k]; break; } } } $drive = getenv("HOMEDRIVE"); $path = getenv("HOMEPATH"); if (!$drive || !$path) { $p = SDKConfig::getTmpDir(); $drive = substr($p, 0, 2); $path = substr($p, 2); putenv("HOMEDRIVE=$drive"); putenv("HOMEPATH=$path"); } return $env; } public function getExtRootDir() : string { return $this->php_ext_root; } public function getRootDir() : string { if ($this->php_root) { return $this->php_root; } /* XXX adapt for any possible PHP variants. */ $root = getenv("PHP_SDK_PGO_TEST_PHP_ROOT"); if (!$root) { if (!$this->isDist()) { $s = file_get_contents("Makefile"); if (preg_match(",BUILD_DIR=(.+),", $s, $m) > 0) { $root = trim($m[1]); } } } if (!file_exists($root)) { throw new Exception("'$root' doesn't exist."); } return $root; } public function getVersion(bool $short = false) : string { $ret = NULL; $cli = new CLI($this->conf, $this->scenario); $out = shell_exec($cli->getExeFilename() . " -n -v"); if ($short) { if (preg_match(",PHP (\d+\.\d+),", $out, $m)) { $ret = $m[1]; } } else { if (preg_match(",PHP ([^ ]+),", $out, $m)) { $ret = $m[1]; } } if (NULL === $ret) { throw new Exception("Failed to determine the test PHP version."); } return $ret; } public function isThreadSafe() : bool { $cli = new CLI($this->conf, $this->scenario); $out = shell_exec($cli->getExeFilename() . " -n -v"); if (preg_match(",NTS,", $out, $m) > 0) { return false; } return true; } /* Need to cleanup it somewhere. */ public function getIniFilename() { $ret = tempnam(sys_get_temp_dir(), "ini"); $tpl_vars = array( $this->conf->buildTplVarName("php", "extension_dir") => $this->php_ext_root, $this->conf->buildTplVarName("php", "error_log") => $this->getRootDir() . DIRECTORY_SEPARATOR . "pgo_run_error.log", ); $k = SDKConfig::getCurrentArchName(); $scenario_vars = (array)$this->conf->getSectionItem("php", "scenario", $this->scenario, "ini", $k); if ($scenario_vars) { foreach ($scenario_vars as $k => $v) { //$tpl_vars[$this->conf->buildTplVarName("php", "scenario", $this->scenario, str_replace(array(".", "-"), "_", $k))] = $v; $tpl_vars[$this->conf->buildTplVarName("php", str_replace(array(".", "-"), "_", $k))] = $v; } } /* Special handling, otherwise it'll need functionality to extrapolate ini values. */ if ("cache" == $this->scenario) { $tpl_vars[$this->conf->buildTplVarName("php", "opcache", "file_cache")] = $this->opcache_file_cache; } $this->conf->processTplFile( $this->getIniTplFilename(), $ret, $tpl_vars ); return $ret; } protected function getIniTplFilename() { $tpl_path = $this->conf->getTplDir("php"); $version = $this->getVersion(true); $ts = $this->isThreadSafe() ? "ts" : "nts"; $construct = $tpl_path . DIRECTORY_SEPARATOR . "php-$version-pgo-$ts" . ("default" == $this->scenario ? "" : "-{$this->scenario}") . ".ini"; if (!file_exists($construct)) { throw new Exception("Couldn't locate PHP config under '$construct'."); } return $construct; } public function exec(string $php_cmd, string $args = NULL, array $extra_env = array()) : int { $env = $this->createEnv(); $exe = $this->getExeFilename(); $ini = $this->getIniFilename(); $cert_path = getenv("PHP_SDK_ROOT_PATH") . "\\msys2\\usr\\ssl\\cert.pem"; $ini .= " -d curl.cainfo=$cert_path"; $spent_key = array(); foreach ($env as $k0 => &$v0) { foreach ($extra_env as $k1 => $v1) { if (strtoupper($k0) == strtoupper($k1)) { /* XXX some more things could require extra handling. */ if (strtoupper($k0) == "PATH") { $v0 = "$v1;$v0"; } else { $v0 = $v1; } $spent_key[] = $k1; break; } } } foreach ($extra_env as $k => $v) { if (in_array($k, $spent_key)) { continue; } $env[$k] = $v; } $cmd = "$exe -n -c $ini " . ($args ? "$args " : "") . $php_cmd; $desc = array( 0 => array("file", "php://stdin", "r"), 1 => array("file", "php://stdout", "w"), 2 => array("file", "php://stderr", "w") ); $p = proc_open($cmd, $desc, $pipes, $this->getRootDir(), $env); return proc_close($p); } public function getIdString(): string { return $this->getVersion() . "-" . SDKConfig::getCurrentCrtName() . "-" . ($this->isThreadSafe() ? "ts" : "nts") . "-" . SDKConfig::getCurrentArchName() . "-" . substr(md5(uniqid()), 0, 8); } }