IIS + PHP 执行到 运行 Linux 命令且 WSL 不工作

IIS + PHP exec to run Linux commands with WSL not working

配置

上下文

我正在尝试编写一个 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)了解更多详情。