My question is simply: how can I output an mp3 with PHP that is seekable? I believe I have the appropriate headers set and I have tried with both readfile() and fopen() because my research has led me to believe that readfile() does not support byteranges and fopen() does. However, I really don't understand how to work with or set byteranges, just that I apparently need to. I am playing the song through jPlayer and the song plays fine, but it not seekable. In other words, you can't skip through the song by clicking different places on the seek bar.
Here is the code that is outputting the mp3 file:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); // required for certain browsers
header("Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3");
header("Content-Disposition: inline; filename=" . $file . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($path));
//readfile("$path");
$music = fopen($path, 'r');
fseek($music, 0);
fpassthru($music);
exit();
If I need to read the Range header, how do I do that?
I've spent days trying to solve the same thing. I'm yet to crack it, but I have noticed this.
Mp3s aren't skipping ahead (due to quicktime grabbing the first byte then going back to the rest)
soundcloud streams (which are mp3) however, are letting me skip ahead (when played through the same player)
I suspect you might find the solution in the the soundcloud headers (since they somehow cracked it).
Related
I have searched and exhausted every solution I could find on stack overflow but with no joy.
Basically, I have a folder of images/videos. .htaccess redirects all requests to a .php file that checks a user can view these videos against a paywall, or redirects them to login. If the user is authorised then it sends the file. This works perctly for images and small videos.
However, once the video gets up to 500mb - 1GB I start getting: "The media could not be loaded, either because the server or network failed or because the format is not supported." On playing said video. Wierder still this seems only to be on safari or chrome.
Firefox plays these videos without any issue what so ever.
Here is my code to output the video:
$mime = mime_content_type($_SERVER['DOCUMENT_ROOT'].'/uploadvideos/'.$video);
ob_clean();
ob_flush();
flush();
header('Expires: 0');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: pre-check=0, post-check=0, max-age=0');
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Length: ".filesize(trim($_SERVER['DOCUMENT_ROOT'].'/uploadvideos/'.$video)));
// Force the download
header("Content-Type: ".$mime);
header('Content-Length: '.filesize($_SERVER['DOCUMENT_ROOT'].'/uploadvideos/'.$video));
readfile($_SERVER['DOCUMENT_ROOT'].'/uploadvideos/'.$video);
Can anyone see any headers that might be missing that I need to add or something to get this working properly, as it is literally driving me insane and I just cant fathom out what the cause is here.
I have added numerous header options but to no joy. I tried this one that some seemed to think from other Stackoverflow posts:
header("Content-Transfer-Encoding: binary");
$size = filesize(trim($_SERVER['DOCUMENT_ROOT'].'/uploadvideos/'.$video));
$begin = 0;
$end = $size - 1;
header("Content-Range: bytes $begin-$end/$size");
But this seemed to make the situation worse, and removing it made it at least work in Firefox.
I'm using a script to download video, but it take lot of time to download. Are there any processes or other scripts that could help me?
// set headers
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: $mtype");
header("Content-Disposition: attachment; filename=\"$asfname\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fsize);
// download
// #readfile($file_path);
$file = #fopen($file_path,"rb");
if ($file) {
while(!feof($file)) {
print(fread($file, 1024*100));
flush();
if (connection_status()!=0) {
#fclose($file);
die();
}
}
#fclose($file);
}
Using the readfile() function (as you originally had) will allow you to spool directly from the file to output, rather than using a chunking loop and printing as you're doing. So why have you chosen to do this chunk loop?
As above, readfile() is one way.
The other, even more preferred method depends on your webserver. NginX, Lighttpd and there's also a module for Apache, allows you to pass a header with a filepath/name to the server, and it will send the file directly from the server itself, and so not need to use PHP resources to do it. If thats not possible, then readfile() is the best you probably have - if you can't just give someone a direct URL to download it.
I'm trying to force download a image file (jpg for example) using php. So I have a script here force.php and here would be the code:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header('Content-Description: File Transfer');
header("Content-Type: image/jpeg");
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename=test.jpg');
readfile($file);
Now the problem is for some browsers (mobile phone browsers especially), it'll work properly and prompt test.jpg for the user to save. However on some browser, it'll prompt force.php as download. Any solution?
Thank you!
Content disposition header highly depends on how a particular browser implements it. Sometimes there are encoding issues (I do not see in your case).
The document at Test Cases for HTTP Content-Disposition shows behavior for various browsers.
To be safe with mobile browsers you should consider having the http request's last part be equal to the actual filename of the attachment, for example http://some.url/download/test.jpg .
Use apache mod_rewrite or similar to route such requests to your download script.
I'm offering a sermon downloading site and I have a user experiencing an issue with his download. Anyone have any ideas on how I can improve this code, or perhaps send better headers...
$path = "http://www.domain.com/sermon_files/".date("Y", $array["preached"])."/".$array["filename"];
$corePath = "/home/user/public_html/sermon_files/".date("Y", $array["preached"])."/".$array["filename"];
if (!file_exists($corePath)) {
echo "An error has occured with this download.";
} else {
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: audio/mp3");
header("Content-Disposition: attachment; filename=\"".$array["title"]."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($corePath));
readfile($path);
exit();
}
Take a look at this thread, I had similar problems: PHP: Force file download and IE, yet again. Also consider using Fiddler to capture the exact HTTP headers that are being sent to the client.
Combine your PHP ( ? ) code with a server with X-Send available, lighttpd has it so does apache
Watch out for Expires: 0 on downloads. This messes with IE6's tiny little brain and makes it think there is no data to save/open. Try expiring in a minute from access and see if that fixes the problem. Otherwise, tell us exactly what the problem is.
Normally, when I want to allow a user to download a file without revealing the exact location, I just use something like this to let them download the file:
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"" . $filename) . "\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($filename));
readfile("$filename");
But if they are using a modern browser or other download client, and they pause the download and try to resume it, the script (assuming they are still authenticated or whatever) will resend the headers and the file contents from the beginning, thus breaking the download, and basically requiring the file to be redownloaded from the beginning.
How can I enable my script to compensate for paused (and consequentially, resumed) downloads?
Use php's built-in fopen to open the file and then fseek to the right place (based on the range in the request header) and then return the partial file using fpassthru instead of using readfile.
You can find some example code in php under the comments for fread
You need to read the request headers like Range, If-Range, etc then seek to the correct location in the file. Normally a web-server would do this for you on an ordinary file. It's a bit complex but here's something that might get you started:
http://forums.asp.net/t/1218116.aspx
http://www.notes411.com/dominosource/tips.nsf/0/480C4E3BE825F69D802571BC007D5AC9!opendocument
For the second link the code is in part 12