stream audio/video files from gridFS on the browser

五迷三道 提交于 2019-12-08 19:54:25

The PHP GridFS support has a MongoGridFSFile::getResource() function that allows you to get the stream as a resource - which doesn't load the whole file in memory. Combined with fread/echo or stream_copy_to_stream you can prevent the whole file from being loaded in memory. With stream_copy_to_stream, you can simply copy the GridFSFile stream's resource to the STDOUT stream:

<?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 );
?>

Alternatively, you can use fseek() on the returned $stream resource to only send back parts of the stream to the client. Combined with HTTP Range requests, you can do this pretty efficiently.

Tino

If the other recipe fails, for example with NginX and php-fpm, because STDOUT is not available in fpm, you can use

fpassthru($stream);

instead of

stream_copy_to_stream( $stream, STDOUT );

So a complete solution looks like:

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:

In this example:

  • File is not acccessed by the filename, instead it is accessed by a number stored in the metadata. Hint: You can set an unique index to ensure, that no number can be used twice.
  • Content-Type is read from GridFS, too, so you do not need to hardcode this.
  • NginX caching is switched off to enable streaming.

This way you can even handle other things like video or html pages. If you want to enable NginX caching, perhaps only output X-Accel-Buffering on bigger sizes.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!