.правило htaccess для получения запрошенного размера файла

интересно, может ли быть такая вещь. Я хочу проверить размер файла, а затем сделать правила htaccess на его основе. Например:

# like this line
CheckIf {REQUESTED_FILE_SIZE} 50 # MB
AuthName "Login title"
AuthType Basic
AuthUserFile /path/to/.htpasswd
require valid-user

ясно, что я хочу сделать некоторые файлы с определенным размером файла доступными только для некоторых пользователей (используя аутентификацию)

любая идея приветствуется.

обновление #1

должно быть сделано в htaccess

обновление #2

есть так много файлов, и их URL-адреса уже размещены в блоге. Поэтому нельзя отделять большие файлы в другую папку и обновлять каждую запись, также ограничение размера файла может измениться в будущем.

обновление #3

это сервер windows с установленным приложением PHP & helicon

обновление #4

некоторые люди запутались в реальной проблеме, и я не понял и это тоже.

.реврайт + PHP файл для аутентификации (использует API) и проверки размера файла + все загружаемые файлы находятся на одном сервере но наш веб-сайт размещен на другом сервере.

6 ответов


очевидно .htaccess не может проверить запрошенный размер файла и действовать соответствующим образом. Что вы можете сделать, это использовать External Rewriting Program feature of RewriteMap

необходимо указать RewriteMap как это ваша конфигурация Apache сначала:

RewriteMap checkFileSize prg:/home/revo/checkFileSize.php
внутри .htaccess определяет такое правило, передавая:
RewriteRule - ${checkFileSize:%{REQUEST_FILENAME}}

%{REQUEST_FILENAME} передается php скрипту на STDIN.

внутри /home/revo/checkFileSize.php вы можете поставить PHP-код для проверки размера файла и действовать соответственно как перенаправление на URI, который показывает основной диалог auth.


Я бы сделал это в 2 шага:

1: htaccess перенаправляет все запросы на один PHP-скрипт, скажем, у вас есть файлы внутри /test/ и вы хотите, чтобы все это обрабатывалось /test/index.php, например:

RewriteEngine On
RewriteBase /test
RewriteCond %{REQUEST_URI} !/test/index.php
RewriteRule ^(.+)? /test/index.php?file= [L]

на RewriteCond просто, чтобы избежать запросов цикла.

2: о index.php скрипт выполняет всю логику auth, основанную на запрошенном размере файла, например:

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

есть много возможных улучшений, но он должен работать в качестве основы.


Я думаю, что оба ответа от @Paolo Stefan и @anubhava действительны (+1).

обратите внимание, что использование RewriteMap приведет к изменению конфигурации apache, а не только.файл htaccess. Если вы немного думаете о производительности, вы должны, на самом деле, положить все, что у вас есть .htaccess файлы в <directory /same/filesystem/path/as/the/.htaccess/file/> директивы и положить AllowOverride None в конфигурации VirtualHost. Вы, безусловно, получите некоторую скорость, избегая ввода-вывода файлов и динамической проверки файлов конфигурации настройки для apache для каждого запроса (.файлы htaccess плохие, действительно). Так что тот факт, что RewriteMap недоступно .htaccess не должен быть проблемой.

тезисы два ответа обеспечивают способ динамического изменения заголовков аутентификации на основе размера файла. Теперь один важный факт, который вы забыли упомянуть в своем вопросе, заключается в том, что файлы не доступны непосредственно на том же сервере, что и PHP, а также что вы не хотите запускать скрипт на каждом скачать.

с текущим решением @anubhava у вас будет вызов на ОС для размера файла при каждом доступе, и, конечно, этот скрипт должен быть запущен на сервере хранения файлов.

одним из решений может быть хранение где-то (выделенная база данных или хранилище ключевых значений?) индекс размера файла. Вы можете кормить этот индекс после каждой загрузки, вы можете управлять некоторыми асинхронными задачами для его поддержания. Затем в конфигурации apache серверов хранения файлов вам придется запустить скрипт проверки размеров файлов. С помощью RewriteMap у вас есть несколько вариантов:

  • используйте очень быстрый скрипт С prg: ключевое слово (написано на C, Perl, ничего, вы не привязаны к PHP), запрашивая этот индекс размера файла в этом хранилище данных, или даже fastdbd: для непосредственного выполнения SQL-запроса в apache. Но это означает запрос по каждому запросу, поэтому у вас есть другие решения.
  • использовать непосредственно o mapping file С txt: ключевое слово, имеющее для каждого имени файла уже вычисленный соответствующий размер, больше никаких запросов, просто
  • еще лучше, использовать hashmap этого файла С dbm: 'ключевое слово.

С последними двумя параметрами индекс размера файла является текстовым файлом или хэшированной версией этого текстового файла. Apache кэширует hashmap и пересчитывает кэш при перезапуске или когда изменение времени файл изменен. Так что вам просто нужно пересчитайте этот hashmap после каждой загрузки, чтобы получить очень быструю проверку размера файла в перезаписи, как показано anubhava, но с помощью

RewriteMap checkFileSize dbm:/path/to/filesize_precomputed_index.map

вы также можете попробовать использовать mod_security на файловых серверах и проверьте Content-Length заголовок для добавления http Auth. Проверка этой теме для начала ответа на этот вопрос. Но конфигурация mod_security - непростая задача.


не напрямую, но с небольшой модификацией на стороне файловой системы вы можете это сделать.

Если это система, где пользователи загрузка а также загрузка, вы можете отключить на mod_rewrite поставить большие файлы в отдельный каталог. (или, если вы можете каким-то другим способом переместить их в любом случае при загрузке)

далее, в каталоге с большими файлами вы установили, что для всех файлов требуется аутентификация.

наконец-то использовать тесты существования в mod_rewrite прозрачно перенаправляют пользователя в каталог large_files, если файл есть.

Если вы не можете переместить файлы, вы можете использовать символические ссылки для установки двух макетов.


по данным этой mod_rewrite поддерживает "-s" CondPattern который проверяет, если указанный TestString - обычный файл с ненулевым размером. Прилагаемый патч расширяет "-s" возможность поддержки сравнения с произвольными размерами.

так спрашивали:

CheckIf {REQUESTED_FILE_SIZE} 50 # MB

должны работать с этим .реврайт код:

RewriteCond %{REQUEST_FILENAME} -s=52428800

в то время я задал вопрос Apache 2.4, поэтому этот ответ может быть правильным.

Выражения Apache

начиная с Apache 2.4 новая возможность называется выражения. В соответствии с этим вы можете использовать некоторые функции в своих директивах, а также в сочетании с RewriteCond.

к счастью, есть функция под названием filesize() который может сравнить размер файла вместе с операторы сравнения: - et-gt-ge-lt-le-ne

говоря , что-однако в документации отсутствует информация об этой функции-ниже приведены соответствующие правила для сравнения размера файла:

RewriteCond expr "filesize('%{REQUEST_FILENAME}') -gt 52428800"
RewriteRule ** **

использование выражений внутри RewriteCond должно быть сделано в следующий синтаксис:

RewriteCond expr "..."

BNF:

expr        ::= "true" | "false"
              | "!" expr
              | expr "&&" expr
              | expr "||" expr
              | "(" expr ")"
              | comp

вы можете найти полный BNF на странице документации.