I currently have the following:
if (headers_sent()) {
echo 'HTTP header already sent';
} else {
if (!is_file($path)) {
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
echo 'File not found';
} else if (!is_readable($path)) {
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
echo 'File not readable';
} else {
ob_start();
header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
header('Content-Description: File Transfer');
header("Content-Type: octet-stream");
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header("Content-Length: ".filesize($path));
header("Content-Disposition: attachment; filename=\"".basename($path)."\"");
ob_clean();
ob_flush();
readfile($path);
exit;
The above code produces a file download of the correct file name, but with a twist.
The downloaded file has some html from the download page (headers being sent incorrectly?) then later in the downloaded document there is gibberish text (ex. OJQJ^J.??. WW8Num2z0) taking up several pages. Finally at the end of the .doc I can read some English which appears to be the correct text of the .doc, but with no formatting.
These issues persist in Chrome and Mozilla.
Any help would be greatly appreciated. Thanks in advance.
EDIT:
I began testing with a .doc that has only one line of text: "test"
The file can be opened manually from the directory in which it is uploaded to, and verified that it is not corrupt. However, downloading this file using any of the methods recommended thus far yields several pages of gibberish text (the real file is only 1 line). The actual text of the file, which is "test", is found on the very last of the 66 pages of gibberish, and it is found in this haystack: ?test ?"ᄚ? ᄚ?!ᄚn"ᄚn#ミn$ミn3P(20???՜.モラ+,??՜.モラ+,???Root Entry???????? ?F#CompObj????jOle ????????1Table????????????ᆬSummaryInformation(?????WordDocument????????????"$DocumentSummaryInformation8????????????[t????????????????
What are these?
header("Content-Type: octet-stream");
header("Content-Transfer-Encoding: binary");
Trim down your code to a working example and extend it from there. You do not need to set the status code, PHP does this for you. You do not need to set the Content-length either. Sending only this should just work:
$path = 'foo.dat';
if (headers_sent()) {
echo 'HTTP header already sent';
} else {
if (!is_file($path)) {
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
echo 'File not found';
} else if (!is_readable($path)) {
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
echo 'File not readable';
} else {
header("Content-Disposition: attachment; filename=\"".basename($path)."\"");
readfile($path);
}
}
Try this excerpt for the last else that is without any flushing functions
header("HTTP/1.1 200 OK");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".basename($path));
header("Content-Description: File Transfer");
#readfile($path);
Related
Very lost right now. The filePath to this document is correct and is in the directory that is being printed by the echo but it keeps saying "file not found".
$fileName = 'driver.txt';
$filePath = $_SERVER['DOCUMENT_ROOT']."/driver.txt";
echo $filePath;
if(!file_exists($filePath)){ // file does not exist
die('file not found');
} else {
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$fileName");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
// read the file from disk
readfile($filePath);
}
Very silly mistake, tried downloading a different file and it worked. I then realized the file's name was driver.txt. So PHP was looking for driver.txt.txt. I appreciate all the help.
I am trying to download a large file using the script below. The file downloads, but its named 'download' and the file extension is missing. How can I modify the code below so that the original file name and extension is preserved ? Also is there anyway to automatically detect the mime type and include that as well ?
Thanks a lot in advance.
$path = 'public/Uploads/Films/files/Crank2006.avi';
$size=filesize($path);
$fm=#fopen($path,'rb');
if(!$fm) {
// You can also redirect here
header ("HTTP/1.0 404 Not Found");
die();
}
$begin=0;
$end=$size;
if(isset($_SERVER['HTTP_RANGE'])) {
if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
$begin=intval($matches[0]);
if(!empty($matches[1])) {
$end=intval($matches[1]);
}
}
}
if($begin>0||$end<$size)
header('HTTP/1.0 206 Partial Content');
else
header('HTTP/1.0 200 OK');
header("Content-Type: video/avi");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Connection: close');
$cur=$begin;
fseek($fm,$begin,0);
while(!feof($fm)&&$cur<$end&&(connection_status()==0))
{ print fread($fm,min(1024*16,$end-$cur));
$cur+=1024*16;
usleep(1000);
}
die();
In Content Disposition header you need to specify file name
$file_url = 'what you want to set'
header("Content-disposition: attachment; filename=\"" . $file_url. "\"");
A good tutorial on forced download php here.
PHP Force Download.
For mime type see the following SO post
Detecting mine-type in PHP.
Just do this below the $path
$path = 'public/Uploads/Films/files/Crank2006.avi';
$filename = array_pop(explode('/',$path)); // Grabbing the filename ... it will be Crank2006.avi
and add the header with filename to your existing headers.
header("Content-disposition: filename=$filename");
EDIT:
Detecting MIME type...
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, $filename);
Try Something Like Below
$file='test.pdf' //File to download with Large Size
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile('backup/'.$file);
return 1;
} else {
return 0;
}
I'm downloading a file through php script and everything work perfectly except one ugly truth. The downloaded file keep the same url and with original name appended. How do I maintain the same filename when file downloaded?
http://bachday.com/index.php?page=custom&file=mmailer/download.php?mfile=sample.docx
if (isset($_GET['mfile'])) {
$file = $_SERVER['DOCUMENT_ROOT'].'/oc-content/plugins/mmailer/pfile/'.$_GET['mfile'];
if (file_exists($file) && is_readable($file) && preg_match('/\.docx$/',$file)) {
header('Content-Type: application/docx');
header("Content-Disposition: attachment; filename=\"$file\"");
readfile($file);
/*
header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
echo (readfile($file));*/
}
else
{
header("HTTP/1.0 404 Not Found");
echo "Error 404: File Not Found: $file";
}
header('Content-Disposition: attachment; filename="name_of_file_here"') would have done the trick. You are passing the full path of the file there as header("Content-Disposition: attachment; filename=\"$file\""); since your $file contains full path. Instead just send the name of the file.
header('Content-Disposition: attachment; filename='.basename($file));
This line can perhaps solve the issue.
if (isset($_GET['mfile'])) {
$file = $_SERVER['DOCUMENT_ROOT'].'/oc-content/plugins/mmailer/pfile/'.$_GET['mfile'];
if (file_exists($file) && is_readable($file) && preg_match('/\.docx$/',$file)) {
header('Content-Type: application/docx');
header("Content-Disposition: attachment; filename=\"".basename($file)."\"");//use basename to extract filename from full file path
readfile($file);
/*
header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
echo (readfile($file));*/
}
else
{
header("HTTP/1.0 404 Not Found");
echo "Error 404: File Not Found:
$file";
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
try to download file and getting invalid file in response in core php
$filename=gallery/downloads/poster/large/h.jpg
path to download file is correct but don't know why it give invalid file in return ...
$filename = $_GET["filename"];
$buffer = file_get_contents($filename);
/* Force download dialog... */
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header('Content-Type: image/jpeg');
/* Don't allow caching... */
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
/* Set data type, size and filename */
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . strlen($buffer));
header("Content-Disposition: attachment; filename=$filename");
/* Send our file... */
echo $buffer;
if u have a better way then please share .... thanks in advance .
A better solution would be:
$filename = $_GET["filename"];
// Validate the filename (You so don't want people to be able to download
// EVERYTHING from your site...)
if (!file_exists($filename))
{
header('HTTP/1.0 404 Not Found');
die();
}
// A check of filemtime and IMS/304 management would be good here
// Be sure to disable buffer management if needed
while(ob_get_level()) {
ob_end_clean();
}
// Do not send out full path.
$basename = basename($filename);
Header('Content-Type: application/download');
Header("Content-Disposition: attachment; filename=\"$basename\"");
header('Content-Transfer-Encoding: binary'); // Not really needed
Header('Content-Length: ' . filesize($filename));
Header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
readfile($filename);
That said, what does "invalid file" mean? Bad length? Zero length? Bad file name? Wrong MIME type? Wrong file contents? The meaning may be clear to you with everything under your eyes, but from our end it's far from obvious.
below is some part of code in my download gateway
if (!isset($_GET['f']) || empty($_GET['f'])) {die("<h1>URL Malfunction</h1><br/><p><i>Please Try Later</i>");}
if (strpos($_GET['f'], "\0") !== FALSE){ die("<h1>URL Malfunction</h1><br/><p><i>Please Try Later</i>");}
#Check URL, find resource Path
$fileName = basename($_GET['f']);
$file_path=(string)makeDownloadFilePath($fileName,"dir");
if(!is_file($file_path)){die("<h1>404 Not found</h1><br/><p><i>The resource you requested is not available</i>");}
$fileSize = filesize($file_path);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public"); #Build Response#
header("Content-Description: File Transfer");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=\"$fileName\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $fileSize);
$file = #fopen($file_path,"rb");
if ($file) {
while(!feof($file)) { #File Transfer#
print(fread($file, 1024*8));
flush();
if (connection_status()!=0) {
#fclose($file);
die();
}
}
#fclose($file);
//The File is Downloaded . Closing Connections
I am using GET method to receive the filename. The filename and its path will e genrated from gateway. Now the problem is When i click on download in a page, instead of showing a Download dialog, the browser just renders the file content as text on screen. For eg, i am downloading foo.mp3. the binary contents are displayed as weird text on screen.
Its echoing a warning like: We cannot change the Headers. headers already sent to ...
Can any one tell , where i had made the mistake?
Thanks
We cannot change the Headers. headers already sent to..
This error comes when you print any thing before php your header command.
The most common cause of this error by a long, long way is that you have some leading white-space before the opening <?php tag in your file (or one of it's includes).
The < should be the first character in the file, anything before it is written to the output buffer directly and will probably result in the headers being sent. When forcing file download in this manner, it will also result in corrupted files.
Use readfile instead of fopen as follow and use ob_clean() , ob_flush() :
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$Name.'"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: '.filesize($musicPath));
ob_clean();
flush();
readfile($musicPath);
ob_flush();
Are you using the output buffer?
try adding ob_start(); before you send out the header information, this may solve your issue.
You can find out more information about it here
Thanks all for the help. The problem was i was using a
error_reporting(E_ALL);
ini_set('display_errors', true);
flush();
for debugging in one of my includes.
I just removed it.Now it works.