Okay so this is how I rewrote it. Any changes? Will this work? I've added the Javascript at the end with the timeout.
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);
}
?>
<script type="text/Javascript">
window.setInterval(function()
{
window.location = "www.moneymovers.com";
}, 5000);
</script>:
You can't download and then do a header redirect. The client is going to redirect as soon as it sees the header, which means the download won't work. But you also can't output the header after the download, because then the redirect won't happen. Either way, it's not gonna work.
I would recommend doing this at a different level. For example, when the user clicks the download link, have some JavaScript start the download in a new tab/window and then redirect to the desired location in the current tab.
You can put the location header wherever you want, as long as nothing has been outputted (echo).
If you have outputted something, you can output something like this to redirect :
<script type="text/javascript">
window.location = "www.example.com";
</script>
EDIT :
In your case, it is not possible to do what you're looking for, as far as I know. You will have to manage this case in the caller page. The Javascript will not be called because you've modified the Content-Disposition.
Related
simple question I guess, but can't figure it out... Here's the problem:
In the front end, I export some user-selected data to the server to dynamically create a file:
$("#export-button").click(function() {
$.post("'.$postUrl.'",{variable:exportSelection},
function(data) {
console.log(data);
}
);});
Then, after I receive the data and create/save the file on the server, I am doing the following in php:
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));
ob_clean();
flush();
readfile($file);
exit;}
What am I supposed to do in the post callback function instead of printing on the console in order to get a download prompt?
UPDATE: OK - I just realised that my #export-button was an anchor tag with no href... Now when I point to the file on the server, the problem is that when I click, it follows the link prompts to save file etc., but it gets to the file BEFORE the "new" version is generated (so using the previous selection at each click)
OK - I figured it out. I just needed to disable the link from pointing anywhere and then do:
window.location = 'my_file_location.doc';
... inside the callback function
I am using this little pusher php file to download an 'exe' file for the user to save when they fill-out a form.
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);
with this method there is no link to the online $file location for someone to follow but for some reason I cannot display a thank you page after or even immediately before the code is executed.
I've tried header( "Location: $thankyouurl" ); immediately after the above code, but nothing is ever displayed and I've tried echoing the html source of the thank you page just prior to running the above code, but that causes the exe file to be downloaded to the web page actually crashing the browser.
Any suggestions???
Point the user directly to a static page that displays your thank you message. Then, use JavaScript to set the window.location to your download script.
If your download page's headers are set up correctly, the browser will start downloading the file, while your user is reading your thank you message.
Make sure to display a direct download link in case the user has JavaScript disabled.
Example:
index.php
Click here to download.
thankyou.php
<html>
<head>
<script type="text/javascript">
function startDownload() {
window.location = "/download.php";
}
</script>
</head>
<body onload="startDownload();">
<h1>Thank you!</h1>
<p>Your download will start in a moment. If it doesn't, use this direct link.</p>
</body>
download.php
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);
Update
In order to pass data from index.php on to the download script, you could use GET variables. The link to the thankyou.php page would become thankyou.php?download=12 where download is an ID for you to grab the correct file. You would then pass that variable on to your download script by echoing it out in your markup like so:
index.php
Click here to download.
thankyou.php
<html>
<head>
<script type="text/javascript">
function startDownload() {
window.location = "/download.php?file=<?=$_GET['download']?>";
}
</script>
</head>
<body onload="startDownload();">
<h1>Thank you!</h1>
<p>Your download will start in a moment. If it doesn't, use this direct link.</p>
</body>
You'd then grab the value in your download script and handle it any way you like.
Not too sure on this, would a...
header('Location: thanks_page.php');
...not work,. if placed after the readfile()? Unsure on it really, only my thoughts!
You can open the "download page" with an "windows.open( 'url to download file' )"
Example:
<script type="text/javascript">
function openDownload()
{
window.open( "http://domain.com/download.php?file=file.pdf" );
window.location = "http://domain.com/thanks.php";
}
</script>
Opening a window that directly download a file, this will be automatically closed when you chose save or cancel and then, the "parent" window redirect to thanks page.
Using your original method, add header('location: thank-you-page.php'); to the end, along with an exit, as shown here:
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);
header('location: thank-you-page.php');
exit;
I guess I have to break down and ask for help. (Should have done it 3 days ago!)
Here's what happens...
PHP reads session & post variables, builds a .csv file from a mysql query.
it attempts to open a 'Save As' dialog box and when that's done, jump to another page.
I'm using nested functions but when run, the dialog box seems to get run over and never appears.
separately the functions work fine.
when run, the 'save as' dialog box doesn't wait for user input
Can anyone see what I've done wrong or can you redirect my thinking?
$filename points to the created CSV file on the server
$suggname is a default filename users should see in the dialog box.
The code:
holdit($filename,$suggname);
function holdit($filename,$suggname) {
$fp=#fopen($filename, 'rb');
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$suggname.'"' );
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: ".filesize($filename));
} else {
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$suggname.'"' );
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize($filename));
}
fpassthru($fp);
fclose($fp);
jump();
}
function jump() {
header('Location: return_from_csv.php');
}
You are adding lots of headers to your HTTP response. One of those is Location which instructs the browser to redirect. Obviously it is interpreting that as a higher priority than your other headers.
Decide if you want to redirect or serve a file in your response and do one or the other.
I suspect you have misunderstood the Location header. Read this: http://en.wikipedia.org/wiki/HTTP_location
By the looks of things you are trying to serve the CSV file and then redirect to another page. Sorry, you cannot do this. An HTTP response does one thing and one thing only. You might consider opening your link to the CSV file in another window using the target attribute of <a>.
When I use this code to download this image (only used for testing purposes), I open the downloaded image, and all it gives me is an error. i tried it in chrome. opening it with windows photo viewer, it says that it can't display the picture because it is empty???
here is the code:
<?PHP
// Define the path to file
$file = 'http://www.media.lonelyplanet.com/lpi/12553/12553-11/469x264.jpg';
if(!file)
{
// File doesn't exist, output error
die('file not found');
}
else
{
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);
exit;
}
?>
I've had a chance to work it out. Your problem is two-fold.
First, remove the www. from the url.
Second, remove the call to filesize($file) which is throwing an error because PHP doesn't know the size of the file before it downloads the file. (really, just remove the whole line)
Removing these two things, I was successful.
Replace ob_clean() with ob_end_clean()
You're still buffering, so none of the image contents get to the browser.
If your intention is just the download the file from a third party on click of a link, you could use the new property download in the anchor tag.
The code will look something like
<a download href="path/to/the/download/file"> Clicking on this link will force download the file</a>
It works on firefox and chrome latest version. Should I mention that I didn't check it in IE? :P
Replace:
ob_clean();
flush();
readfile($file);
With:
echo file_get_contents($file);
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.