I am looking for a way to force the browser to download an image instead of just display it.
I already looked a lot (and deeply) and there seems to be no standard way to do it properly.
The way Facebook do it, it's with some PHP I guess they put a parameter at the end :
?dl=1
So it's certainly a PHP page behind with an url rewritting i guess
<a class="itemAnchor" role="menuitem" tabindex="-1" href="http://a5.sphotos.ak.fbcdn.net/hphotos-ak-ash4/327910_2733459209258_1040639162_2895571_6924037615_o.jpg?dl=1" rel="ignore"><span class="itemLabel fsm">Download</span></a>
So if you have any clue how they do it... My clue is that they probably do something in the headers of the PHP page
They simply force downloading using HTTP headers just like you do with any other file:
<?php
$file = 'C:\\test.jpg';
header('Cache-Control: public');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Type: '.mime_content_type($file));
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
readfile($file);
?>
X-SendFile
For larger files or busy webservers, I would suggest the use of X-SendFile header instead of using readfile() function (note that you need mod_xsendfile installed in Apache).
header('X-Sendfile: '.$file);
//readfile($file);
.htccess
As you noticed, the Facebook URL points at a jpg file, rather than a PHP one.
You will need to have URL rewriting in a .htaccess file to do this trick.
Something like the following should work (note you will need to use the real URL, checking the contents of $_SERVER to do so).
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
You'll have to define the Content-Disposition variable in your header:
<?php
header("Content-Disposition: attachment; filename='downloaded.png'");
?>
You can achieve this by setting the appropriate headers before sending the file. Specifically you can set the Content-Type to whatever your content type is and Content-Disposition: attachment; filename=<yourfilename>.
There are some gotchas with IE; check this answer for more info.
Related
I have a problem that I can not solve.
I use RewriteEngine in my .htaccess to access some videos. I need to export them for use in android.
My .htaccess:
RewriteRule ([^/]*)\.amr$ api.php?cmd=getmp3&hash=$1 [L]
In api.php
$__GB->getSafemp3($_GET['hash']);
And feature code:
header('Content-Type: video/3gpp');
header('Content-Disposition: inline; filename=' . $fetch['new_name']);
header('Content-length: '.filesize($path));
header("Content-Transfer-Encoding: binary");
readfile($path);
With the URL directly works perfectly, but not RewriteRule
Edit:
I've fixed the problem, i changed the feature code for this:
header('Location: ' . $path.$fetch['new_name']); //$path.$fetch['new_name'] is the file directory, ex: /music/audio.3gp
I want to redirect all feed file requests(*.xml) to a php script which will adjust the url of the request and then output the result. I currently have a script which does this, but ends up in an infinite redirect loop. I understand that Apache will request the adjusted file over and over unless I have a condition to stop it, hence I then added a condition to the .htaccess file to only process the file if it originated from root. I thought the concept was good, but still got the same error. The last part of the script is follows:
...
$fileUrl = $row['file_url'] . $feedFile;
}
header('Location: ' . $fileUrl);
header('Content-type: text/xml');
header('Content-length: ' . filesize($fileUrl));
header('Content-Disposition: filename= '.$fileUrl);
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile($fileUrl);
?>
The .htaccess file is as follows:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
#Only process .xml requests if they are from root
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ([a-zA-Z0-9]+\.xml$) checkForAuth.php?file=$1 [QSA]
I get the following error using castfeedvalidator:
Warning: copy(http://www.example.com/SFAPremium.xml?name=ejleeson) [function.copy]: failed to open stream: Redirection limit reached, aborting in /home/podcasts/public_html/castfeedvalidator/ajax/validate.php on line 243
Thanks,
Dion
Your RewriteCond doesn't look right, try this rule instead:
RewriteEngine On
RewriteBase /
# Only process .xml requests if they are from root
RewriteRule ^([\w-]+)\.xml$ checkForAuth.php?file=$1 [NC,L,QSA]
I have a little bit stupid necessity to disguise links to PDF files as PHP files with the PDF filename as a parameter.
Something like:
Client requests xxxx.pdf file.
Server receives request but instead of returning xxxx.pdf goes to yyyy.php or whatever extension.
yyyy.php has an iframe in which the PDF file is loaded.
The thing is that I managed to do point 2. but when I try to do point 3. it either cycles or doesn't locate the file.
I was thinking of having a custom extension to "simulate" another file in order to not cycle but it's still cycling.
I have the following .htaccess:
AddType application/pdf .view
RewriteRule ^(.*)\.pdf$ yyyy.php?filename=$1 [L]
RewriteRule ^(.*)\.view$ $1.pdf [L]
The thing is that it cycles and I get nowhere.
I am not really good with .htaccess, so where am I doing this wrong?
You probably need to add something to prevent the referer for yyyy.php from getting rewritten back to the php file. Add this before your yyyy.php rule:
RewriteCond %{HTTP_REFERER} !yyyy\.php
Note that referers can be forged, so this is one way people will be able to bypass the yyyy.php file.
I found it easier to just redirect when I detect a .pdf extension.
So I basically did this:
.htaccess detects a PDF extension and redirects to a php file passing the filename without extension as a parameter.
The php file uses the filename and renders the PDF using header and readfile to avoid conflicts with .htaccess.
Something like that:
.htaccess
RewriteRule ^(.*)\.pdf$ /pdfreader/$1 [L,R=302,NC]
RewriteRule ^pdfreader/(.*)?$ pdfreader.php?file=$1 [L,NC]
pdfreader.php
$file = $_GET["file"].".pdf";
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $file . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Accept-Ranges: bytes');
#readfile($file);
I want to force the browser to download all files linked inside a RSS-Feed, that is created by a php-script.
Therefore I need to change the HTTP-headers of these files and set
header("Content-Disposition: attachment; filename=$file");
(and maybe also some other changes).
At the moment I try to do this using a download script, that sets these parameters.
However, the disadvantage of this method is, that I have to link to "download.php" instead of "target.file", which is somehow misleading for the user. Besides, I have to reveal the internal file path to the user or use quite a lot of GET-variables instead.
It would be much better if it was possible to change the HTTP-headers inside the script that generates the RSS-Feed. Is there a way to achieve this?
You can't change the headers from inside the RSS feed. You could, however, hide the download.php part with some rewrite magic:
RewriteEngine on
RewriteRule ^download/.*$ /download.php?file=$1 [L]
This would cause any URL starting with /download/ to be run through your download script:
/img/foo.jpg - normal file
/download/img/foo.jpg - force a download
You could do a similar thing without the PHP too:
RewriteEngine on
RewriteRule ^download/.*$ /$1 [L]
<Location /download>
Header add Content-Disposition "attachment"
</Location>
If I do the following (this is the actual/direct path to the JavaScript file):
<script href="http://localhost/tpl/blue/js/functions.js" type="text/javascript"></script>
It works fine, and the JavaScript parses - as its meant too.
However I'm wanting to shorten the path to the JavaScript file (aswell as do some caching) which is why I'm rewriting all JavaScript files via .htaccess to cache.php (which handles the caching).
The .htaccess contains the following:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^js/(.+?\.js)$ cache.php?file=$1 [NC]
</IfModule>
cache.php contains the following PHP code:
<?php
if (extension_loaded('zlib')) {
ob_start('ob_gzhandler');
}
$file = basename($_GET['file']);
if (file_exists("tpl/blue/js/".$file)) {
header("Content-Type: application/javascript");
header('Cache-Control: must-revalidate');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT');
echo file_get_contents("tpl/blue/js/".$file);
}
?>
and I'm calling the JavaScript file like so:
<script href="http://localhost/js/functions.js" type="text/javascript"></script>
But doing that the JavaScript doesn't parse? (if I call the functions which are within functions.js later on in the page they don't work) - so theirs a problem either with cache.php or the rewrite rule? (because the file by itself works fine).
If I access the rewrited file-> http://localhost/js/functions.js directly it prints the JavaScript code, as any JavaScript file would - so I'm confused as to what I'm doing wrong...
PS: I've tried changing the mime/content-type to text/javascript, aswell as clearing the browser cache - but no luck.
All help is appreciated! :)
I think your solution is ridiculus given your stated aims. Keep it simple.
I'm wanting to shorten the path to the
JavaScript file
Why? What's the problem with long paths?
(aswell as do some caching)
Good aim. But have you seen mod_expires? Enable it then stick this in your .htaccess
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType text/javascript "access plus 1 days"
</IfModule>
Done.
And also, Apache serving a static file is so so much faster than apache starting up an entire PHP process which then serves a static file, not to mention (as you are finding out) less error prone.
Simplicity rules!
The content-type should be text/javascript, not application/javascript.
Be sure to send the correct content-type header from cache.php, e.g. with
header('Content-Type: text/javascript');
This is required because your webserver thinks he's serving a PHP script and by configuration it's told that the default output of such a script is text/html or text/plain. Therefore it adds one of these content-types unless you send one yourself from the script.