在浏览器上从gridFS流式传输音频/视频文件


stream audio/video files from gridFS on the browser

我一直在尝试从mongoDB中读取一个音频文件,该文件是我使用GridFS存储的。我可以在系统中下载文件并从中播放,但我想从数据库本身流式传输这些音频/视频文件并在浏览器中播放。有没有办法在不将文件下载到系统的情况下做到这一点?任何帮助都是好的。

PHP GridFS支持有一个MongoGridFSFile::getResource()函数,它允许您将流作为资源获取,而不会在内存中加载整个文件。与fread/echo或stream_copy_to_stream结合使用,可以防止整个文件加载到内存中。使用stream_copy_to_stream,您可以简单地将GridFSFile流的资源复制到STDOUT流:

<?php
$m = new MongoClient;
$images = $m->my_db->getGridFS('images');
$image = $images->findOne('mongo.png');
header('Content-type: image/png;');
$stream = $image->getResource();
stream_copy_to_stream( $stream, STDOUT );
?>

或者,您可以在返回的$stream资源上使用fseek(),只将流的一部分发送回客户端。结合HTTP范围请求,您可以非常有效地完成这项工作。

如果其他配方失败,例如NginXphp-fpm,因为STDOUTfpm中不可用,则可以使用

fpassthru($stream);

而不是

stream_copy_to_stream( $stream, STDOUT );

因此,一个完整的解决方案看起来像:

function img($nr)
{
  $mongo = new MongoClient();
  $img = $mongo->ai->getGridFS('img')->findOne(array('metadata.nr'=>$nr));
  if (!$img)
    err("not found");
  header('X-Accel-Buffering: no');
  header("Content-type: ".$img->file["contentType"]);
  header("Content-length: ".$img->getSize());
  fpassthru($img->getResource());
  exit(0);
}

FYI:

在本例中:

  • 文件不是由文件名处理的,而是由存储在元数据中的数字访问的。提示:您可以设置一个唯一的索引,以确保任何数字都不能使用两次
  • 内容类型也是从GridFS中读取的,所以您不需要对其进行硬编码
  • 关闭NginX缓存以启用流式传输

这样你甚至可以处理其他事情,比如视频或html页面。如果您想启用NginX缓存,也许只在较大的大小上输出X-Accel-Buffering