I'm trying to send files (attachments) for users outside webroot. I made force download script, which sends the file in the header and outputs it in stream. This works good, until I call readfile (could be also header settings), which outputs a file which contains a half of my html source (of this specific page). I did file_get_contents() and the file contained the proper string: "test". What is the problem here?
<?php
//The path where the files are stored
$file_path = "";
if(isset($_GET['file'])) {
$file_path = $_GET['file'];
}
else {
header('HTTP/1.0 404 Not Found');
die('File not found!');
}
$file_name = basename($_GET['file']);
//Make sure the file exists
if(!file_exists($file_path) && !is_file($file_name)) {
header('HTTP/1.0 404 Not Found');
die('File not found!');
}
//Initialize the actual file.
$file = $file_path;
//Notice: Remember to set fifo extension in php.ini
//Windows users must include the bundled php_fileinfo.dll DLL file in php.ini to enable this extension.
$finfo = new finfo(FILEINFO_MIME);
$mime = "";
if(function_exists("finfo_open")) {
$finfo = finfo_open(FILEINFO_MIME);
$mime = finfo_file($finfo, $file);
}
// Provide a default type in case all else fails
else {
$mime = "application/octet-stream";
}
//Set the appropriate content-type and provide the content-length.
header('Content-Description: File Transfer');
header('Content-Transfer-Encoding: binary');
header('Content-type: '.$mime);
header('Content-Disposition: attachment; filename='.$file_name);
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: '.filesize($file));
//Print the image data
readfile($file);
exit;
?>
The $file is called test.txt and contains string "test". Mime/content-type is proper.
The output of this script however is html source.
From the readfile docs, they make two call before the readfile (with a forced download): ob_clean() & flush(). My assumptions is they call these to make sure headers have been sent and the client understands there's content coming.
I suggest adding those in there, and it should work.
Related
I'm trying to download a .rar file from a cloud (for sake of simplicity I'm using my google drive storage), the file is downloading perfectly, but once i want to open the .rar file , it says that "the archive is either unknown format or damaged" , tried all methods even cURL ,but it didnt want to work,
Im just wondering what I'm missing in my code, thank you
<?php
$filename = 'stu.rar';
if ( file_put_contents( $filename,file_get_contents("mygoogleDriveLink/search?q=stu.rar"))) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
//header('Content-Length: '.filesize($filename));
readfile($filename);
//print_r("this is ".$id);
exit();
}
else{
echo "err";
}
You may use file_put_contents to save the file to the server first, before you stream it to your browser.
if you do not need to stream to user's web browser, then you may remove the codes from start streaming to end streaming.
Please try the following:
<?php
// Initialize a file URL to the variable
$url = 'http://www.xxxxxxxxxxx.com/xxxxx.rar';
// Use basename() function to return the base name of file
$file_name = basename($url);
// Use file_get_contents() function to get the file
// from url and use file_put_contents() function to
// save the file by using base name
if(file_put_contents( $file_name,file_get_contents($url))) {
// File successfully saved in the server
// start streaming . The following is to stream and save to browser
$file_name = $file_name;
$file_url = $file_name;
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"".$file_name."\"");
readfile($file_url);
exit;
/// end streaming
}
else {
echo "File downloading failed.";
}
?>
I want to download image file in php.
<?php
if(isset($_REQUEST["file"])){
$filepath = BASE_URL.'assets/uploads/save_template_images/template1_221594899972.png';
// Process download
if(file_exists($filepath)) {
echo $filepath;
exit;
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
flush(); // Flush system output buffer
readfile($filepath);
die();
} else {
echo $filepath;
exit;
http_response_code(404);
die();
}
}
?>
In my index page, I have an anchor tag and if click on anchor tag then above code run. I am not showing anchor tag because, I put the $filepath static value in above code. When I run above code then it goes on else condition. I think, full path of project is not taking by above code. If I put image in same folder then it downloads.
First ensure allow_url_fopen setting in php.ini file is turned on. After that Use this code to download your file:
<?php
$url = 'https://lokeshdhakar.com/projects/lightbox2/images/image-5.jpg';
$file = './files/'.basename($url);
file_put_contents($file, file_get_contents($url));
?>
For successful download, files directory must be exists. But I think it would be inefficient to add directory existence check as I think you already know where to save the file you are downloading.
I am not able to open the file after the download.
It says the the file has been corrupted.
I guess i have used all the required headers fine.
In chrome it shows error like:
chrome resource interpreted as document but transferred with mime type application/octet-stream
In Firefox no error msg.
if (isset($_GET['file']) && basename($_GET['file']) == $_GET['file']) {
$filename = $_GET['file'];
} else {
$filename = NULL;
}
$err = 'Sorry, the file you are requesting is unavailable.';
if ($filename) {
// define the path to your download folder plus assign the file name
$path = '/wp-content/uploads/'. $filename;
// check that file exists and is readable
if (file_exists($path)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'. basename($path) . '"');
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($path));
ob_end_clean();
flush();
readfile($path);
exit;
}
}
download: getting downloaded from ftp folder.
None of the formats are opening.
.txt is getting opened.
Let me know if i am in wrong direction.
Inserting into table:
echo "<tr><a href='?file=". $row["FileupName"]."'>".$row["FileupName"]."</td></tr>";
readfile('$path') is your issue, it should be readfile($path) (with no quotes)
In PHP, variables are only evaluated in strings if the string is defined in double quotes ". Effectively you're downloading a file where the contents is the literal string '$path', with an incorrect filesize.
I'm creating a website on my localhost that should let people download some .rar files.
In my index I've created some tags like this:
$filename = "Test001.rar";
'.$filename.'';
This is just an example of one single file, but in my php file 'download.php' I've got the problem when I want to download the .rar file
This is download.php
<?php
echo "Welcome to Knowledge!";
if (isset($_GET['file']) && basename($_GET['file']) == $_GET['file'])
{
$file = $_GET["file"];
$path = 'C:\xampp\htdocs\TestSite'."\\".$file;
}
$err = $path.'Sorry, the file you are requesting doesnt exist.';
if (file_exists($path) && is_readable($path))
{
//get the file size and send the http headers
$size = filesize($path);
header('Content-Type: application/x-rar-compressed, application/octet-stream');
header('Content-Length: '.$size);
header('Content-Disposition: attachment; filename='.$file);
header('Content-Transfer-Encoding: binary');
readfile($filename);
}
?>
It opens the stream in the right way, but I get that the file size is about 200 bytes and not the full length that is about 200MB.
How can I fix this problem?
Remove the echo statement, there should not be any output before the headers. Change readfile($filename) to readfile($file)
I have set up a page using php and mysql that requires user to log in to download various paid for programs. They can click on a link as here and the program downloads and runs correctly.
$c3 = mysql_result($result,$i,"exe");
echo "<a href='$c3'>... etc
However, RT-click properties lets them see the path to that file, so I changed the above to:
$c3="downloads3.php?link=".mysql_result($result,$i,"exe");
Where downloads3.php is as follows:
<?php
$file = $_GET['link'];
$size = filesize($file);
$type = filetype($file);
$path = "../downloads/";
header('Content-Type: $type');
header("Content-Transfer-Encoding: Binary");
header("Content-Disposition: attachment; filename=$path.$file");
header("Content-Length: ".filesize($file));
readfile($file_url);?>
?>
It finds the correct file and I get a security warning but on clicking run anyway it immediately gives a windows error message that the file is not compatible with this version of windows. Must be something in the above header but can't figure out what. Tried various permutations.
Any brill ideas, either of getting the above to work or other ways of hiding the source path? Thanks.
It's far more likely that the EXE is getting corrupted due to unexpected output. Your downloads3.php file has some extra output that will appear in the download:
readfile($file_url);?> //PHP stops parsing here
?> //output "\n?>"
The PE header itself tells Windows what versions it can run on, so if any errors get generated before the file gets sent, they'll appear in the place Windows is expecting the header.
To mitigate this you can remove the extra newline and ?> at the end of the file and turn error reporting off with error_reporting(0) at the top of the file.
The Best solution for here to get download file with any name what do you have want
function force_download($filename = '', $data = '')
{
if ($filename == '' OR $data == '')
{
return FALSE;
}
// Try to determine if the filename includes a file extension.
// We need it in order to set the MIME type
if (FALSE === strpos($filename, '.'))
{
return FALSE;
}
// Grab the file extension
$x = explode('.', $filename);
$extension = end($x);
// Load the mime types
if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes'.EXT))
{
include(APPPATH.'config/'.ENVIRONMENT.'/mimes'.EXT);
}
elseif (is_file(APPPATH.'config/mimes'.EXT))
{
include(APPPATH.'config/mimes'.EXT);
}
// Set a default mime if we can't find it
if ( ! isset($mimes[$extension]))
{
$mime = 'application/octet-stream';
}
else
{
$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
}
// Generate the server headers
if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
{
header('Content-Type: "'.$mime.'"');
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: ".strlen($data));
}
else
{
header('Content-Type: "'.$mime.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".strlen($data));
}
exit($data);
}
$data = 'Here is some text!';
$name = 'mytext.txt';
force_download($name, $data);
DOH!!!!!!!!!!!!!!!! Too much cutting and pasting, that code has a really stupid error readfile($file_url) should be readfile($file), no wonder my 36Mb file was only 1KB after download, it was empty!
Thanks for all the comments, apologies for wasting your time.