Disguising .pdf extension using .htaccess avoiding cycling - php

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);

Related

Redirecting feeds to another directory using .htaccess and mod_rewrite

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]

DENY direct download of file using php

I have .doc and .zip files in download directory on my server.
whoever visit my site page (download-file.php) only those user should be able to download these files and other should not.
I am trying to achieve above but no luck...
I am still able to put direct file address (http://example.com/sample.doc) in browser and I am able to download which I don't want..even someone else giving link to above file on any website then also download should not happen.
Could any one please share some idea..how i should achieve this.
Thank you in advance.
In the htaccess file in your document root, you can include these rules:
RewriteEngine On
# you can add whatever extensions you want routed to your php script
RewriteCond %{REQUEST_URI} \.(doc|zip|pdf)$ [NC]
RewriteRule ^(.*)$ /download-file.php?filename=$1 [L]
Then in your download-file.php, you can display whatever you need to display and the download link, which your php script can just immediately serve the file using php's readfile() (see link for examples)
You should disallow access to your files directory, and offer downloads only PHP driven (example with PDFs):
data/.htaccess (googled):
deny from all
download.php:
/* User access check here, prior to the following code */
$name = 'MyPDF.pdf';
$filename = 'data/pdf_12345.pdf';
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Type: application/pdf");
header("Content-Length: " . filesize($file));
fpassthru($filename)
Of course you can set different filenames for each user and each request, like download.php?file=MyPDF
You should be able to restrict people from directly accessing your content using a method similar to the following code:
RewriteCond %{HTTP_REFERER} !^http://your_domain.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://your_domain.com$ [NC]
RewriteCond %{HTTP_REFERER} !^http://www.your_domain.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://www.your_domain.com$ [NC]
RewriteRule .*.(jpg|jpeg|gif|png|bmp|pdf|doc)$ http://your_domain.com/no_access.php [R,NC]
This would prevent people from directly linking images, pdfs or docs from your site. Then, files with these extensions would only be able to accessed from your site. If someone attempts to directly link or access your files, they will experience the whatever you choose for them to see (that you place in the no_access.php).
If you have a dedicated server the easiest and in my opinion the most secure way is to store the files outside of /var/www/
You can for example create a folder /var/webdocs/ and store them there.

PHP force browser downloading image, Facebook like

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.

Change http-header of linked files without explicit download script (in an own 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>

JavaScript doesn't parse when mod-rewrited through a PHP file?

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.

Categories