I am downloading a WAV file from my remote server (Centos 5.8). using the following PHP script:
header('Content-Description: File Transfer');
header('Content-Type: audio/x-wav');
header('Content-Disposition: attachment; filename=' . basename($realLink));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($realLink));
ob_clean();
flush();
readfile($realLink);
When I try to play the downloaded file using either Windows Media Player or Itunes, it will not play. Even though the downloaded WAV on my local machine has a file size that is the same as the version of the file on the server, the downloaded file's properties show 00:00 length and will not play. Also, the file downloads and plays just fine if I manually download it using ftp. The apparent corruption only happens when I use the above script to download. I would appreciate any help with this.
The following are valid MIME types for WAVs:
audio/vnd.wave
audio/wav
audio/wave
audio/x-wav
You're using application/x-wav. See here and here for references.
This code work for download wav audio.
$ctype ='audio/x-wav'; // file type
$filepath = '/var/www/html/audio.wav';//absolute url
$size = filesize($fichero); // size of file
$name = basename($fichero); // name of file
$fp=fopen($fichero, "rb");
if ($size && $ctype && $fp) {
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: wav file");
header("Content-Type: " . $ctype);
header("Content-Disposition: attachment; filename=" . $name);
header("Content-Transfer-Encoding: binary");
header("Content-length: " . $size);
ob_clean();
fpassthru($fp);
}
Related
I've got a web from that has two buttons for submitting, one sends an email with pdf attached, this works perfectly.
The second button is to download the pdf, this is the problem. I am saving the pdf in a temp file before download but after it is downloaded the file doesn't open and it is corrupt. The pdf is about 30KB. I have tried solutions to similar questions but always the same result, the pdf won't open.
This didn't work
$fileName = "file.pdf";
$file_name = ("temp/file.pdf");
file_put_contents($file_name, $pdf_content);
$filepath=$file_name; //file location
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Content-Length: ' . filesize($file));
readfile($file);
This didn't work
$path = $_SERVER['DOCUMENT_ROOT']."/temp/"; // change the path to fit your websites document structure
$fullPath = $path.$fileName;
header("Cache-Control: public");
header("Content-Description: File Transfer");
header('Content-disposition: attachment;
filename='.basename($fullPath));
header("Content-Type: application/pdf");
header("Content-Transfer-Encoding: binary");
header('Content-Length: '. filesize($fullPath));
readfile($fullPath);
exit;
This didn't work
set_time_limit(0); // disable timeout
$file = $root_path.'/full-tile-book.pdf';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="NewName.pdf"');
header('Content-Length: ' . filesize($file));
$f = fopen($file, 'rb');
fpassthru($f);
fclose($f);
exit;
This didn't work
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);
header('Content-Type: application/pdf');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($filepath)) . ' GMT');
header('Content-disposition: attachment; filename=file.pdf');
header("Content-Transfer-Encoding: binary");
header('Content-Length: ' . filesize($filepath)); // provide file size
header('Connection: close');
readfile($filepath);
exit();
The file is always in the temp folder on the server and that works fine so somewhere in the download the file is getting corrupted.
I don't care how the download is done, pdf or oclet-stream or any other way.
I removed the : Content-Type header and it works for me.
Regards
This question already has answers here:
Downloading large files reliably in PHP
(13 answers)
Closed 9 years ago.
Using PHP, I am trying to serve large files (up to possibly 200MB) which aren't in a web accessible directory due to authorization issues. Currently, I use a readfile() call along with some headers to serve the file, but it seems that PHP is loading it into memory before sending it. I intend to deploy on a shared hosting server, which won't allow me to use much memory or add my own Apache modules such as X-Sendfile.
I can't let my files be in a web accessible directory for security reasons. Does anybody know a method that is less memory intensive which I could deploy on a shared hosting server?
EDIT:
if(/* My authorization here */) {
$path = "/uploads/";
$name = $row[0]; //This is a MySQL reference with the filename
$fullname = $path . $name; //Create filename
$fd = fopen($fullname, "rb");
if ($fd) {
$fsize = filesize($fullname);
$path_parts = pathinfo($fullname);
$ext = strtolower($path_parts["extension"]);
switch ($ext) {
case "pdf":
header("Content-type: application/pdf");
break;
case "zip":
header("Content-type: application/zip");
break;
default:
header("Content-type: application/octet-stream");
break;
}
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
header("Content-length: $fsize");
header("Cache-control: private"); //use this to open files directly
while(!feof($fd)) {
$buffer = fread($fd, 1*(1024*1024));
echo $buffer;
ob_flush();
flush(); //These two flush commands seem to have helped with performance
}
}
else {
echo "Error opening file";
}
fclose($fd);
If you use fopen and fread instead of readfile, that should solve your problem.
There's a solution in the PHP's readfile documentation showing how to use fread to do what you want.
To download large files from server, I have changed the below settings in php.ini file:
Upload_max_filesize - 1500 M
Max_input_time - 1000
Memory_limit - 640M
Max_execution_time - 1800
Post_max_size - 2000 M
Now, I am able to upload and download 175MB video on server.
Since, I have the dedicated server. So, making these changes were easy.
Below is the PHP script to download the file. I have no made any changes in this code snippet for large file size.
// Begin writing headers
ob_clean(); // Clear any previously written headers in the output buffer
if($filetype=='application/zip')
{
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
$fp = #fopen($filepath, 'rb');
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
{
header('Content-Type: "$content_type"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".filesize(trim($filepath)));
}
else
{
header('Content-Type: "$content_type"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize(trim($filepath)));
}
fpassthru($fp);
fclose($fp);
}
elseif($filetype=='audio'|| $filetype=='video')
{
global $mosConfig_absolute_path,$my;
ob_clean();
header("Pragma: public");
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-Type: application/force-download");
header("Content-Type: $content_type");
header("Content-Length: ".filesize(trim($filepath)));
header("Content-Disposition: attachment; filename=\"$filename\"");
// Force the download
header("Content-Transfer-Encoding: binary");
#readfile($filepath);
}
else{ // for all other types of files except zip,audio/video
ob_clean();
header("Pragma: public");
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-Type: $content_type");
header("Content-Length: ".filesize(trim($filepath)));
header("Content-Disposition: attachment; filename=\"$filename\"");
// Force the download
header("Content-Transfer-Encoding: binary");
#readfile($filepath);
}
exit;
If you care about performance, there is xsendfile, available in apache, nginx and lighttpd as module. Check the readfile() doc's users comments.
There are also modules for these webservers which accept a url with an additional hash value which allows downloading the file for a short time period. This can be also used to solve authorization issues.
You could also handle this in the style of the Gordian Knot - that is to say, sidestep the problem entirely. Keep the files in a non-accessible directory, and when a download is initiated you can simply
$tempstring = rand();
symlink('/filestore/filename.extension', '/www/downloads' . $tempstring . '-filename.extension');
echo('Your download is available here: <a href="/downloads/' . $tempstring . '-filename.extension">');
and setup a cronjob to unlink() any download links older than 10 minutes. Virtually no processing of your data is required, no massaging of HTTP headers, etc.
There are even a couple libraries out there for just this purpose.
I have a problem with reading pdf file in Chrome by using PHP.
The following code is how I do in PHP
$path = "actually file path";
header("Pragma: public");
header("Expires: 0");
header("Content-type: $content_type");
header('Cache-Control: private', FALSE);
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Disposition: inline; filename=\"$filename\"");
header('Content-Transfer-Encoding: binary');
header('Content-Length' . filesize($path));
ob_clean();
flush();
readfile($path);
In here, I set the Content-Disposition to inline. Because I want to display the pdf file if user browser have build-in pdf viewer plugin. As you may know, Chrome has build-in pdf viewer.
The problem is I have bunch of pdf files on the server. Only some of them can be viewed by Chrome. I can't figure out why others can not work the same way. I have checked the permission of each files. It looks like not the permission problem.
Is there anyone know what the problem is? Thank you.
I've been wrestling with this same issue. This is as close as I got to consistent results across browsers. I think that the reason you could be having problems is if some PDF's are too large for readfile() to handle correctly. Try this:
$file = "path_to_file";
$fp = fopen($file, "r") ;
header("Cache-Control: maxage=1");
header("Pragma: public");
header("Content-type: application/pdf");
header("Content-Disposition: inline; filename=".$myFileName."");
header("Content-Description: PHP Generated Data");
header("Content-Transfer-Encoding: binary");
header('Content-Length:' . filesize($file));
ob_clean();
flush();
while (!feof($fp)) {
$buff = fread($fp, 1024);
print $buff;
}
exit;
I had similar issue but I noticed the order matters. Seems that ; filename= must have quotes around it, Content-Disposition: attachment Try this:
$file = "/files/test.pdf";
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
$mime = finfo_file($finfo, $file);
header('Pragma: public');
header('Expires: 0');
header('Content-Type: $mime');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="'.basename($file).'"'));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Length' . filesize($file));
ob_clean();
flush();
readfile($file);
i've fixed this way
$path = 'path to PDF file';
header("Content-Length: " . filesize ( $path ) );
header("Content-type: application/pdf");
header("Content-disposition: inline; filename=".basename($path));
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
ob_clean();
flush();
readfile($path);
Had the same problem, chrome didn't display the inline PDF, stuck at loading. The solution was to add header('Accept-Ranges: bytes').
My complete code:
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="'.$title.'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: public, must-revalidate, max-age=0');
For me adding the following header fixed this annoying Chrome bug (?):
header('HTTP/1.1 200 OK');
After hours wasted this...i added comments to point out that #Kal has the only solution that worked. But somehow that's not enough...this is such an impossible and frustrating problem when Chrome does this:
Error Failed to load PDF document. Reload
Here is the diff that ended the torture.
- // Waste time with chrome:
- header("Content-type:application/pdf");
- header("Content-Disposition:attachment;filename=$file_basename");
- readfile($file);
exit();
---------------------------
+ // Deliver the file:
+ header('Pragma: public');
+ header('Expires: 0');
+ header('Content-Type: $mime');
+ header('Content-Description: File Transfer');
+ header('Content-Disposition: attachment; filename="'.basename($file).'"');
+ header('Content-Transfer-Encoding: binary');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Content-Length'.filesize($file));
+ ob_clean();
+ flush();
+ readfile($file);
exit();
For about thirty minutes i fooled with various variations of this...but i could not pin it down to "Add HTTP 200", not to "add bytes", not to "quote your filename", not to "separate the file ending". None of those worked.
(Thank you again #Kal).
I was having this issue, struggled for almost 6 hours and finally got it working. My solution is similar to the above answers but the above answers are not completed. There are three steps to solve this issue.
Step 1.
Go to php.ini file and add this line.
output_buffering = False
Step 2.
This error comes if you are opening a large PDF file. So, to solve this, just before adding headers, make sure you put these two lines.
set_time_limit(0);
ini_set('memory_limit', '100M'); //the memory limit can be more or less depending on your file
Step 3.
Add below headers and the code to read the file, so the final code would like this.
set_time_limit(0);
ini_set('memory_limit', '100M');
$file = "path/to/file.pdf";
header('Content-Type: application/pdf');
header('Content-Disposition: inline;
filename="yourfilename.pdf"'); //not the path but just the name
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: public, must-revalidate, max-age=0');
ob_clean();
flush();
readfile($file);
exit();
100% working solution. If you have any issues, let me know :)
I have the following code
header("Content-Description: File Transfer");
header('Content-Type: audio/mp3');
header("Content-Disposition: attachment; filename=" . $arrResults['audioLink'] . ".mp3");
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("Content-Transfer-Encoding: binary");
$strLink = 'http://ag-org.s3.amazonaws.com/members/tele_classes/' . $arrResults['audioLink'];
ob_clean();
flush();
readfile($strLink);
However when the download link is clicked that executes this code it always returns a 0 byte file. All files are set to public in the bucket.
What am I doing wrong here?
Is the .mp3 extension really not part of the filename as it's stored on S3?
You're appending .mp3 to the filename in the Content-Disposition header, but not the URL you're passing to readfile.
I'm trying to force a download so this is my code:
$file = 'test.m4r';
$mime = 'audio/aac';
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: $mime");
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename=' . basename($file));
readfile($file);
The file extension should be .m4r, even though the mime is aac. On some computers it's downloaded as test.m4r, while on other computers, the file has extension of test.m4r.acc. How do I fix this problem?
Thank you!
You can lie about the mimetype, but besides that there isn't anything you can do.
Try:
"application/octet-stream"
This might work, and is the default for unknown filetypes etc.
try this one
<?php header("Content-Type: application/force-download"); ?>