exec在PHP 7.4中默认可用,但实际执行失败主因是disable_functions屏蔽、safe_mode残留、Web进程权限不足或命令路径不在PATH中;返回空且$return_var为127表明shell找不到命令,需检查php.ini配置、使用绝对路径、escapeshellarg()防护注入,并注意后台执行需重定向输出。

exec 在 PHP 7.4 中默认可用,但实际能否执行命令不取决于版本,而取决于服务器配置和运行环境权限。直接调用 exec 失败,90% 的情况不是函数被禁用,而是被 disable_functions 列表屏蔽、safe_mode(已废弃但旧配置残留)干扰,或 Web 进程用户无权访问目标命令/路径。
为什么 exec('ls') 返回空,但 echo 'ok' 能输出
常见现象:代码没报错,$output 是空数组,$return_var 是 127 —— 这是 shell 找不到命令的典型错误码。
- 检查
disable_functions:在 phpinfo() 页面搜索该配置项,确认exec是否在其中;若在,改 php.ini 并重启 PHP-FPM 或 Apache - 确认命令是否在 PATH 中:Web 进程用户(如
www-data)的$PATH通常比你登录终端时窄,exec('which ls', $out)可能返回空;稳妥做法是写绝对路径:/bin/ls -l - 注意 Windows 和 Linux 行为差异:Windows 下
exec实际调用cmd.exe /c包裹命令,所以exec('dir')可行,但exec('ls')会失败(除非安装了 Git Bash 等并加入 PATH)
含空格路径或参数必须用 escapeshellarg()
直接拼接字符串如 exec("convert $input_path -resize 50% $output_path") 是高危操作——用户上传文件名含 ;、& 或反引号时,可能触发命令注入。
- 所有外部输入(尤其是文件名、URL、用户 ID)必须过
escapeshellarg(),例如:$safe_path = escapeshellarg("/var/www/uploads/my file.jpg"); exec("identify $safe_path"); - 不要对整个命令字符串用
escapeshellcmd(),它会转义|、&等管道符,导致本意是ps aux | grep nginx变成字面量执行 - Windows 下路径分隔符用反斜杠需双重转义,但更推荐统一用正斜杠或
escapeshellarg()自动处理:escapeshellarg("C:/Program Files/ImageMagick/convert.exe")
后台异步执行必须重定向输出流
想让耗时命令(如 FFmpeg 转码)不阻塞 HTTP 响应?不能只写 exec('ffmpeg -i input.mp4 output.mp4') —— PHP 会等它结束才继续,且若输出未重定向,进程可能卡住。
立即学习“PHP免费学习笔记(深入)”;
- 必须加
> /dev/null 2>&1 &(Linux)或> NUL 2>&1 &(Windows),例如:exec("ffmpeg -i $in $out > /dev/null 2>&1 &"); - 注意:末尾的
&是 shell 后台运行符号,必须由 shell 解析,所以不能省略/bin/sh -c包裹(尤其当系统默认 shell 不是 bash):exec("/bin/sh -c 'ffmpeg -i " . escapeshellarg($in) . " " . escapeshellarg($out) . " > /dev/null 2>&1 &'"); - 别依赖
exec返回值判断后台任务成败——它只反映sh -c启动是否成功,而非子进程结果;应改用临时文件、数据库状态位或消息队列来跟踪真实进度
proc_open 比 exec 更可控,但资源要手动清理
当需要实时读取命令输出(如进度条)、向 stdin 写入数据(如交互式密码输入),或精确控制超时,proc_open 是唯一选择。
- 必须配
["pipe" => "r"]描述符数组,并用proc_close()显式释放资源,否则反复调用会导致“Too many open files”错误 - PHP 7.4 对
proc_open的bypass_shell支持稳定,Windows 下可绕过cmd.exe直接启动程序,避免额外解析层干扰:proc_open($cmd, $descriptors, $pipes, null, null, ["bypass_shell" => true]) - 不要把
proc_open当作exec的“高级替代”——它复杂度高、易出错;仅在exec确实无法满足需求时才用
真正难的从来不是怎么写那行 exec(),而是搞清谁在跑它、它能访问什么、输出去哪了、失败时有没有留下痕迹。别跳过 whoami、which、strace(Linux)或 Process Monitor(Windows)这些底层验证步骤。



















