Я перепробовал очень много вещей, и кажется, что нет простого решения.
Мое решение использует хитрость заголовка Location
, предложенную @ yes123, но я настроил его так, чтобы он соответствовал моим предпочтениям.
Ссылки на файлы остаются без изменений, поэтому они по-прежнему: /files/path/to/my/file.abc
У меня есть RewriteRule
:
RewriteRule ^files/(.*) path/to/tracker.php?path=/$1
Затем в файле я выдаю заголовок Location
, добавив ?track=no
к URL-адресу и исключение к более раннему RewriteRule
:
RewriteCond %{QUERY_STRING} !(&|^)track=no(&|$)
Я добавил еще одну оптимизацию. Я включил E-Tag, поэтому, если клиент отправляет заголовок E-Tag, проверьте, соответствует ли он файлу, и верните 304 Not Modified
вместо Location
.
$fs = stat($document_root . $path);
$apache_etag = calculate_apache_etag($fs);
if ((isset($_SERVER["HTTP_IF_MATCH"]) && etag_within_range($_SERVER["HTTP_IF_MATCH"], $apache_etag))
|| (isset($_SERVER["HTTP_IF_NONE_MATCH"]) && etag_within_range($_SERVER["HTTP_IF_NONE_MATCH"], $apache_etag))
) {
header("ETag: " . $apache_etag, true, 304);
exit;
}
function etag_within_range($etag1, $etag2) {
list($size1, $mtime1) = explode("-", $etag1);
list($size2, $mtime2) = explode("-", $etag2);
$mtime1 = floor(hexdec($mtime1) / 1000000);
$mtime2 = floor(hexdec($mtime2) / 1000000);
return $mtime1 === $mtime2 && $size1 === $size2;
}
И реализацию для calculate_apache_etag
можно найти здесь: Как создать этаг, соответствующий Apache?
etag_withing_range
решает проблему сравнения с более высокой точностью mtime
в Apache.
Примечания о решениях, которые не работали
virtual
Тестовый скрипт:
var_dump(apache_response_headers());
virtual("/path/to/image.jpg");
var_dump(apache_response_headers());
Выходы:
array(1) { ["X-Powered-By"]=> string(10) "PHP/5.2.11" }
[[binary junk]]
array(5) { ["X-Powered-By"]=> string(10) "PHP/5.2.11" ["Keep-Alive"]=> string(18) "timeout=5, max=100" ["Connection"]=> string(10) "Keep-Alive" ["Transfer-Encoding"]=> string(7) "chunked" ["Content-Type"]=> string(9) "text/html" }
Content-Type: text/html
reaaaaalllly ? (
Возможно, функция PHP5.3 header_remove
может решить эту проблему? Я не пробовал.