如何在 Windows 上从 PHP 中启动基于 WSL 的 Linux 可执行文件并捕获其标准输出?
How can I start a WSL-based Linux executable from within PHP on Windows and capture its stdout?
我有一个程序只能在 Linux 上运行,我的开发环境在 Windows。
当我在 Windows 中 运行 来自 cmd
的 WSL 命令时,它按预期工作。
- 当我在
cmd.exe
中 运行 C:\wsl echo "foo"
时,我通过 stdout 返回 foo
。
当我 运行 通过 exec
从 php 中执行相同的命令时,我没有得到任何标准输出并得到退出代码 -1073740791
我认为这是一个错误。
Cmd.exe:
C:\wsl echo "foo"
foo
PHP:
<?php
$cmd = 'wsl echo "foo"';
exec($cmd, $out, $code);
dd($out, $code);
?>
// $out is []
// $code is -1073740791
正如评论中所讨论的,潜在的问题是您的系统范围的 Apache Web 服务器服务 (wampapache64
) 被配置为 运行 作为 NT Authority\SYSTEM
(又名 Local System
或 LocalSystem
).
...并且 运行将任何类似网络服务器的东西设置为 LocalSystem
是一个非常非常糟糕的主意 出于其他原因,尤其是当这是 运行ning PHP 代码 - 上传文件处理中的一个简单错误或未能正确清理用户输入可能会破坏您的整个计算机,尤其是当它是一个公开暴露的网络服务器时,恶意软件攻击者可以连接到。
无论如何:
显然,当一个进程 运行 宁作为 SYSTEM
它不能使用 Win32 的 CreateProcess
调用 wsl
然后间接调用 Linux 程序。
PHP's exec
function is implemented 像这样:
exec
函数包装 PHP 的内部 VCWD_POPEN
。
VCWD_POPEN
is a macro 定义为 #define VCWD_POPEN(command, type) virtual_popen(command, type)
virtual_popen
因 OS 而异:
- 在 Win32 上,
virtual_popen
只是调用 popen_ex(command, type, CWDG(cwd).cwd, NULL)
。
- And
popen_ex
calls CreateProcessAsUserW
or CreateProcessW
实际开始新进程。
- 我注意到
popen_ex
使用 OpenThreadToken
来确保创建新进程时使用与父进程相同的用户帐户和权限 - 在本例中为 NT Authority\SYSTEM
.
所以 PHP 的 exec()
而不是 只是 C 的 system()
.[=44 的简单包装=]
而如果 exec()
是 对 system()
的包装,那么程序 would be invoked via cmd.exe
的行为会有所不同(尽管也可能会失败)
-
因此,通过将您的网络服务器更改为 运行 作为 真实用户帐户,这意味着 CreateProcess...
调用在 wsl
内调用受支持的环境。
我有一个程序只能在 Linux 上运行,我的开发环境在 Windows。
当我在 Windows 中 运行 来自
cmd
的 WSL 命令时,它按预期工作。- 当我在
cmd.exe
中 运行C:\wsl echo "foo"
时,我通过 stdout 返回foo
。
- 当我在
当我 运行 通过
exec
从 php 中执行相同的命令时,我没有得到任何标准输出并得到退出代码-1073740791
我认为这是一个错误。
Cmd.exe:
C:\wsl echo "foo"
foo
PHP:
<?php
$cmd = 'wsl echo "foo"';
exec($cmd, $out, $code);
dd($out, $code);
?>
// $out is []
// $code is -1073740791
正如评论中所讨论的,潜在的问题是您的系统范围的 Apache Web 服务器服务 (wampapache64
) 被配置为 运行 作为 NT Authority\SYSTEM
(又名 Local System
或 LocalSystem
).
...并且 运行将任何类似网络服务器的东西设置为 LocalSystem
是一个非常非常糟糕的主意 出于其他原因,尤其是当这是 运行ning PHP 代码 - 上传文件处理中的一个简单错误或未能正确清理用户输入可能会破坏您的整个计算机,尤其是当它是一个公开暴露的网络服务器时,恶意软件攻击者可以连接到。
无论如何:
显然,当一个进程 运行 宁作为 SYSTEM
它不能使用 Win32 的 CreateProcess
调用 wsl
然后间接调用 Linux 程序。
PHP's
exec
function is implemented 像这样:exec
函数包装 PHP 的内部VCWD_POPEN
。VCWD_POPEN
is a macro 定义为#define VCWD_POPEN(command, type) virtual_popen(command, type)
virtual_popen
因 OS 而异:- 在 Win32 上,
virtual_popen
只是调用popen_ex(command, type, CWDG(cwd).cwd, NULL)
。- And
popen_ex
callsCreateProcessAsUserW
orCreateProcessW
实际开始新进程。 - 我注意到
popen_ex
使用OpenThreadToken
来确保创建新进程时使用与父进程相同的用户帐户和权限 - 在本例中为NT Authority\SYSTEM
.
- And
- 在 Win32 上,
所以 PHP 的
exec()
而不是 只是 C 的system()
.[=44 的简单包装=]而如果
exec()
是 对system()
的包装,那么程序 would be invoked viacmd.exe
的行为会有所不同(尽管也可能会失败)
因此,通过将您的网络服务器更改为 运行 作为 真实用户帐户,这意味着 CreateProcess...
调用在 wsl
内调用受支持的环境。