I am working on a little resize and download image kind of php script wherein the events must happen in the following fashion :
A visitor uploads an image file.
The image is resized by the script.
A download link to the resized image appears in the front-end.
My resizing code is ready and working but I need help with the third part, that is how do I offer a download link to the recently created image. Here is a gist of how the resized image is created i the php script.
<?php
//normal validation stuff happens here
//resizing stuff happens here
//here is last part of the code that creates the resized image
$filename = uniqid();
$file = 'uploads/'.$filename.'.jpeg';
imagejpeg($new, $file, 80);
imagedestroy($new);
This download link must prompt as a download box instead of opening a new tab. Headers is what I know is needed in case we need to offer a download link. But this is useless to me unless I understand a right approach to this. Also please understand that my situation may be a little different as this is not a download link for a static-resource. Here the images to be downloaded are created dynamically at every request, everytime.
While I am struggling on my own a solution, will be great otherwise please provide me a road-map of what steps should be taken or what are functions that I will need to get this done. Thanks in advance.
Step 1 - User is uploading picture and you are saving it on server (you can resize it now) with new unique name (maybe md5 from time()?). On response page you can give link like this www.mypage.com/downloadimg.php?fileid=54gj6hg45h654g where last part is generated file name.
Step 2 - User clicks download link. You just have to send headers from Hanky 웃 Panky answer and then file_get_contents().
You can force a download using proper headers.
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
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: ' . filesize($file));
Related
I have created a movie which I have saved as an MP4 file and uploaded to my server. The file is 4.6 GB. When I have tried to send a link to my family, the video tries to play in their browser.
What I want to do is have them click a link and the file downloads to their computer instead. I have searched endlessly for solutions, but they all keep failing, probably due to the size of the file.
Is anyone able to help with a PHP script that will allow the downloading of such a large file?
Thanks
The easiest solution is to press Ctrl+S, select File>Save or do right click + Save as in the browser when the file starts to load - this will open the Save File dialog.
In case you want to return this file from PHP, you can do that with following script:
<?php
$file = 'video.mp4';
if (file_exists($file)) {
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;
}
I have a really weird problem regarding a small piece of code in a CodeIgniter application. Basically, there's a page with links to various PDF files. When a user clicks on the link, the request is parsed by PHP, an observer is notified, writing the click event in the database (activity log), and then the file is outputted by using readfile().
So far, so good. Tested it, it works like a charm. The PDF is outputted for download, and the event is written in the database as it should.
The problem comes when a user clicks on such link, then cancels the download and clicks on another link no later than 9-10 seconds. When that happens, the event is registered in the database twice.
I did triple check of the observers that record the event, but they appear to be fine. Besides, there's a similar function for a video links, only it redirects to another page instead of outputting the file directly, and it works just fine.
After a few hours of scratching my head, I figured there's an issue with the readfile() function, because, if I put a var_dump();die(); or anything that outputs some text before the download and force it to come as text, the download event is recorded only once.
Here's the code in question:
public function downloadPDF($id = NULL)
{
if (($id == NULL) OR (!$this->validateId($id))) {
// redirect with error
}
$item = // code for fetching the PDF properties from the DB
$this->notify('ActivityObserver'); // writes the download event in the DB
$file = '.' . urldecode($item['link']);
$size = filesize($file);
$name = urldecode(basename($file));
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
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($file));
readfile($file);
exit();
}
Tried to test it with different browsers, the behaviour is the same. All inspector tools show only 1 request being made on click.
What am I missing in this big ugly picture? Why could it sometimes write twice instead of only once?
Thanks for your time to read this wall of text.
I use wordpress cms and I am working on a little script wherein visitor could upload image, resize and download. I am stuck in the download stage. I have already written most of the code but I am unable to connect these things together to make it work somehow. First among these is a resize.php which basically resizes the image and creates a jpeg file. Here is some relevant snippet from my resize.php.
<?php
//normal validation stuff happens here
//resizing stuff happens here
//here is last part of the code that creates the resized image
$filename = uniqid();
$file = 'uploads/'.$filename.'.jpeg';
imagejpeg($new, $file, 80);
imagedestroy($new);
Second is a download.php. Here is a code in my download.php. If you see a lot of question mark in the code, that means I am sure that these are the codes I am missing.
// ????????????
$FilePath = TEMPLATEPATH. '/resize/uploads/';
$final = $FilePath . $FileName;
$size = filesize($final) ;
header("Content-Disposition: attachment; filename=\"". $FileName ."\"");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Transfer-Encoding: binary");
header('Content-Description: File Transfer');
header("Content-Length: ". $size ."");
header('Content-Type: image/jpeg');
header("Expires: 0");
header("Pragma: no-cache");
ob_clean();
flush();
echo (readfile($final));
Third is an html link I have currently on the template page, again question mark for missing code. If someone clicks the link they are supposed to get the newly created resized image file.
DOWNLOAD'
I hope you got the gist of my issue. I am having a hard time trying to figure out how these three will work together to create a download link for the recently resized image. While I am struggling for a solution myself, Please help me point out the mistakes and suggest corrections. THANKS.
FINAL UPDATE : After a few hours of effort, I have this sorted now. I did not realize earlier that the only thing I was missing was the query string and the $_GET. After I understood their role in this whole process everything was pretty easy. Later on when I downloaded the images they came out corrupt. How I sorted that I saved the corrupted files everytime, opened them up in notepad++ and checked for the error. Now my application is flawless. Of course the codes are drastically changed, now. Thanks to everyone for whatever bit of interest they took to help.
Im having some major problems with an site im developing, basically whats happening is a user fills out a form, then jquery takes over and posts all the information to sendfile.php, it then is meant to force the user to download a specific file, but its just not doing anything at all and im not seeing any errors either, the file exists.
The code im using is as follows:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="http://website.com/wp-content/uploads/2012/02/303lowe-logo.jpg"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
readfile("http://website.com/wp-content/uploads/2012/02/logo.jpg");
Any help would be awesome.
Based on what you said about using jQuery, I assume you are using AJAX to post the form results to the server. I think you will find that you cannot download a file using AJAX.
Perhaps consider doing the AJAX request then redirecting the user to a new page to download the file. If the redirected page serves the file directly, then the user won't even know they have been redirected (the browser will stay on the same page, usually).
I need to know if a user selected download then clicked the cancel button, which is not the same as readfile having an error. I have inspected the count returned by the readfile function, but it shows the bytes in the file even if the user canceled the download from the Save As dialog.
The reason this is needed is because my site has a one-time download, where a member gives permission for another use to download their file one time, then the permission goes away. But if a member clicks the download button then decides not to download it right then, I dont' want my database to get updated to show they got the file.
This deals with intellectual property protection since the files are the property of the member who uploaded them, and I need to keep an audit trail of exactly what other members downloaded the file in case they start floating around the internet. But if the readfile function always reflects the filesize (meaning those bytes were transferred in some way), I have no way to know if the file was actually downloaded.
I have seen a number of posts about this subject, but no real solutions to what has to be a frequent need - did they download it or not? Just knowing that they clicked the download button doesn't really say whether they decided to go through with it since the Save As dialog box allows someone to cancel the actual completion of the download.
For completeness, here is my download code up until the readfile function:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=$download_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("sub/$doc_file"));
ob_clean();
flush();
$wasdownloaded = readfile("sub/$doc_file");
I fear the correct answer is "Impossible" - let me explain: You might be able to correctly figure out, when the file has crossed the wire, but you can't figure out reliably, whether the client threw it away or not.
Example (chronological sequence):
A user on MSIE clicks download and is presented with the "Save where" Dialog.
While this dialog is open, the download is started in the background.
The user navigates around in the dialog or simply does nothing (phone rang, he talks)
The background download is finished, your script sees the download as complete
The user clicks on "cancel"
MSIE deletes the tempfile, the download is never stored in a user-accessible form
Result:
The user sees the file as "not downloaded" - and he is correct
Your app sees the file as "correctly downloaded" - and it is correct
You would first need ignore_user_abort().
This would allow your script to continue on after the user has hit cancel, or escape.
You would then have to print out the file and continuously check with connection_aborted().
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=$download_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("sub/$doc_file"));
ob_clean();
flush();
$fp=fopen("sub/$doc_file","rb");
while(!feof($fp))
{
print(fread($fp,1024*8));
flush();
ob_flush();
if( connection_aborted() )
{
//do code for handling aborts
}
}
Use this comment on php.net : http://www.php.net/manual/en/function.fread.php#72716
On fclose you would be able to determine if file has been downloaded successful, because your are checking if user aborted connection with connection_status()