views:

389

answers:

5
+2  Q: 

PHP Streaming MP3

I have a very similar situation to the person who asked: http://stackoverflow.com/questions/1516661/can-i-serve-mp3-files-with-php Basically I am trying to protect mp3 files from direct download, so users have to go through php to get authenticated first. Here's my code:

header('Content-type: audio/mpeg');
header('Content-length: ' . filesize($file));
header('X-Pad: avoid browser bug');
Header('Cache-Control: no-cache');
header("Content-Transfer-Encoding: binary"); 
header("Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3");
readfile($file);

Here's my problem: The file only plays a very small chunk of the beginning (via Quicktime in the browser) and then stops - Quicktime seems to think the length of the file is only as long as the chunk it managed to download. When I reload - it plays a slightly larger chunk - whatever it managed to download up to that point.

Is that a problem in the headers I am sending? How would I stream such a file? Is it a problem if an swf is reading from that file?

Thanks!


Thank you guys for all the answers. Although none of these things were exactly what solved the problem, many of them sent me in the right direction. Much appreciated. For the full solution see my answer below

+1  A: 

I haven't used this myself yet, but the xmoovStreamingServer seems to offer the features you need. Maybe it's overkill for what you need, but it may not be.

The xmoovStream Server (formerly known as xmoov-php) is a centralized http streaming server written in PHP. It sits between your files and the world giving you control over many aspects of how your content is accessed. You can manage different kinds of content from different urls under a single installation.

Pekka
If you read through xmoov's source, you'll notice that all it does is effectively `while(!feof($fh)}` (not exactly the code, but close enough). I wouldn't say it's overkill, but it's a lot of really unnecessary wrapper code.
mattbasta
+1  A: 

if your server is running on apache or lighty, i would suggest you look into x-sendfile

http://tn123.ath.cx/mod_xsendfile/

this allows you to handle authentication in your php application, but let's your webserver handle the transmission of the file. the performance improvement you gain should be a nice additional benefit

roman
+1  A: 

You can try HTTP chunking. Set the "Transfer-Encoding" header to "chunked", then output the size of each chunk before sending it. End each chunk size and chunk with a CRLF.

For anything more complex, I recommend using a streaming server, such as Icecast.

outis
+1  A: 

Two things stand out:

  1. You've got a Content-Length set. If you server is set to automatically gzip your output, this can mess with things. Try turning off Content-Length and see if that fixes it.
  2. You've got about a thousand Content-Types set. Since it's Mp3 that you're serving, just use audio/mpeg. You can effectively get rid of the whole last header() command. It's easy to get carried away with HTTP headers.

Try it out and let us know how it goes!

mattbasta
A: 

Here's what did the trick.

$dir = dirname($_SERVER['DOCUMENT_ROOT'])."/protected_content";
$filename = $_GET['file'];
$file = $dir."/".$filename;

$extension = "mp3";
$mime_type = "audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3";

if(file_exists($file)){
    header('Content-type: {$mime_type}');
    header('Content-length: ' . filesize($file));
    header('Content-Disposition: filename="' . $filename);
    header('X-Pad: avoid browser bug');
    header('Cache-Control: no-cache');
    readfile($file);
}else{
    header("HTTP/1.0 404 Not Found");
}
yuval
You might want to do some validation/sanitising on $_GET['file'] before reading it...
Simon
I check if the file exists `if(file_exists($file)){`... Is that what you meant?
yuval
No he didn't mean that. Think for yourself, what happens if someone tries this http://yoursite.com/yourscript.php?file=../../../home/someonesgirlfriend/secretdiary.doc
Jonny