在页面关闭后继续php exec()ffmpeg

在页面关闭后继续php exec()ffmpeg,php,html,post,ffmpeg,Php,Html,Post,Ffmpeg,我想知道在exec()()关闭页面后如何继续php页面 我有一个表单,允许人们用ffmpeg转换他们的视频文件,但是如果用户点击离开页面,exec()会继续运行,但是这个exec之后的任何内容都不会被执行 <?php if (!empty($_POST) && $imgDir) { exec('"/dir/to/ffmpeg" -f image2 -i "' . $imgDir . '" -r 12 -s 610x489 /dir/to/out.avi',

我想知道在
exec()
()关闭页面后如何继续php页面

我有一个表单,允许人们用ffmpeg转换他们的视频文件,但是如果用户点击离开页面,exec()会继续运行,但是这个exec之后的任何内容都不会被执行

<?php
   if (!empty($_POST) && $imgDir) {
      exec('"/dir/to/ffmpeg" -f image2 -i "' . $imgDir . '" -r 12 -s 610x489 /dir/to/out.avi', $out);

      /* INSERT statement (Not being executed) */
      $sql = "INSERT INTO requests (userID,image) VALUES (?,?)";
      $stmt= $pdo->prepare($sql);
      $stmt->execute([$user_id, $imgDir]);
   }
?>

这类场景中的常见解决方案是将转换过程卸载到后台脚本(例如,由cron定期触发的作业)。这避免了长时间运行的进程超时的问题,或者外部命令行进程不能正确返回的问题

网页只需将请求放入队列(例如,在db表中)并保存文件

然后,后台服务将从队列中选取下一个项目,对其进行处理,并将其标记为完成


<>你必须考虑如何通知用户。你可以给他们发电子邮件,或者有一个状态页面,在那里他们可以检查他们的工作,下载任何准备好的文件,或者两者都可以,或者你选择的其他过程。也许您可以允许用户指定如何通知他们。

如果您想在后台从PHP启动此命令,可以通过以下模式运行非阻塞进程:

if(is_resource($proc = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes)))
{
    stream_set_blocking($pipes[1], false);
    stream_set_blocking($pipes[2], false);
在Linux系统上,您可以使用前置的
nohup
启动命令,例如:

$cmd = 'nohup "/dir/to/ffmpeg" -f image2 -i "' . $imgDir . '" -r 12 -s 610x489 /dir/to/out.avi'

使用
nohup
后,您甚至可以退出启动新流程的流程。它将与父进程分离。

您可能希望将转换进程卸载到后台脚本(例如,由cron定期触发的作业)。网页只需将请求放入队列(例如,在db表中)并保存文件。然后,后台服务将从队列中选取下一个项目,对其进行处理,并将其标记为完成。然后你必须考虑如何通知用户。你可以给他们发电子邮件,或者有一个状态页面,在那里他们可以检查他们的工作,下载任何准备好的文件,或者两者都可以,或者你选择的其他过程。也许您可以允许用户指定如何通知他们。您确定没有执行INSERT查询吗?可能只是SQL查询失败了……您是否已将PDO设置为在发生异常时抛出异常?您正在记录异常吗?我还注意到SQL块不在
if(!empty($\u POST).
块内,因此即使用户没有提交任何数据,SQL块也会执行……我怀疑这是可取的。@ADyson您是对的,我认为在后台运行该程序更好。队列非常适合于多人同时转换。(我以错误的方式复制了代码,查询在实际代码中的if语句中。)这是在后台运行ffmpeg还是在整个php文件/进程中运行?@Tygo
proc_open
启动一个新的系统进程,类似于
exec
和其他系统函数,但使用管道而不是通过引用返回函数值/参数。
stream\u set\u blocking
从流读取时不等待EOF。Howev呃,当父进程在不等待子进程完成的情况下完成时,除非您使用
nohup
linux命令分离子进程,否则子进程仍然会被杀死。简言之:子进程,即
ffmpeg
在后台运行。@Tygo如果您不想,您甚至不需要使用管道和设置非阻塞模式从子级的STDOUT/STDERR接收输出数据(运行并忘记)。