既然你说你在 Apache 上,这里有 2 个想法。
第一个想法(马马虎虎,但想想很有趣……):
Cookie 随服务器上的每个请求一起发送(包括所有图像等)。当用户登录时,使用 PHP 设置一个 cookie 并将其命名为 USERTOKEN 然后将其值设置为该用户 id 的 md5+salt。
将%{USERTOKEN}C 和%B 插入到自定义LogFormat 指令中。
%{Foobar}C The contents of cookie Foobar in the request sent to the server.
Only version 0 cookies are fully supported.
%B Size of response in bytes, excluding HTTP headers.
现在,您创建一个如下所示的自定义日志格式:
LogFormat "%B %{USERTOKEN}C" php_bandwidth_log
CustomLog "logs/php_bandwidth_log" php_bandwidth_log
然后,您创建一个脚本来解析 php_bandwidth_log 并将其映射到原始用户的 id。
不幸的是,这个想法并不是万无一失的,因为有人仍然可以通过不传递 cookie 来假设访问网站内容(也许)。无论如何,根据您的情况,这可能对您有用,如果不是,另一种更好的想法是基本上通过 PHP 脚本路由所有内容,以便您可以对其进行任何类型的日志记录。
第二个想法(更好):
因此,创建一个可以像 /files.php?path=/blah/blah.jpg 那样调用的 PHP 文件(本示例过于简单,可以使用 mod_rewrite 规则进行修饰)然后在其中您可以记录该用户的 id 并跟踪访问的文件。这是假设您只想跟踪文件。这不会跟踪页面上生成的 HTML - 您可能会使用前面提到的自定义 Apache 日志记录想法,但对其稍作修改以获取该信息。
这里有一些伪代码可以帮助你理解这个想法:
if (!$hasSession) {
die("Invalid session");
}
$size = filesize($path);
insert_into_bandwidth_table($userId, $size);
header("Content-Type: ...");
readfile($path);
以下是仅跟踪已执行 PHP 脚本的响应大小的方法,但仅当您将 PHP 作为模块运行时才有效。
在您的 PHP 中添加类似这样的内容。基本上,这允许 Apache 读取此变量以用于日志写入目的:
apache_note("PHP_USER_ID", 1234);
apache_note — apache_note — 获取和设置 apache 请求注释
描述:这个函数是 Apache 的 table_get 和 table_set 的包装器。它编辑请求期间存在的注释表。该表的目的是允许 Apache 模块进行通信。
Read more here
然后在您的 httpd.conf 日志配置中执行如下操作:
LogFormat "%B %{PHP_USER_ID}n" php_bandwidth_log
CustomLog "logs/php_bandwidth_log" php_bandwidth_log
来自文档的注释信息:
%{Foobar}n The contents of note Foobar from another module.
而且...刚刚意识到 apache_note 有一个替代方案,以防您不将其作为模块运行。你的 PHP 代码会这样做:
apache_setenv('PHP_USER_ID', $userId, TRUE);
然后记录你会使用这个 LogFormat 指令:
LogFormat "%B %{PHP_USER_ID}e" php_bandwidth_log