How can I allow users to download pictures saved on the server? The goal is to have the user click on a link and have a specified image to start to download.
Facebook example:
Make the link to another .php page, not the image. Then on that page use the content-disposition header like this:
<?php
// Define the name of image after downloaded
header('Content-Disposition: attachment; filename="file.jpg"');
// Read the original image file
readfile('file.jpg');
?>
From there, you can just add the filename of the image in a get command like
`download.php?filename=file`
then reference that in the file as:
readfile($_GET['filename'].'.jpg')
You need to set a specific header on the response that delivers the image in order to force a download.
Content-Disposition: attachment; filename=myawesomefilename.png
Otherwise it will just load up in browser.
So send that header and then just link to the path that delivers that image with that header.
Send a header to tell the browser to download it like this:
header("Content-type: application/force-download")
Then send them the data for the file itself without any HTML or anything.
This example is snipped from the PHP docs
<?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('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);
exit;
}
?>
If by "download pictures saved on the server" you mean "try to make the browser offer a 'save as' dialog box instead of just displaying the image" then you might want to look into using the Content-Disposition: attachment header in the response that serves the image:
Content-Disposition: attachment; filename="thefilename.jpg"
You can set headers in php using the header function.
Related
I have a file download code using php and my code at download page is follows.
if (file_exists($strDownload)) {
//get the file content
$strFile = file_get_contents($strDownload);
//set the headers to force a download
header("Content-type: application/force-download");
header("Content-Disposition: attachment; filename=\"" . str_replace(" ", "_", $arrCheck['file_name']) . "\"");
//echo the file to the user
echo $strFile;
//update the DB to say this file has been downloaded
mysql_query("xxxxxxxx");
exit;
}
Where the function file_exists() passed with valid check and my $strDownload variable will be something like /home/public_html/uploads/myfile.zip which is located in server folder. But when I trying to download the file instead of downloading, the page displays the full encrypted source of the file. How can I make it downloadable?
EDIT: for the information, myself trying to use this bit of code inside the wordpress system and my file path will be something like http://example.com/wp-content/uploads/2016/02/myfile.zip. Also in the above mentioned code myself checking the file_exists() condition for the server path which is already mentioned above and it returns 1 as desired.
Try this
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');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
It is solved by using the above bit of codes at beginning of php page. Ie, before declaring the famous wordpress tag get_header();
If we use the above code after get_header(); tag of wordpress, it results in the opening of page first and hence it writes the source of the file in the page instead of downloading since the meta tags are already set.
I am handed over a PHP Code-igniter project by my Manager, and i have not a dependable experience in PHP. Im trying to download a newly created .csv file from server. But when i download it, it does not have the content of that file, instead it shows the header stript of my .html page where im doing the whole coding.
i am trying this using Force Downloading technique, mentioned all over internet.
$filename = $_SERVER['DOCUMENT_ROOT'] . '/apps/views/style/Default/files/'.'Attendance'.'_'.strtotime("now").'.csv';
$file = $filename;
if (is_file($file) == true) {
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header("Pragma: public", true);
header("Content-Transfer-Encoding: binary");
header('Content-Length: ' . filesize($file));
readfile($file);
}
This code runs on a button click, and the File does download, but it does not show the content, but when i manually download that same file directly from Cpanel server, it has content.
When i download it through this coding, it has the html scripts.
It is because you have the code inside a page, which already have html content displayed or in buffer to be displayed, you will have to implement your force download code inside a blank page or keep the code on top of page, so it give you download of the file content only.
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
readfile($file);
User on my site can download files. Sometimes these files are pretty large and I would like users to see download progress bar at their browsers.
I use the following code to give user a file:
header('Content-Type: text/xml');
header('Content-Disposition: attachment; filename='.$fileName);
header('Pragma: no-cache');
header('Content-Transfer-Encoding: binary');
header('Pragma: public');
header('Content-Length: '.filesize($fullFileName));
header("Content-Description: File Transfer");
$fileHandler = fopen($fullFileName, 'r');
while(!feof($fileHandler)){
echo fread($fileHandler, 2048);
}
fclose($fileHandler);
When I run this script browser(FireFox) freezes for some time, I can see loading colour circle and only after save/open dialog file appears. When I click on "save" button, file almost immediately is downloaded to my computer(while file is quite large - 50 Mb).
I want to have downloading system like on this site. Dialog for save/opean appears immediately when you click on any links. And after you can see downloading progress in your browser.
Are there any special headers to display progress bar in browser? How I should change my code?
I use the code below, and in Firefox it does give me the download time and progress:
// send headers first
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Content-disposition: attachment; filename='.$FileName);
header("Content-Length: ".filesize($Path));
// then use an easy way to flush and end all output buffers
while (#ob_end_flush());
// flush file
readfile($Path);
It should work if you specify Content-Length correctly. The only thing I find mildly weird in your code is the Content-Type: text/xml header. Note that I use Content-type: application/octet-stream.
What I'm trying to do:
Im trying to push a jpg file to download witout user seeing the URL. In this case the file is located at: http://www.example.com/upload/asdasdsadpokdaspdso/36.jpg.
My current code:
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$download->name.'.jpg"');
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
My vars / db values:
$weburl = "http://wwww.example.com";
$hiddenpassage = "asdasdsadpokdaspdso";
$download->link = 36.jpg //not a var, just drom db.
$download->name = The First Test Product //not a var, just from db.
The problem:
When I get the download I open it and I get the following error:
The file “The First Test Product (28).jpg” could not be opened.
It may be damaged or use a file format that Preview doesn’t recognize.
Renaming .jpg to .txt:
http://pastebin.com/K9NGL5RP
Most of that is the content of the page I downloaded it from.
I think you need to specify the whole header (untested). Specially the Content-Length.:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$download->name.'.jpg');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($weburl."/upload/".$hiddenpassage."/".$download->link));
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
Hope this helps.
This one should be easy, I think. I have a paginated image gallery, and under each image is a small link that says "Download Comp". This should allow people to quickly download the .jpg file (with a PHP generated watermark) to their computer.
Now, I know I can just link straight to the .jpg file, but that requires the user to have the image open in a new window, right click, Save As..., etc. Instead, I want the "Download Comp" link to initiate the download of the file immediately.
PHP.net seemed to suggest using readfile(), so each "Download Comp" link is being echoed as "?download=true&g={$gallery}&i={$image}".
Then at the top of the page I catch to see if the $_GET['download'] var isset, and if so, I run the following code:
if(isset($_GET['download'])) {
$gallery = $_GET['g'];
$image = $_GET['i'];
$file = "../watermark.php?src={$gallery}/images/{$image}";
header('Content-Description: File Transfer');
header('Content-Type: application/jpeg');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: public');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
}
The link takes a lonnnnnnnnng time, and then it brings up a dialog prompt asking you to Open or Save the file, but once you Save and try to open it, it says the file is corrupt and can't be opened.
Any ideas?
Don't set $file to a relative url. The readfile function will try to access the php file on the server. That is not what you want. In your case it looks like the watermark.php file will send the contents you want, so you could possibly just set up the environment it needs and include it.
<?php
if(isset($_GET['download'])) {
$gallery = $_GET['g'];
$image = $_GET['i'];
$_GET['src'] = "{$gallery}/images/{$image}";
header('Content-Description: File Transfer');
header('Content-Type: image/jpeg');
header('Content-Disposition: attachment; filename='.basename($image));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: public');
header('Pragma: public');
ob_clean();
include('../watermark.php');
exit;
}
Another (simpler) way is to modify watermark.php. Add a query parameter to make it send the proper headers to force a download and link to that
...
watermark.php:
<?php
if (isset($_GET['download']) && $_GET['download'] == 'true') {
header('Content-Description: File Transfer');
header('Content-Type: image/jpeg');
header('Content-Disposition: attachment; filename='.basename($src));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: public');
header('Pragma: public');
}
// continue with the rest of the file as-is
Also, you don't need the call to flush(). There should not be any output to send at that point, so it is not necessary.
header('Content-Type: image/jpeg');
Perhaps?
I think you might need to follow the call to readfile() with a call to exit() to make sure nothing else gets written to the output buffer.
This seems like a security issue.
What if someone enters:
$g = '../../../../../../';
$i = '../../sensitive file at root';
How about making .htaccess (if you are using apache) i for the gallery directory serve jpegs up as a download rather than normal.
Also, try file_get_contents() instead of readfile(). I find it works under more circumstances. I would also recommend you use ob_flush() after you output the image data. I've never needed to use ob_clean() or flush() to get this kind of thing to work.
And as Eric said, you may also want to put a call to exit() in there as well for good measure if it still isn't working just in case you are getting some junk data stuck at the end.