I wonder if there can be such a thing. I wanna check for size of the file and then do htaccess rules based on it. For example:
# like this line
CheckIf {REQUESTED_FILE_SIZE} 50 # MB
AuthName "Login title"
AuthType Basic
AuthUserFile /path/to/.htpasswd
require valid-user
It's clear that I want to make some files with specific file size available to some users only (Using Authentication)
Any idea is appreciated.
Update #1
should be done in htaccess
Update #2
There are so many files and their URLs are already posted in blog. So can't separate larger files to another folder and update each post, also the limitation of file size may change in future.
Update #3
It's a windows server with PHP & helicon App installed
Update #4
Some people got confused about the real issue and I didn't clear it as well either.
.htaccess + PHP file for authentication (uses API) and checking file size + All downloadable files are all in the same server BUT our website is hosted on a different server.
Obviously .htaccess cannot check the requested file size and act accordingly. What you can possibly do is to make use of External Rewriting Program feature of RewriteMap
You need to define a RewriteMap
like this your Apache config first:
RewriteMap checkFileSize prg:/home/revo/checkFileSize.php
Then inside your .htaccess define a rule like this by passing :
RewriteRule - ${checkFileSize:%{REQUEST_FILENAME}}
%{REQUEST_FILENAME}
is passed to PHP script on STDIN.
Then inside /home/revo/checkFileSize.php
you can put PHP code to check for size of file and act accordingly like redirect to a URI that shows basic auth dialog.
I'd do it in 2 steps:
1: htaccess redirecting all requests to one php script, say you have your files inside /test/
and you wanna make it all handled by /test/index.php
, eg:
RewriteEngine On
RewriteBase /test
RewriteCond %{REQUEST_URI} !/test/index.php
RewriteRule ^(.+)? /test/index.php?file=$1 [L]
The RewriteCond
is just to avoid loop requests.
2: the index.php
script does all the auth logic, based on the requested file size, like this:
define('LIMIT_FILESIZE',50*1024*1024); // eg.50Mb
define('AUTH_USER', 'myuser'); // change it to your likes
define('AUTH_PW','mypassword'); // change it to your likes
if( filesize($_GET['file'])>LIMIT_FILESIZE ){
if( !isset($_SERVER['PHP_AUTH_USER']) ) {
header('WWW-Authenticate: Basic realm="My realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Canceled';
exit;
}
else if( $_SERVER['PHP_AUTH_USER']!=AUTH_USER &&
$_SERVER['PHP_AUTH_PW']!=AUTH_PW ) {
header('HTTP/1.0 401 Unauthorized');
echo 'Wrong credentials';
exit;
}
}
// If we're here, it's fine (filesize is below or user is authenticated)
// offer file for download
$file = rawurldecode($_GET['file']);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file( $finfo, $file );
header("Content-type: ".$mime );
header("Content-Disposition: attachment; filename=".basename($file));
include( $file );
There are many possible improvements to it, but it should work as a basis.
I think both answers from @Paolo Stefan and @anubhava are valid (+1).
Note that using RewriteMap will enforce a modification on the apache configuration, not just on the .htaccess file. If you think a little about performance you should, in fact, put all the things you have in .htaccess files into <directory /same/filesystem/path/as/the/.htaccess/file/>
directives and put an AllowOverride None
in the VirtualHost configuration. You will certainly gain some speed by avoiding File I/O and dynamic check-for-configuration-files settings for apache for each query (.htaccess files are bad, really). So the fact that RewriteMap is not available in .htaccess should not be a problem.
Theses two answers provides a way to dinamically alter the Authentification headers based on the filesize. Now, one important fact you forgot to mention on your question is that the files are not directly available on the same server than the PHP ones and also that you do not want to launch a script on each download.
With current @anubhava solution you would have a call on the OS for file size at each access, and of course this script should be run on the file storage server.
One solution could be to store somewhere (a dedicated database or key value storage?) a file-size index. You could feed this index after each download, you could manage some asynchronous tasks to maintain it. Then on the file storage servers's apache configuration you will have to launch a script checking for file sizes. Using RewriteMap you have several options:
prg:
keyword (written in C, Perl, anything, you are not tied to PHP), requesting for this index of file size in this data storage, or even fastdbd:
to directly execute the SQL query in apache. But this means a query at each request, so you have others solutions.txt:
keyword, having for each filename the matching size already computed, no more queries, just With the last two options the file size index is the text file or hashed version of this text file. Apache is caching the hashmap and recompute the cache on restart or when the modification time of the file is altered. So you would just need to recompute this hashmap after each download to obtain a very fast filesize check in a RewriteRule as shown by anubhava but using
RewriteMap checkFileSize dbm:/path/to/filesize_precomputed_index.map
You could also try to use mod_security on the file servers and check the Content-Length
header to add the HTTP Auth. Check this thread for a beginning of answer on that subject. But mod_security configuration is not an easy task.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With