PHP File Down with header() - php

I have written the following code to allow download of files without the source being displayed.
In this example, the file 'test.pdf' is downloaded, but its corrupt.
Can anyone see any reason this would be the case?
$path = 'http://www.domain.org/images/uploads/test.pdf';
// Directory Path
$directory_path_filename = str_replace('http://www.domain.org/', '', $path);
$filepath = '/var/sites/l/domain.org/public_html/'.$directory_path_filename;
if ( file_exists( $filepath ) ) {
$finfo = finfo_open( FILEINFO_MIME );
header( 'Content-Type: application/pdf' );
header( 'Content-Disposition: attachment; filename= ' . basename( $filepath ) );
header( 'Content-Length: ' . filesize( $filepath ) );
header( 'Expires: 0' );
finfo_close( $finfo );
ob_clean( );
flush( );
readfile( $filepath );
exit;
}

Please use this method
$file receive the full path, $filename is the download filename.
public static function downloadFile($file, $filename)
{
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename = '.basename($filename));
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($file);
die;
}
}

Related

How to download zip with php without messy code

I want to download xxx.zip in my linux server.
And I got the code from php offical web site. The url is
http://php.net/manual/en/function.readfile.php
I have set content-Type: application/zip. But unlucky, when executing the download.php, I got messy code in firfox or chrome browser.
My linux charset and browser charset are both utf-8.
Here is my download.php code:
<?php
$file_name = "xxx.zip";
if (!file_exists ($file_name)){
echo "file is not exist";
exit();
}
else{
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($file_name).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_name));
readfile ($file_name);
exit;
}
?>
Compress xxx.zip code is:
<?php
$fileArr={1.jpg,2.jpg,3.jpg};
$fpName="xxx.zip";
$zip=new ZipArchive();
$zip->open($fpName,ZipArchive::CREATE);
foreach($fileArr as $file)
{
$zip->addFile("files/".$file,basename($file));
//$zip->renameName($file,$fileChName);
}
$zip->close();
?>
However, I can download xxx.zip file with xftp from linux server, and decompressing xxx.zip successfully in my windows desktop.
$file_name = "xxx.zip";
header("Cache-Control: no-cache, must-revalidate");
header("Expires: 0");
header("Content-Disposition: attachment; filename=\"" .basename($file_name)."\"");
header("Content-Length: " . filesize($file_name));
header("Content-Type: application/zip;");
readfile($file_name);
exit;
This will work.
A function I have used several times to download files might be of use
function sendfile( $filename=null, $filepath=null ){
if( file_exists( $filepath ) ){
if( !is_file( $filepath ) or connection_status()!=0 ) return false;
header("cache-control: no-store, no-cache, must-revalidate");
header("pragma: no-cache");
header("expires: ".gmdate("d, d m y h:i:s", mktime( date("h")+2, date("i"), date("s"), date("m"), date("d"), date("y")))." gmt");
header("content-type: application/octet-stream");
header("content-length: ".(string)( filesize( $filepath ) ) );
header("content-disposition: inline; filename={$filename}");
header("content-transfer-encoding: binary\n");
if( $file = #fopen( $filepath, 'rb' ) ) {
while( !#feof( $file ) and ( connection_status()==0 ) ) {
print( fread( $file, 1024*8 ) );
flush();
}
#fclose( $file );
}
return( ( connection_status()==0 ) and !connection_aborted() );
}
}
$file_name = "xxx.zip";
if( file_exists( $file_name ) ) sendfile( 'somefile.zip', $file_name );

How to solve the issue with downloading in PHP?

guys.
I am using a local server with laravel framework and trying to download file.
I tried many cases but nothing works for me.
The thing is I get no errors.
Downloading wont`t start but in response I have something like this:
�
���JFIF��;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 95��C
���}!1AQa"q2���#B��R��$3br�
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz���������������������������������������������������������������������������
���w!1AQaq"2�B���� #3R�br�
$4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������?���!�A���I��+�P�sB���i��?�Y�L��iG���B���Ap�����J;���;}ic=F{R�Z��
�$��z�q��~�p8�h�v?A#��;����t�#�Fx��Ǯq�S#<������qS-
That what I used:
tried this way:
$file = 'D:\Server\OpenServer\domains\memo.ru\public\img\avatars\\'.$file_name;
$filePath=$file;
and this:
$file = "http://example.com/img/avatars/1457091259.png";
1.
set_time_limit(0);
$file = #fopen($filePath, 'rb');
while ( !feof($file) ) {
print( #fread($file,1024*8) );
//ob_flush();
flush();
}
2
$handle = fopen($filePath, 'rb');
$buffer = '';
while ( !feof($handle) ) {
$buffer = fread($handle, 4096);
echo $buffer;
ob_flush();
flush();
}
fclose($handle);
3
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');
header('Pragma: public');
//header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
4
$real_path = 'D:\Server\OpenServer\domains\example.com\public\img\avatars\\';
$file = "http://example.com/img/avatars/1457091259.png";
$url = 'http://example.com/img/avatars/'.$tmpFileName;
$path = $real_path.$tmpFileName;
$fp = fopen($path, 'w');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_FILE, $fp);
$data = curl_exec($ch);
curl_close($ch);
fclose($fp);
If you're using Laravel 5 then this would be the most straightforward way:
public function download()
{
$file = base_path(). "public/img/avatars/1457091259.png";
$name = "Human Name For File.jpg";
$headers = ['Content-Type: application/octet-stream'];
return Response::download($file, $name, $headers);
}
Just name sure you have use Response at the top before the class
The application/octet-stream header should force the browser to download the file rather than display it in the browser window.
This should work
header('Content-Type: image/png');
header('Content-disposition: attachment; filename='.$fileName);
echo readfile($file);
die();
I have used the following quite successfully for downloading / sending files - perhaps it will be of use to you?
Call it like:
call_user_func( 'send_file', 'myfile.docx', 'c:/temp/document.docx' );
function send_file( $name, $strPath ) {
if( file_exists( $strPath ) ) {
if( !is_file( $strPath ) or connection_status()!=0 ) { return FALSE; }
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Content-Type: application/octet-stream");
header("Content-Length: ".(string)( filesize( $strPath ) ) );
header("Content-Disposition: inline; filename={$name}");
header("Content-Transfer-Encoding: binary\n");
if( $file = fopen( $strPath, 'rb' ) ) {
while( !feof( $file ) and ( connection_status()==0 ) ) {
print( fread( $file, 1024*8 ) );
flush();
}
fclose( $file );
}
clearstatcache();
return( ( connection_status()==0 ) and !connection_aborted() );
}
}

What is the correct syntax for defining filename with variables?

Regarding downloading files and defining the headers, I am having trouble assigning a dynamic filename to my files. When using the code below :
header("Content-Disposition: attachment; filename=test.csv");
A test.csv file is generated for download. However if I use this:
header('Content-Disposition: attachment; filename=' . $filename . '.csv');
It generates a .php file instead. Using this method also doesn't pass the Content-Disposition or filename to the header.
Full code:
session_start();
$file =$_SESSION['csvf'];
$filename = $file."_".date("Y-m-d_H-i",time());
header ( "Content-type: text/csv" );
header("Content-Disposition: attachment; filename=test.csv");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
print($file);
exit ();
What is the correct syntax?
EDIT
Working Code after suggestions
session_start ();
$file = $_SESSION ['csvf'];
$filename =date ( "Y-m-d_H-i", time () );
header ( "Content-type: text/csv" );
header ( "Content-Disposition: attachment; filename=".$filename );
header ( 'Expires: 0' );
header ( 'Cache-Control: must-revalidate' );
header ( 'Pragma: public' );
header ( 'Content-Length: ' . filesize ( $file ) );
print ($file) ;
exit ();
I don't see the path to example.csv specified on your code, you need to give the full path to $file, i.e.:
$mySession = $_SESSION['csvf'];
//since $_SESSION['csvf'] contains the actual data you cannot use it for filename
$filename = date("Y-m-d_H-i",time()).".csv";
//write $mySession contents to file. Make sure this folder is writable
file_put_contents("/home/site/csvfolder/$filename", $mySession);
$file = "/home/site/csvfolder/$filename";
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename='.$filename);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
Please Use Like as follows,I am using this for me.
header("Content-Type: application/vnd.ms-excel; charset=utf-8");
header("Content-Disposition: attachment; filename=".$fileName);
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
In place of application/vnd.ms-excel use your file format.It is for Microsoft Excel.
Try with this:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=test.csv');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
You can see more about download files with PHP here:
http://php.net/manual/en/function.readfile.php
Try With Below code , it's work for me
$file =$_SESSION['csvf'];
$filename = $file."_".date("Y-m-d_H-i",time()).".csv";
header ( "Content-type: text/csv" );
header("Content-Disposition: attachment; filename=".$filename);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
print($file);
exit ();
Below is a snippet for a .zip file with some descriptions on some information that header requires, perhaps a good practice is to get the information and some validations before writing headers.
Another shorter example is also included,
// defines filename, type, path, size and a reference to file (handler)
// to set as values for file header
$filename = $survey_id . '.zip';
// define path to the file to be get file size on the next line
$filepath = [path to file]. '/' . $filename;
// used by 'Content-length'
$filesize = filesize($filepath);
// using fopen to get a file handler, 'r' for read, 'b' for binary (zip file)
$file_pointer = fopen($filepath, 'rb');
// check if file exists
if(is_file($filepath))
{
// valid file?
if($filesize && $file_pointer)
{
// some required header information to describe file, see [docs][1]
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: zip file");
header("Content-Type: application/zip");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=" . $filename);
header("Content-Transfer-Encoding: binary");
header("Content-length: " . $filesize);
fpassthru($file_pointer);
// close
fclose($file_pointer);
}
}
Also, checkout readfile(), a shorter snippet below
<?php
$file = 'monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
?>
Hope this helps!
Just escape your php properly like so:
header('Content-Disposition: attachment; filename=' . time() . '.export.csv');
This example will put a UNIX timestamp prepended to the file name. Of course you could get crazy with programmatically using variables or inbuilt php functions, but this is just the example.
Here is more of an example. This file name will be produced when running this php code.
2019-05-18-contacts-main-export-by-Garrick.csv
header('Content-Disposition: attachment; filename=' . date("Y-m-d") . '-contacts-main-export-by-' . $uidName . '.csv');

pdf file not downloading

I am using following code to start downloading but the pop-up for download is not opening. Instead, it shows the binary format of that pdf file. It's working perfectly on local server but not working hosted server.
$file = '../Notes/chapter01.pdf';
if (file_exists($file)) {
header('Content-Description: File Transfer');
// header('Content-Type: application/octet-stream');
header('Cache-Control: public'); // needed for i.e.
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
//header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_end_clean();
flush();
readfile($file);
exit;
}
else {
die('Error: File not found.');
}
This code works.
$file = '../Notes/chapter01.pdf';
$mime_type = 'application/pdf';
$filesize = filesize( $file );
header( "Content-type:" . $mime_type );
header( "Content-Length:" . $filesize );
header( "Content-Disposition: attachment; filename=" . $file );
header( "Cache-Control: private, max-age=15" );
#readfile( $file );
Hope this helps.

Why is my downloaded file is always damaged or corrupted?

I have a very weird problem with my download script
it basically
1.gets a file id with "GET" method
2.gets the name and location of that file from database
3.sends it to the client with the headers and readfile
but strangely that file always comes out as corrupted or damaged
like if it's a zip or rar file
file size is right and it opens ok
but i cant open compressed files inside of it and that's when i get the file damaged error
which is weird cuz if the code had a problem i shouldn't even be able to open the zip file(or at least i think i shouldn't)
another thing is i've printed out the file with it's path right before sending the headers just to be sure everything is ok
I've put the file address on the url and download the file , file was ok with no errors
so everything is fine before sending the headers
here is my code
$file_id = isset($_GET['id']) && (int)$_GET['id'] != 0 ? (int)$_GET['id'] : exit;
//////// finging file info
$file = comon::get_all_by_condition('files' , 'id' , $file_id );
if(!$file) exit;
foreach($file as $file){
$location = $file['location'];
$filename = $file['file_name'];
}
/////////////
$site = comon::get_site_domian();
$ext = trim(end(explode('.' , $filename )));
$abslout_path = 'http://'.$site.'/'.$location.'/'.$filename;
$relative = $location.'/'.$filename;
////////////////// content type
switch($ext) {
case 'txt':
$cType = 'text/plain';
break;
case 'pdf':
$cType = 'application/pdf';
break;
case 'zip':
$cType = 'application/zip';
break;
case 'doc':
$cType = 'application/msword';
break;
case 'xls':
$cType = 'application/vnd.ms-excel';
break;
case 'ppt':
$cType = 'application/vnd.ms-powerpoint';
break;
case 'gif':
$cType = 'image/gif';
break;
case 'png':
$cType = 'image/png';
break;
case 'jpeg':
case 'jpg':
$cType = 'image/jpg';
break;
default:
$cType = 'application/force-download';
break;
}
//////////////// just checking
if(!file_exists($relative)){
echo $relative;
echo '<br />';
exit;
}
if( !is_readable( $relative ) )
exit('its not redable');
if( headers_sent() )
exit('headers ? already sent !! ');
header( 'Pragma: public' );
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($_SERVER['SERVER_PROTOCOL'].' 200 OK');
header( 'Content-Type:'.$cType);
header( 'Content-Disposition: attachment; filename="'. basename($filename) . '";' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Content-Length: ' . filesize($relative) );
readfile($abslout_path);
exit;
I've checked the headers couple times and they are fine(i think) , I've also add every headers known to man just to be sure !
I'm starting to think maybe it's something other than script
like char encoding or folder permission ! or something like that !!
am i missing something ?
That seems allot of code just to force-download, here is a nice function I use all the time. It will handle files over 2GB too.
<?php
$file_id = (isset($_GET['id']) && (int)$_GET['id'] != 0) ? (int)$_GET['id'] : exit;
/*finding file info*/
$file = comon::get_all_by_condition('files', 'id', $file_id);
$path = $file['location'] . '/' . $file['file_name'];
if (!is_file($path)) {
echo 'File not found.('.$path.')';
} elseif (is_dir($path)) {
echo 'Cannot download folder.';
} else {
send_download($path);
}
return;
//The function with example headers
function send_download($file) {
$basename = basename($file);
$length = sprintf("%u", filesize($file));
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $basename . '"');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $length);
set_time_limit(0);
readfile($file);
}
?>
if (file_exists($file)) {
set_time_limit(0);
header('Connection: Keep-Alive');
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($file);
}
Very nice, helpful also...
but there is a problem in your code -
header('Content-Disposition: attachment;
filename="'.basename($file).'"';
please change it with this following -
header('Content-Disposition: attachment;
filename="'.basename($file).'"');
you are forgot to close it.
Your script may contain NOTICE or WARNING, try disabling error reporting on top of your script:
error_reporting(0);
Make sure you do not have any code executed after the last line readfile(FILE_NAME)
I had to add die(); or exit(); as the last line, because MVC framework continues to render the view after readfile

Categories