我的环境是 Windows Server 2012 R2、IIS 8、Active Directory 和文件共享。IIS、AD 和文件共享都是独立的虚拟机。
我在 IIS 中设置了一个网站 www.example.com。应用程序池身份设置为 AD 用户IUSR_example
,该用户对包含网站文件的文件夹具有“完全控制”权限。网站文件位于文件共享上,IIS 通过 UNC 路径引用该文件共享。
总体而言,该网站的工作原理是它可以提供 PHP、ASP.Net 和 ASP Classic 页面,并且代码甚至可以创建新文件。
然而,我遇到了一个似乎特定于 PHP 的问题exec()
。我尝试调用whoami
、dir
和ffmpeg
,但它们没有返回任何内容。使用 Sysinternals Procmon,我已确认可执行文件从未启动。
奇怪的是,我是能够使用 ASP Classic(使用)进行完全相同的调用,并且运行完美。当脚本未通过 UNC 路径运行时, WScript.Shell
我也能够让 PHP运行。exec()
这是我尝试过/发现的:
- 使用 ASP 时,procmon 报告 w3wp.exe 生成 cmd.exe 进程,该进程又生成 conhost.exe 和(例如)ffmpeg.exe。ffmpeg 的输出文件成功显示。
- 使用 PHP 时,procmon 报告 w3wp.exe 生成 php-cgi.exe 进程,该进程又创建 cmd.exe 和 conhost.exe。ffmpeg.exe 的线程从未出现。
- cmd.exe 使用如下命令行调用:
cmd.exe /c ""--the command to be executed--""
- cmd.exe 进程的命令行对于 ASP Classic 和 PHP 完全相同。
- 在 Procmon 中,用户总是被报告为
IUSR_example
- 我尝试
2>&1
在命令末尾添加 - 我尝试将 IUSR 赋予“替换进程级令牌”权限
- 我尝试关闭 FastCGI 模拟并在“进程模型”>“高级设置”下在“NamedPipe”和“TCP”之间切换
- PHP 错误日志中没有错误
- Windows 事件日志中没有任何错误
请注意,这并非特定于 ffmpeg。任何其他使用exec()
也会失败。此外,我宁愿不在WScript.Shell
PHP 中使用,因为最终我们将使用依赖于 的 WordPress 插件exec()
。
我该如何进一步解决这个问题?
答案1
作为建议由用户“pajoye”在 bugs.php.net 上发布,使用proc_open()
允许我成功执行命令。这反过来又允许我使用 procmon 来发现方式exec()
和proc_open()
工作之间的差异。长话短说,当 PHP 脚本位于网络共享上时,我会将其称为在 Windows 上运行的 PHP 中的一个核心错误。以下是关键细节:
exec()
将当前工作目录默认为 PHP 脚本的路径,在我的情况下是 UNC 路径。cmd.exe
不允许您将 UNC 路径作为当前工作目录,并cmd.exe
声称它将恢复到 Windows 文件夹。- 尽管
cmd.exe
继续执行并conhost.exe
生成,但原始工作目录仍然会导致某种问题,并且所需的可执行文件永远不会启动。
因此,一个简单的解决方法是chdir()
在调用之前转到本地目录exec()
。但是,有很多 WordPress 插件依赖于exec()
,所以在我看来,exec()
应该与 PHP 脚本是否在共享上运行无关。我会询问是否可以在未来版本中包含对此的修复。