PHP:立即返回响应,但在后台运行多个冗长的shell_exec函数

PHP:立即返回响应,但在后台运行多个冗长的shell_exec函数,php,asynchronous,ffmpeg,shell-exec,Php,Asynchronous,Ffmpeg,Shell Exec,我正在创建一个简单的web服务,它接受视频上载,在视频上运行多个不同的编码(mp4、webm、ogv),然后将新创建的文件上载到我们的视频主机 假设我有多个命令 shell_exec('ffmpeg -i input.mp4 -f mp4 -c:v libx264 -preset slow -crf 24 -s 1280x720 -c:a libfdk_aac -profile:a aac_he -ar 22050 -b:a 64k -movflags +faststart output-128

我正在创建一个简单的web服务,它接受视频上载,在视频上运行多个不同的编码(mp4、webm、ogv),然后将新创建的文件上载到我们的视频主机

假设我有多个命令

shell_exec('ffmpeg -i input.mp4 -f mp4 -c:v libx264 -preset slow -crf 24 -s 1280x720 -c:a libfdk_aac -profile:a aac_he -ar 22050 -b:a 64k -movflags +faststart output-1280x720.mp4');

shell_exec('ffmpeg -i input.mp4 -f mp4 -c:v libx264 -preset slow -crf 24 -s 1920x1080 -c:a libfdk_aac -profile:a aac_he -ar 22050 -b:a 64k -movflags +faststart output-1920x1080.mp4');

shell_exec('ffmpeg -i input.mp4 -f ogg -c:v libtheora -q:v 5 -s 1280x720 -c:a libvorbis -ar 22050 -b:a 64k -movflags +faststart output-1280x720.ogv');

shell_exec('ffmpeg -i input.mp4 -f ogg -c:v libtheora -q:v 5 -s 1920x1080 -c:a libvorbis -ar 22050 -b:a 64k -movflags +faststart output-1920x1080.ogv');
总之,我想

  • 打印即时响应:{success:true}
  • 同步启动多个ffmpeg作业
  • 每个作业完成后,向另一台服务器发送一篇文章(每个shell_exec发送一篇文章)
  • 如果作业成功,只发送帖子也很好,但是我可以通过检查服务器上是否存在输出文件来轻松解决这个问题

    我知道我可以强制shell_exec在后台运行,只需将
    /dev/null 2>/dev/null&
    添加到每个命令中即可--这将允许我立即打印响应--但我认为这样做会导致所有作业并行运行,而且,由于这会转移输出,当作业完成时,我没有收到任何真正的回调


    有什么想法吗???

    我决定采用异步请求文件的想法。为了保持它的整洁,我能够将它全部包含在一个文件中,该文件使用不同的POST请求“重新调用”自身

    $root_path = $_SERVER['DOCUMENT_ROOT'] . '/';
    $root_http = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . '/';
    
    function request_async($url, $params, $type='POST', $timeout=30) {
      foreach ($params as $key => &$val) {
        if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
      }
      $post_string = implode('&', $post_params);
    
      $parts = parse_url($url);
    
      $fp = fsockopen(
        $parts['host'],
        isset($parts['port']) ? $parts['port'] : 80,
        $errno,
        $errstr,
        $timeout
      );
    
      if ('GET' == $type) $parts['path'] .= '?'.$post_string;
    
      $out = "$type ".$parts['path']." HTTP/1.1\r\n";
      $out.= "Host: ".$parts['host']."\r\n";
      $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
      $out.= "Content-Length: ".strlen($post_string)."\r\n";
      $out.= "Connection: Close\r\n\r\n";
    
      if ('POST' == $type && isset($post_string)) $out .= $post_string;
    
      fwrite($fp, $out);
      fclose($fp);
    }
    
    function get_http_path($path, $relative = FALSE){
      global $root_http, $root_path;
      return str_replace($root_path, $relative ? '/' : $root_http, $path);
    }
    
    $url = $_POST['url'];
    $media = $_POST['media'];
    
    if (isset($url)) {
      request_async(get_http_path(__FILE__), array(media => $url), 'POST', 1800);
      echo '{"success": true}';
    } else
    if (isset($media)) {
      $data = file_get_contents($media);
      // KICK OFF JOBS HERE
      echo '{"success": true}';
    } else {
      echo '{"success": false}';
    }
    

    我决定采用异步请求文件的思想。为了保持它的整洁,我能够将它全部包含在一个文件中,该文件使用不同的POST请求“重新调用”自身

    $root_path = $_SERVER['DOCUMENT_ROOT'] . '/';
    $root_http = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . '/';
    
    function request_async($url, $params, $type='POST', $timeout=30) {
      foreach ($params as $key => &$val) {
        if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
      }
      $post_string = implode('&', $post_params);
    
      $parts = parse_url($url);
    
      $fp = fsockopen(
        $parts['host'],
        isset($parts['port']) ? $parts['port'] : 80,
        $errno,
        $errstr,
        $timeout
      );
    
      if ('GET' == $type) $parts['path'] .= '?'.$post_string;
    
      $out = "$type ".$parts['path']." HTTP/1.1\r\n";
      $out.= "Host: ".$parts['host']."\r\n";
      $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
      $out.= "Content-Length: ".strlen($post_string)."\r\n";
      $out.= "Connection: Close\r\n\r\n";
    
      if ('POST' == $type && isset($post_string)) $out .= $post_string;
    
      fwrite($fp, $out);
      fclose($fp);
    }
    
    function get_http_path($path, $relative = FALSE){
      global $root_http, $root_path;
      return str_replace($root_path, $relative ? '/' : $root_http, $path);
    }
    
    $url = $_POST['url'];
    $media = $_POST['media'];
    
    if (isset($url)) {
      request_async(get_http_path(__FILE__), array(media => $url), 'POST', 1800);
      echo '{"success": true}';
    } else
    if (isset($media)) {
      $data = file_get_contents($media);
      // KICK OFF JOBS HERE
      echo '{"success": true}';
    } else {
      echo '{"success": false}';
    }
    

    只是一个想法。。。如果为每个命令创建一个新的PHP脚本,然后调用该脚本直接运行该命令?在脚本结束时,您可以向服务器发送操作已完成的通知。您可以始终将该代码放在另一个PHP文件中,并使用CURL作为外部文件调用它,例如,在CURL中设置非常低的超时。另外,你的第二行有三个单引号,打破了代码:)。这两个建议都很好。我要试一试。如果有效的话,我会汇报的。这很有效,谢谢你的建议!ogv输出不需要
    -movflags+faststart
    ;这只适用于mov/mp4多路复用器。代替旧的,GrayBurd定理,考虑使用LVVPX用于VP8/VP9视频和WebM中的OPUS音频。如果为每个命令创建一个新的PHP脚本,然后调用该脚本直接运行该命令?在脚本结束时,您可以向服务器发送操作已完成的通知。您可以始终将该代码放在另一个PHP文件中,并使用CURL作为外部文件调用它,例如,在CURL中设置非常低的超时。另外,你的第二行有三个单引号,打破了代码:)。这两个建议都很好。我要试一试。如果有效的话,我会汇报的。这很有效,谢谢你的建议!ogv输出不需要
    -movflags+faststart
    ;这只适用于mov/mp4多路复用器。代替旧的,GrayBurd定理,考虑使用LVVPX用于VP8/VP9视频和WebM中的OPUS音频。