Php exec()应该是异步的,但它不是';T

Php exec()应该是异步的,但它不是';T,php,bash,server,yii2,imagick,Php,Bash,Server,Yii2,Imagick,我正在使用yii2框架创建一个web应用程序,它运行在一个带有PHP的apacheweb服务器上(服务器是Ubuntu) 该应用程序的很大一部分涉及用户上传视频,通过FFMpeg运行的视频将被重新保存两次,一次作为MP4,另一次作为WEBM。FFMpeg还提取一帧,然后通过Imagick运行该帧以正确调整大小 所有这些都需要花费大量的时间,因此,我选择将所有处理放在控制台命令中,然后在后台异步运行,并在视频处理完成后向用户发送电子邮件,而不是向用户显示可能需要5-10分钟的加载屏幕 以下是上传表

我正在使用yii2框架创建一个web应用程序,它运行在一个带有PHP的apacheweb服务器上(服务器是Ubuntu)

该应用程序的很大一部分涉及用户上传视频,通过FFMpeg运行的视频将被重新保存两次,一次作为MP4,另一次作为WEBM。FFMpeg还提取一帧,然后通过Imagick运行该帧以正确调整大小

所有这些都需要花费大量的时间,因此,我选择将所有处理放在控制台命令中,然后在后台异步运行,并在视频处理完成后向用户发送电子邮件,而不是向用户显示可能需要5-10分钟的加载屏幕

以下是上传表单模型的相关部分:

// if the new database entry successfully saved
if($video->save()){

    // define the target filename and full target filepath
    $target_name = uniqid();
    $target_path = Yii::getAlias('@webroot'). '/videos/' . $target_name;

    // get the current working directory (should be /models)
    $cwd = getcwd();

    // move up one directory to the app base 
    chdir('../');

    // prepare the shell command to process the video
    $command = escapeshellcmd("php yii video/process " . $fileFullPath . " " . $target_name . " " . $target_path . " " . $video->id . " " . $video->name . " " . Yii::$app->language . " " . Yii::$app->homeUrl . " " . $this->email . " >/dev/null 2>&1 &");

    // execute the shell command
    exec($command);

    // change the working directory back to the original
    chdir($cwd);

    // return the ID of the uploaded video
    return $video->id;
}
在shell命令的末尾,您可以看到/dev/null重定向,该重定向将导致命令异步执行,从而允许PHP脚本继续并将上载的视频ID返回给控制器

下面是VideoController方法操作流程的一个略为缩短的版本:

public function actionProcess($source_path, $target_name, $target_path, $id, $first_name, $language, $homeUrl, $email)
{
    $ffmpeg = FFMpeg\FFMpeg::create(['timeout' => 7200, 'ffmpeg.threads' => 4]);
    $video = $ffmpeg->open($source_path);
    $dimension = new FFMpeg\Coordinate\Dimension(1280, 1280);

    $video
        ->filters()
        ->resize($dimension, 'inset')
        ->synchronize();

    $video
        ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(2))
        ->save($target_path . '.png');

    $video
        ->save(new FFmpeg\Format\Video\X264(), $target_path . '.mp4')
        ->save(new FFMpeg\Format\Video\WebM(), $target_path . '.webm');

    @unlink($source_path);

    $image = Imagick::open($target_path . '.png');

    //////////
    // There's a big if statement here controlling whether to crop the image vertically or horizontally to get the desired size.
    // Didn't seem necessary to include.
    //////////

    $image->saveTo($target_path . '.png');

    $video = Video::find()->where(['id' => $id])->one();
    $video->path = $target_name;
    $video->published = Video::IS_PUBLISHED;
    $video->save();

    //////////
    // There's another large code block here to send an email to the user.
    // Also didn't seem necessary to include.
    //////////

    return 0;
}
正如您可能知道的,我正在使用PHP FFmpeg库()调用FFmpeg,并且正在使用tpmanc的Yii2 Imagick库()实现Imagick

因此,尽管如此:exec()命令应该以异步方式实现,但事实并非如此。上传视频会导致视频被上传,然后在视频处理过程中再等待5-10分钟并完成,最后加载“成功上传”页面

事情是这样的:它起作用了。我在开发周期的早期就对它进行了测试,结果很好。然后我在shell命令上注释掉了/dev/null重定向,这样我可以在开发时进行调试,现在我又重新添加了它,它似乎不再工作了。是什么原因导致上述命令不能异步执行

编辑:我还应该补充的是,所做的唯一更改是对控制台执行的PHP脚本所做的。在执行实际命令本身(上传表单模型)的脚本工作和不工作之间,没有对脚本进行任何更改。因此,要么是我遗漏了一个明显的输入错误,要么是console命令中的某个内容覆盖了/dev/null重定向,并强制表单模型等待脚本完成,这似乎实际上是不可能的,尽管在这方面我可能是错的

更新:我使用Cron来完成这个任务,而不是每次上传视频时手动调用脚本。也就是说,我认为这个问题应该保持开放,因为实际问题尚未解决:为什么上面的exec()不能异步执行


最后编辑:好了,下面是投票表决的仙女们。考虑问题关闭。

< P>我有同样的问题,多年前的视频。PHP不是异步的。我建议您使用React PHP()或创建JobQueue和/或Cron任务列表来处理这个问题。您可以创建视频,并在向用户显示视频时上载,显示消息,“渲染”,并在未向用户创建缩略图时为视频创建一个示例缩略图

我使用Yii创建了这个示例,但之后搜索效果更好

问题是,这以前已经奏效了。我正在用yii2重新创建一个应用程序,这是我以前在“原始”PHP中创建的,那时我还不知道框架是什么东西(这显然是很久以前的事了)。如果它在那里起作用,我看不出它在这里不起作用的理由,除非Yii以某种方式进行干预。除此之外,它甚至在三、四天前还在Yii中工作。“您可以看到/dev/null重定向,它应该导致命令异步执行”。不完全是。命令末尾的符号指示shell在后台执行命令。如果你要做后台任务,你应该使用一个真正的异步任务队列,比如芹菜。