如何从脚本中获取当前的PHP可执行文件?
我想从PHPCLI中运行PHPCLI程序。在一些将运行此功能的机器上,PHP4和PHP5都已安装。如果我运行外部程序作为如何从脚本中获取当前的PHP可执行文件?,php,Php,我想从PHPCLI中运行PHPCLI程序。在一些将运行此功能的机器上,PHP4和PHP5都已安装。如果我运行外部程序作为 php5 outer.php 我希望内部脚本使用相同的PHP版本运行。在Perl中,我将使用$^X获取Perl可执行文件。PHP中似乎没有这样的变量 现在,我使用的是$\u服务器[''.],因为Bash(和zsh)将环境变量$\u设置为上次运行的程序。但是,我不想依赖特定于shell的习惯用法 更新:版本差异只是一个问题。例如,如果PHP不在PATH中,或者不是PATH中找
php5 outer.php
我希望内部脚本使用相同的PHP版本运行。在Perl中,我将使用$^X
获取Perl可执行文件。PHP中似乎没有这样的变量
现在,我使用的是$\u服务器[''.]
,因为Bash(和zsh)将环境变量$\u
设置为上次运行的程序。但是,我不想依赖特定于shell的习惯用法
更新:版本差异只是一个问题。例如,如果PHP不在PATH中,或者不是PATH中找到的第一个版本,那么查找版本信息的建议就没有帮助
此外,csh
和变体似乎没有为其流程设置$\ucode>环境变量,因此解决方法不适用于此
更新2:我一直在使用$\u SERVER['''.]
,直到我发现它在xargs
下没有做正确的事情(这是有意义的…zsh
将它设置为它运行的命令,即xargs
,而不是php5
,并且xargs
不会更改变量)。我又开始使用:
$version = explode('.', phpversion());
$phpcli = "php{$version[0]}";
您可以尝试分析结果。在执行“内部”脚本之前,您可以使用它获取当前版本的PHP。好的,这很难看,但它在Linux上工作:
<?php
// Returns the full path of the current PHP executable
function get_proc_name(){
// Gets the PID of the current executable
$pid = posix_getpid();
// Returns the exact path to the PHP executable.
$exe = exec("readlink -f /proc/$pid/exe");
return $exe;
}
值得注意的是,现在在PHP5.4+中,您可以使用预定义的常量:
PHP_二进制文件
指定脚本执行期间的PHP二进制路径。从PHP5.4开始提供
在我的服务器上,我使用了PHP5.3.14
我发现了一个预定义的常量:
然后,假设可执行文件的文件名始终为“php”,则“/php”
指向我的php可执行文件。我认为最好的常量是。使用PHP5.5.12。不幸的是,我找不到更短的方法,但效果非常好,并且与多OS/PHP版本兼容
$lookIn可能会被扩展以包括更多的公共位置。不幸的是,PHP\U二进制文件正在返回httpd
二进制文件(在Windows上),所以我又回到了使用路径
if (defined('PHP_BINARY') &&
PHP_BINARY &&
in_array(PHP_SAPI, array('cli', 'cli-server')) &&
is_file(PHP_BINARY)) {
return PHP_BINARY;
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
foreach ($paths as $path) {
if (substr($path, strlen($path)-1) == DIRECTORY_SEPARATOR) {
$path = substr($path, 0, strlen($path)-1);
}
if (substr($path, strlen($path) - strlen('php')) == 'php') {
$response = $path.DIRECTORY_SEPARATOR . 'php.exe';
if (is_file($response)) {
return $response;
}
} else if (substr($path, strlen($path) - strlen('php.exe')) == 'php.exe') {
if (is_file($response)) {
return $response;
}
}
}
} else {
$paths = explode(PATH_SEPARATOR, getenv('PATH'));
foreach ($paths as $path) {
if (substr($path, strlen($path)-1) == DIRECTORY_SEPARATOR) {
$path = substr($path, strlen($path)-1);
}
if (substr($path, strlen($path) - strlen('php')) == 'php') {
if (is_file($path)) {
return $path;
}
$response = $path.DIRECTORY_SEPARATOR . 'php';
if (is_file($response)) {
return $response;
}
}
}
}
return null;
对答案不满意后,我提出了自己的答案。如果看起来合理,它会尝试使用PHP\u BINARY
,否则它会寻找与当前运行的解释器版本相同的解释器
/**
* Return a suitable PHP interpreter that is likely to be the same version as the
* currently running interpreter. This is similar to using the PHP_BINARY constant, but
* it will also work from within mod_php or PHP-FPM, in which case PHP_BINARY will return
* unusable interpreters.
*
* @return string
*/
public function getPhpInterpreter(): string {
static $cachedExecutable = null;
if ($cachedExecutable !== null) {
return $cachedExecutable;
}
$basename = basename(PHP_BINARY);
// If the binary is 'php', 'php7', 'php7.3' etc, then assume it's a usable interpreter
if ($basename === 'php' || preg_match('/^php\d+(?:\.\d+)*$/', $basename)) {
return PHP_BINARY;
}
// Otherwise, we might be running as mod_php, php-fpm, etc, where PHP_BINARY is not a
// usable PHP interpreter. Try to find one with the same version as the current one.
$candidates = [
'php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION,
'php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION,
'php' . PHP_MAJOR_VERSION,
];
$envPath = $_SERVER['PATH'] ?? '';
$paths = $envPath !== '' ? explode(':', $envPath) : [];
if (!in_array(PHP_BINDIR, $paths, true)) {
$paths[] = PHP_BINDIR;
}
foreach ($candidates as $candidate) {
foreach ($paths as $path) {
$executable = $path . DIRECTORY_SEPARATOR . $candidate;
if (is_executable($executable)) {
$cachedExecutable = $executable;
return $executable;
}
}
}
// Fallback, if nothing else can be found
$cachedExecutable = 'php';
return $cachedExecutable;
}
让我知道这是否适合你。我在Debian Buster、CLI和FPM上对其进行了测试。是否可以有条件地包含另一个PHP文件?这是确保包含的代码使用与包含代码相同的解释器运行的最简单方法。有趣的一点。在这个特殊的例子中,它作为子进程运行的部分原因是内部脚本在不同的地方调用“exit()”,我也在考虑这样做。我想我可能可以使用或PECL扩展来调用API函数,但目前两个扩展似乎都没有得到有效维护。与使用$pid
相比,您可以随时查看“/proc/self/exe”
我喜欢这个解决方案!,这并没有说明它是在什么时候添加的,它是PHP\u BINDIR
(没有第二条下划线)。这是一个相当体面的回答。谢谢。我对答案和评论投了赞成票,但在Windows中尝试后,我收回了赞成票。无论实际情况如何,都将始终返回C:\php
。答案不错,但是,如果在Linux系统上安装多个版本的php,它将无法正常工作,因为它们很可能都在/usr/bin
中。注意:在Apache2handler中返回httpd
路径。注意:它返回php cgi
而不是php
在我的例子(windows)中,在不存在此类文件或目录的windows(PHP7.1.11、Apache2.4.29、Windows7Pro)上返回C:\php
,如下所示:,正如在另一个答案的评论中所指出的,doesPHP\u BINDIR
。在托管公司的Linux框中,它也返回与PHP\u BINDIR
相同的结果。这里是/usr/bin
,它确实包含一个php
可执行文件,但这是5.3版的可执行文件,而不是调用环境的7.0.25版。所以我不认为这个答案有用。@Jake你是如何测试它的?看起来和答案一样。有人试过吗?它有用吗?在Win和Unix之间保持一致?代码很难看,但如果它能正常工作,我会对它进行规范化。我知道这是一个旧答案,没有人有答案@XedinUnknown,但我可以确认这在运行XAMPP的Windows上非常有效。还有人在更多的环境中测试过这个吗?为什么要混合使用运算符==
和===
(两个和三个)来比较字符串常量?外部链接的问题是它们随时都可能断开。