IIS + PHP 执行到 运行 Linux 命令且 WSL 不工作
IIS + PHP exec to run Linux commands with WSL not working
配置
- Windows11
- IIS 10.0.22000.1
- PHP 5.6.40(我知道,它很旧,但我不知道我的脚本会在哪里执行,所以我走得更远)
- 已安装 WSL
上下文
我正在尝试编写一个 runLinuxCommand
,它将 运行 在 Windows(Windows 子系统用于 Linux)或 Linux(也许 OSX 就像 Unix 一样)。
我在 exec("dir", $result, $code)
返回 $code ==> 1
时遇到了一些问题。然后,我将 IIS 中的用户 运行ning PHP 更改为我当前登录的用户(管理员)。我知道,这并不理想,但现在,我想实现我的目标。之后我会尝试减少权利。而且...它奏效了!
问题
所以,我尝试执行 exec("wsl date", $result, $code)
,但没有成功,退出代码仍然为 1。是的,打开命令提示符并执行 wsl date
确实有效。使用登录用户或管理员身份。
我目前唯一能看到的是初始化WSL需要太多时间,但完全不确定。
尝试次数
尝试 #1
问题部分
尝试 #2
exec('C:\Windows\System32\wsl.exe date', $result, $code);
同样的结果。
尝试 #3
exec('start /B /WAIT C:\Windows\System32\wsl.exe date', $result, $code);
挂起...永远无法通过这条线。
尝试 #4
exec('start /B /WAIT cmd /C C:\Windows\System32\wsl.exe date', $result, $code);
没有错误。没有结果/输出。
尝试 #5
$WshShell = new \com("WScript.Shell");
$oExec = $WshShell->Exec("C:\Windows\System32\wsl.exe date");
$out = $oExec->StdOut->ReadLine();
现在,当 运行 进入第二行时,我收到一条特定的错误消息:File not found
。我可以向你保证 C:\Windows\System32\wsl.exe
存在。
我已经使用 $oExec = $WshShell->Run("whoami", 0 , true);
作为第二行确认该用户是我登录的用户(一个管理员帐户,我可以从中使用终端进行测试)。
放在一边
我搜索了很多关于它的内容,但一无所获(好吧,我发现的一切都不具体)。
所以,经过一番磨难,我发现问题出在 PHP 32 位版本上。使用 64 位版本调用 exec('wsl date', $result, $code);
效果很好。
因此,对于那些对我构建的 class 感兴趣的人:
class Host {
private function __construct() {}
/**
* Get if the host is Windows
* @return boolean
*/
public static function isWindows() {
$uname = strtolower(php_uname('s'));
return strpos($uname, "win") === 0;
}
/**
* Get if PHP is 64 bits or not (32 bits)
* @ref https://code-boxx.com/check-php-version/#:~:text=To%20check%20if%20you%20are,and%208%20for%2064%2Dbit.
* @return boolean
*/
public static function isPhp64bits() {
if (isset($_SERVER["PROCESSOR_ARCHITECTURE"])) {
// Windows IIS validation
return $_SERVER["PROCESSOR_ARCHITECTURE"] != "x86";
}
return PHP_INT_SIZE == 8;
}
public static function runLinuxCommand($command) {
if (self::isWindows()) {
if (self::isPhp64bits()) {
$wslExecutor = "wsl";
} else {
$wslExecutor = "C:\Windows\Sysnative\wsl.exe";
}
$command = "$wslExecutor $command";
} else {
putenv('LANG=en_US.UTF-8'); // Ensure the output is UTF-8
}
$result = [];
$exitCode = -1;
exec($command, $result, $exitCode);
return new ExecReturn($result, $exitCode);
}
}
不再需要:
对于 WSLExecutor 软件,非常简单,但无论如何:
https://github.com/djon2003/WSLExecutor
我知道,不包括框架调用,但我不会 post 整个框架。而且,它们是很容易实现的方法。
编辑 #1
有了 NotTheDr01ds 的帮助,我不再需要 C# 软件 WSLExecutor。
32 位 PHP 是核心问题。
既然如此,我相信您可以通过使用 Windows Sysnative 界面轻松解决这个问题,该界面旨在允许您从 32 位应用程序中调用 64 位应用程序。
从 32 位 PHP,尝试启动 C:\Windows\Sysnative\wsl.exe <arguments>
。它位于一个虚拟文件夹中,因此您无法从普通的 64 位资源管理器或类似工具中看到它。参见 this answer
(和其他 sysnative related answers)了解更多详情。
配置
- Windows11
- IIS 10.0.22000.1
- PHP 5.6.40(我知道,它很旧,但我不知道我的脚本会在哪里执行,所以我走得更远)
- 已安装 WSL
上下文
我正在尝试编写一个 runLinuxCommand
,它将 运行 在 Windows(Windows 子系统用于 Linux)或 Linux(也许 OSX 就像 Unix 一样)。
我在 exec("dir", $result, $code)
返回 $code ==> 1
时遇到了一些问题。然后,我将 IIS 中的用户 运行ning PHP 更改为我当前登录的用户(管理员)。我知道,这并不理想,但现在,我想实现我的目标。之后我会尝试减少权利。而且...它奏效了!
问题
所以,我尝试执行 exec("wsl date", $result, $code)
,但没有成功,退出代码仍然为 1。是的,打开命令提示符并执行 wsl date
确实有效。使用登录用户或管理员身份。
我目前唯一能看到的是初始化WSL需要太多时间,但完全不确定。
尝试次数
尝试 #1
问题部分
尝试 #2
exec('C:\Windows\System32\wsl.exe date', $result, $code);
同样的结果。
尝试 #3
exec('start /B /WAIT C:\Windows\System32\wsl.exe date', $result, $code);
挂起...永远无法通过这条线。
尝试 #4
exec('start /B /WAIT cmd /C C:\Windows\System32\wsl.exe date', $result, $code);
没有错误。没有结果/输出。
尝试 #5
$WshShell = new \com("WScript.Shell");
$oExec = $WshShell->Exec("C:\Windows\System32\wsl.exe date");
$out = $oExec->StdOut->ReadLine();
现在,当 运行 进入第二行时,我收到一条特定的错误消息:File not found
。我可以向你保证 C:\Windows\System32\wsl.exe
存在。
我已经使用 $oExec = $WshShell->Run("whoami", 0 , true);
作为第二行确认该用户是我登录的用户(一个管理员帐户,我可以从中使用终端进行测试)。
放在一边
我搜索了很多关于它的内容,但一无所获(好吧,我发现的一切都不具体)。
所以,经过一番磨难,我发现问题出在 PHP 32 位版本上。使用 64 位版本调用 exec('wsl date', $result, $code);
效果很好。
因此,对于那些对我构建的 class 感兴趣的人:
class Host {
private function __construct() {}
/**
* Get if the host is Windows
* @return boolean
*/
public static function isWindows() {
$uname = strtolower(php_uname('s'));
return strpos($uname, "win") === 0;
}
/**
* Get if PHP is 64 bits or not (32 bits)
* @ref https://code-boxx.com/check-php-version/#:~:text=To%20check%20if%20you%20are,and%208%20for%2064%2Dbit.
* @return boolean
*/
public static function isPhp64bits() {
if (isset($_SERVER["PROCESSOR_ARCHITECTURE"])) {
// Windows IIS validation
return $_SERVER["PROCESSOR_ARCHITECTURE"] != "x86";
}
return PHP_INT_SIZE == 8;
}
public static function runLinuxCommand($command) {
if (self::isWindows()) {
if (self::isPhp64bits()) {
$wslExecutor = "wsl";
} else {
$wslExecutor = "C:\Windows\Sysnative\wsl.exe";
}
$command = "$wslExecutor $command";
} else {
putenv('LANG=en_US.UTF-8'); // Ensure the output is UTF-8
}
$result = [];
$exitCode = -1;
exec($command, $result, $exitCode);
return new ExecReturn($result, $exitCode);
}
}
不再需要: 对于 WSLExecutor 软件,非常简单,但无论如何: https://github.com/djon2003/WSLExecutor
我知道,不包括框架调用,但我不会 post 整个框架。而且,它们是很容易实现的方法。
编辑 #1
有了 NotTheDr01ds 的帮助,我不再需要 C# 软件 WSLExecutor。
32 位 PHP 是核心问题。
既然如此,我相信您可以通过使用 Windows Sysnative 界面轻松解决这个问题,该界面旨在允许您从 32 位应用程序中调用 64 位应用程序。
从 32 位 PHP,尝试启动 C:\Windows\Sysnative\wsl.exe <arguments>
。它位于一个虚拟文件夹中,因此您无法从普通的 64 位资源管理器或类似工具中看到它。参见 this answer
(和其他 sysnative related answers)了解更多详情。