如何暂停通过PHP的shell_exec()启动的wget下载任务?
在PHP中实现Wget下载的暂停/恢复/终止
首先得说明:用shell_exec()启动wget的话,没法直接实现暂停——因为shell_exec()会一直阻塞到命令执行完毕,而且不会返回wget进程的PID(进程ID),自然没法发送中断信号。所以我们需要换一种方式启动wget,先拿到它的进程ID,再通过系统信号来控制。
核心思路
- 用
exec()启动后台运行的wget,同时捕获它的PID - 利用PHP的
posix_kill()函数发送系统信号:- 发送
SIGSTOP信号暂停进程(相当于让进程“休眠”) - 发送
SIGCONT信号恢复进程 - 发送
SIGINT信号终止进程(和终端按Ctrl+C效果一致)
- 发送
前提条件
确保你的PHP环境安装了posix扩展——这个扩展提供了和系统进程交互的函数。如果没装,比如在Ubuntu/Debian上可以通过apt install php-posix安装,然后重启PHP服务。
具体代码示例
1. 启动Wget并获取PID
先启动后台运行的wget,同时拿到它的进程ID,方便后续控制:
$filename = 'target_file.zip'; $file_url = 'https://example.com/large_file.zip'; // 构造命令:后台启动wget,重定向输出到/dev/null,最后返回PID $command = "wget -O {$filename} {$file_url} > /dev/null 2>&1 & echo $!"; exec($command, $output); // 提取PID(输出数组的第一个元素就是PID) $wget_pid = (int)$output[0]; // 可以把PID存在会话或数据库里,方便后续请求调用(比如Web页面的暂停按钮) session_start(); $_SESSION['wget_pid'] = $wget_pid; echo "Wget进程已启动,PID: {$wget_pid}";
2. 暂停下载
通过PID发送SIGSTOP信号,让wget进程暂停:
session_start(); $wget_pid = $_SESSION['wget_pid']; // 发送SIGSTOP信号 if (posix_kill($wget_pid, SIGSTOP)) { echo "下载已成功暂停"; } else { echo "暂停失败,请检查PID是否有效"; }
3. 恢复下载
发送SIGCONT信号让暂停的进程继续运行:
session_start(); $wget_pid = $_SESSION['wget_pid']; if (posix_kill($wget_pid, SIGCONT)) { echo "下载已恢复"; } else { echo "恢复失败,请检查PID是否有效"; }
4. 终止下载(模拟Ctrl+C)
发送SIGINT信号,和终端按Ctrl+C的效果一样,会终止wget进程:
session_start(); $wget_pid = $_SESSION['wget_pid']; if (posix_kill($wget_pid, SIGINT)) { echo "下载已终止"; } else { echo "终止失败,请检查PID是否有效"; }
注意事项
- 权限问题:确保PHP运行的用户(比如www-data)有权限发送信号给wget进程——因为wget是由PHP启动的,所以通常权限是匹配的,但如果是特殊环境需要额外检查。
- Web环境会话管理:如果是在Web页面中实现暂停/恢复,需要用会话(Session)或者数据库存储PID,因为每个HTTP请求都是独立的,没法直接共享变量。
- PID有效性:操作前最好检查PID对应的进程是否还存在,可以用
posix_getpgid($wget_pid)来判断,如果返回false说明进程已经结束。
内容的提问来源于stack exchange,提问作者Mostafa Elnaggar
相关产品推荐
相关产品推荐

