【问题标题】:.htaccess rule for getting requested file size.htaccess 获取请求文件大小的规则
【发布时间】:2013-08-20 06:22:46
【问题描述】:

我想知道是否会有这样的事情。我想检查文件的大小,然后根据它做 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

这是一个安装了 PHP & helicon App 的 windows 服务器

更新 #4

有些人对真正的问题感到困惑,我也没有弄清楚。

.htaccess + PHP 文件用于身份验证(使用 API)和检查文件大小 + 所有可下载的文件都在同一个服务器中 BUT我们的网站托管在不同的服务器上。

【问题讨论】:

  • 这只能使用可在.htaccess 中使用的另一个脚本。没有服务器变量来确定文件大小。您唯一的其他办法是通过前端代理处理此问题。
  • @BurhanKhalid 你的意思是在 php 中检查文件大小?
  • 是的,类似的东西或使用像 nginx 这样的反向代理并让它处理这部分。

标签: regex apache .htaccess mod-rewrite


【解决方案1】:

显然 .htaccess 无法检查请求的文件大小并采取相应措施。你可以做的是利用External Rewriting Program feature of RewriteMap

您需要先定义一个像这样的RewriteMap Apache 配置:

RewriteMap checkFileSize prg:/home/revo/checkFileSize.php

然后在您的 .htaccess 中通过传递定义这样的规则:

RewriteRule - ${checkFileSize:%{REQUEST_FILENAME}}

%{REQUEST_FILENAME} 被传递到 STDIN 上的 PHP 脚本。

然后在/home/revo/checkFileSize.php 中,您可以放置​​ PHP 代码来检查文件大小并采取相应的操作,例如重定向到显示基本身份验证对话框的 URI。

【讨论】:

  • 那么你的RewriteRuleRewriteRule (.*) /path/to/php/checkFileSize.php?URI=$1 有什么不同呢?
  • 我认为它们的行为相同。就我个人而言,我一直使用RewriteRule ^ /some/target 类型的规则,这也是一样的。
【解决方案2】:

我会分两步完成:

1:htaccess 将所有请求重定向到一个 php 脚本,假设你的文件在 /test/ 中,并且你想让它全部由 /test/index.php 处理,例如:

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

RewriteCond 只是为了避免循环请求。

2:index.php 脚本根据请求的文件大小执行所有身份验证逻辑,如下所示:

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,但这已经完成了。在这种情况下,当谈到速度和性能时,PHP 会失败。文件没有存储在同一台服务器上,所以我们需要从另一台主机获得响应以检查用户名和密码是否有效,这需要很长时间,此外,处理下载恢复将需要 PHP,这是不正确的,并且会减少下载速度与正常下载相比。同样通过这种方式,在我们的案例中,每个获取文件的请求的开始时间最多需要 40 秒(Auth),所以我发现使用 htaccess 和 htpasswd 处理它来回答所有这些问题会更好。
  • 文件不在同一个服务器上?因此,对于每个请求,您都需要 Apache 通过网络检查请求的文件大小?我认为这也是一个严重的性能问题。
  • 我的意思是文件主机与网站本身所在的位置是分开的。我们在另一台主机的专用服务器和网站中有文件。因此,如果我们想通过 PHP,我们应该创建一个 API 来检查每个我们不想要的下载请求的用户验证。
【解决方案3】:

我认为@Paolo Stefan 和@anubhava 的两个答案都是有效的 (+1)。

请注意,使用 RewriteMap 将强制修改 apache 配置,而不仅仅是 .htaccess 文件。实际上,如果您稍微考虑一下性能,您应该将 .htaccess 文件中的所有内容放入 <directory /same/filesystem/path/as/the/.htaccess/file/> 指令中,并将 AllowOverride None 放入 VirtualHost 配置中。通过避免每个查询的 Apache 文件 I/O 和动态检查配置文件设置,您肯定会获得一些速度(.htaccess 文件真的很糟糕)。所以 RewriteMap 在 .htaccess 中不可用的事实应该不是问题。

这两个答案提供了一种根据文件大小动态更改身份验证标头的方法。现在,您在问题中忘记提及的一个重要事实是,文件不能直接在同一服务器上而不是 PHP 文件上可用,而且您不想在每次下载时启动脚本。

使用当前的@anubhava 解决方案,您将在每次访问时在操作系统上调用文件大小,当然该脚本应该在文件存储服务器上运行。

一种解决方案可能是将文件大小的索引存储在某个地方(专用数据库或键值存储?)。您可以在每次下载后提供此索引,您可以管理一些异步任务来维护它。然后在文件存储服务器的 apache 配置上,您将不得不启动一个脚本来检查文件大小。使用 RewriteMap 你有几个选择:

  • 使用非常快的scriptprg: 关键字(用C、Perl 等任何东西编写,您不依赖于PHP),请求此数据存储中的文件大小索引,甚至fastdbd:直接在apache中执行SQL查询。但这意味着对每个请求进行查询,因此您有其他解决方案。
  • use directly o mapping filetxt: 关键字,已经为每个文件名计算了匹配大小,不再查询,只是
  • 更好的是,使用带有 dbm:` 关键字的 hashmap of this file

对于最后两个选项,文件大小索引是文本文件或该文本文件的散列版本。当文件的修改时间改变时,Apache 正在缓存 hashmap 并在重启时重新计算缓存。因此,您只需在每次下载后重新计算此哈希图,即可在 RewriteRule 中获得非常快速的文件大小检查,如 anubhava 所示,但使用

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

您也可以尝试在文件服务器上使用mod_security 并检查Content-Length 标头以添加HTTP Auth。检查this thread 以获得关于该主题的答案的开头。但是 mod_security 的配置并不是一件容易的事。

【讨论】:

  • 但我认为使用 rewritemap 与使用 rewriterule 没有什么不同,因为我评论了 anubhava 答案,如果这是真的,它对我没有帮助
  • a rewriteMap 可以为您提供一个可以在 rewriteRule 中使用的可能快或慢的工具,并且在文件服务器上使用 PHP 或其他东西并不意味着您使用与那个相同的 PHP在 Web 应用程序服务器上使用。如果使用 hashmap 源,rewriteMap 可以避免使用脚本。
【解决方案4】:

不是直接的,但在文件系统方面稍作修改就可以做到。

如果这是一个用户上传和下载的系统,您可以关闭mod_rewrite 中的Content-Length 标头以将较大的文件放入单独的目录中。 (或者如果您可以在上传时以其他方式移动它们)

接下来,在包含较大文件的目录中,您将其设置为要求对所有文件进行身份验证。

如果文件存在,最后使用 mod_rewrite 中的存在测试透明地将用户重定向到 large_files 目录。

如果您无法移动文件,您可以使用符号链接来设置两种布局。

【讨论】:

  • 那么祝你好运。请注意,我的建议明确不需要更新博客条目 - 关键是尽管文件位于其他位置,但您使用 mod_rewrite 的条件文件测试,因此 url 保持不变。在 linux 下使用符号链接 + find 设置两棵树相当简单,但恐怕我不知道足够的 powershell 来提供 windows 版本。
【解决方案5】:

根据this mod_rewrite 支持"-s" CondPattern,它检查指定的TestString 是否为非零大小的常规文件。附加的patch 扩展了"-s" 选项以支持与任意大小的比较。

所以被质疑者:

CheckIf {REQUESTED_FILE_SIZE} 50 # MB

应该使用这个 .htaccess 代码:

RewriteCond %{REQUEST_FILENAME} -s=52428800

【讨论】:

  • 是的,但这个附件从未修补过!
  • 我用你给的线索来回答这个问题。谢谢
  • 不客气。我也将 50MB 大小更改为您的。
【解决方案6】:

当时我问 Apache 2.4 已经发布,所以这个答案可能是正确的。

Apache 表达式

从 Apache 2.4 开始,引入了名为 Expressions 的新功能。据此,您可以在指令中使用一些函数,也可以与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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-01
    • 2011-12-12
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    相关资源
    最近更新 更多