PHP Conference Japan 2024

proc_terminate

(PHP 5, PHP 7, PHP 8)

proc_terminate终止由 proc_open 打开的进程

描述

proc_terminate(资源 $process, 整数 $signal = 15): 布尔值

向一个进程(使用proc_open()创建)发送信号,指示其终止。proc_terminate()立即返回,不等待进程终止。

proc_terminate()允许您终止进程并继续执行其他任务。您可以使用proc_get_status()函数轮询进程(查看其是否已停止)。

参数

process

将要关闭的proc_open() 资源

signal

此可选参数仅在 POSIX 操作系统上有用;您可以使用kill(2)系统调用指定要发送给进程的信号。默认为SIGTERM

返回值

返回运行的进程的终止状态。

参见

  • proc_open() - 执行命令并打开用于输入/输出的文件指针
  • proc_close() - 关闭由 proc_open 打开的进程并返回该进程的退出代码
  • proc_get_status() - 获取由 proc_open 打开的进程的信息

添加注释

用户贡献注释 4 条注释

csh dot spam at me dot com
11 年前
/bin/sh -c CMD 将派生 sh,然后执行 CMD。
/bin/sh -c exec CMD 不会派生,只会执行 CMD。

因此,您可以通过在命令前添加“exec bla bla bla”来去除此 hack。
jerhee at ucsd dot edu
16 年前
http://bugs.php.net/bug.php?id=39992, 中所述,proc_terminate() 会使子进程的子进程继续运行。在我的应用程序中,这些子进程通常具有无限循环,因此我需要一种确保杀死使用 proc_open() 创建的进程的方法。当我调用 proc_terminate() 时,/bin/sh 进程被杀死,但具有无限循环的子进程仍然在运行。

在 proc_terminate() 得到修复之前,我不建议使用它。相反,我的解决方案是
1) 调用 proc_get_status() 以获取要杀死的进程的父进程 ID (ppid)。
2) 使用 ps 获取所有以该 ppid 作为其父进程 ID 的 pid。
3) 使用 posix_kill() 向每个子进程发送 SIGKILL (9) 信号。
4) 对进程资源调用 proc_close()。

<?php
$descriptorspec
= array(
0 => array('pipe', 'r'), // stdin 是一个子进程将从中读取的管道
1 => array('pipe', 'w'), // stdout 是一个子进程将写入的管道
2 => array('pipe', 'w') // stderr 是一个子进程将写入的管道
);
$process = proc_open('bad_program', $descriptorspec, $pipes);
if(!
is_resource($process)) {
throw new
Exception('bad_program 无法启动。');
}
//向程序传递一些输入
fwrite($pipes[0], $lots_of_data);
//关闭 stdin。通过关闭 stdin,程序在处理完输入后应该退出
//。
fclose($pipes[0]);

//做一些其他事情...如果我们立即检查,进程可能仍在运行
//。

$status = proc_get_status($process);
if(
$status['running'] == true) { //进程运行时间过长,杀死它
//关闭所有仍在打开的管道
fclose($pipes[1]); //stdout
fclose($pipes[2]); //stderr
//获取要杀死的进程的父进程 ID
$ppid = $status['pid'];
//使用 ps 获取此进程的所有子进程,并杀死它们
$pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $ppid`);
foreach(
$pids as $pid) {
if(
is_numeric($pid)) {
echo
"正在杀死 $pid\n";
posix_kill($pid, 9); //9 是 SIGKILL 信号
}
}

proc_close($process);
}

?>
v dot denegin at yahoo dot com
10 年前
在 Windows 平台上,proc_terminate() 不会杀死未处理 kill 信号的子进程。即使您调用 xxx.exe 并调用 proc_terminate(),进程也将保持活动状态。

解决方案是,不要调用 proc_terminate(),而是调用用户定义的 kill() 函数(已针对 win/unix 进行优化)
之后需要关闭所有管道并执行 proc_close()。

function kill($pid){
return stripos(php_uname('s'), 'win')>-1 ? exec("taskkill /F /T /PID $pid") : exec("kill -9 $pid");
}

function killall($pids) {
$os=stripos(php_uname('s'), 'win')>-1;
($_=implode($os?' /PID ':' ',$pids)) or ($_=$pids);
return preg_match('/success|close/', $os ? exec("taskkill /F /T /PID $_") : exec("kill -9 $_"));
}

示例

$pstatus = proc_get_status($resource);
$PID = $pstatus['pid'];

// 其他命令

kill($PID); // 而不是 proc_terminate($resource);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($resource);
smcbride at msn dot com
3 年前
只是一个小的提示,以便人们不必去其他地方查找

要获取进程列表或按名称查找进程,请使用
$proclist = shell_exec('ps -elF') 用于 Linux
$proclist = shell_exec('tasklist') 用于 Windows

之后,您可以使用 php 的常规解析函数获取 pid
To Top