使用 URL 参数和 XSendFile 在浏览器中缓存图像
Caching images in browser with URL parameters and XSendFile
我正在尝试建立一个站点,以便用户只能访问他们自己的图像和音频文件。为此,我在 URL 中使用变量,例如:
<img src="/public/get_file.php?type=image&file=pic001.png" />
在前端我使用的是 React JS(不确定这对这个问题是否重要)。但在后端,PHP 脚本将验证用户是否已登录(仅通过检查一个简单的 SESSION 变量)并在用户的数据目录中查找该文件(基于其 SESSION 变量中的用户 ID) .如果存在,它将 return 使用 XSendFile 将其发送给用户。
我遇到的问题是,每次用户尝试访问文件时,在加载文件之前都会有一点延迟。这告诉我它们可能没有被浏览器缓存。
为什么文件没有被缓存?它与 URL 参数或 PHP/XSendFile 的使用有关吗?
我该怎么做才能让我的文件 (images/audio) 被缓存?
更新
这里要求的是我的 get_file.php:
<?php
session_start();
if (empty($_SESSION['auth']['id'])){
exit;
}
require_once("../../api_modules/settings.php");
$developer_id = $_SESSION['auth']['id'];
$type = preg_replace('/[^-a-zA-Z0-9_]/', '', $_GET['type']);
$file = preg_replace('/[^-a-zA-Z0-9_\.]/', '', $_GET['file']);
$file = preg_replace('/[\.]{2,}/', '', $file);
$project_id = preg_replace('/[^0-9]/', '', $_GET['project_id']);
$developer_id = preg_replace('/[^0-9]/', '', $developer_id);
if ($type == "image")
$file = FILEPATH ."files/$developer_id/$project_id/images/thumbs/88x88/$file";
else if ($type == "full_image")
$file = FILEPATH ."files/$developer_id/$project_id/images/originals/$file";
else if ($type == "audio"){
$file = FILEPATH ."files/$developer_id/$project_id/audio/$file";
}
else {
exit;
}
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
尝试使用这种 header(PHP 代码),例如 header('Cache-Control: must-revalidate');
下载私人文件
$mime_types = array(
'pdf' => 'application/pdf',
'txt' => 'text/plain',
'html' => 'text/html',
'exe' => 'application/octet-stream',
'zip' => 'application/zip',
'doc' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'gif' => 'image/gif',
'png' => 'image/png',
'jpeg' => 'image/jpg',
'jpg' => 'image/jpg',
'php' => 'text/plain'
);
if ($mimeType == '') {
$file_ext = strtolower(substr(strrchr($file_path.$file_name_gen, '.'), 1));
if(array_key_exists($file_ext, $mime_types)) $mime_type = $mime_types[$file_ext];
else $mime_type = 'application/force-download';
}
ob_start();
header('Content-Disposition: attachment; filename="' . $file_name_gen . '"');
header('Content-Type: '.$mime_type);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_path.$file_name));
ob_clean();
flush();
readfile($file_path.$file_name);
并使用具有最佳解决方案选项的缓存控制,例如
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
顺便说一句。 $file_name_gen
是服务器上的真实文件名,$file_name
是用户查看更多文件隐私的文件名。
郑重声明,这主要是因为 session.cache_limiter
的默认值为 nocache
。
请参阅 http://php.net/manual/en/function.session-cache-limiter.php 了解如何设置适合您需要的不同值。
如何生成图像?您有 public 本地目录还是由 CDN(远程)加载?
我认为这是一个duplicate。
但是由于有赏金,让我们尝试根据那里建议的解决方案调整您的代码。
您需要检查 Apache 是否启用了 mod_expires 和 mod_headers 并正常工作。
然后在开始实际输出之前检查文件是否被修改:
...
$last_modified_time = filemtime($file);
$etag = md5_file($file);
// always send headers
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("Etag: $etag");
// exit if not modified
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
@trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
header("HTTP/1.1 304 Not Modified");
exit;
} else {
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
}
我正在尝试建立一个站点,以便用户只能访问他们自己的图像和音频文件。为此,我在 URL 中使用变量,例如:
<img src="/public/get_file.php?type=image&file=pic001.png" />
在前端我使用的是 React JS(不确定这对这个问题是否重要)。但在后端,PHP 脚本将验证用户是否已登录(仅通过检查一个简单的 SESSION 变量)并在用户的数据目录中查找该文件(基于其 SESSION 变量中的用户 ID) .如果存在,它将 return 使用 XSendFile 将其发送给用户。
我遇到的问题是,每次用户尝试访问文件时,在加载文件之前都会有一点延迟。这告诉我它们可能没有被浏览器缓存。
为什么文件没有被缓存?它与 URL 参数或 PHP/XSendFile 的使用有关吗?
我该怎么做才能让我的文件 (images/audio) 被缓存?
更新
这里要求的是我的 get_file.php:
<?php
session_start();
if (empty($_SESSION['auth']['id'])){
exit;
}
require_once("../../api_modules/settings.php");
$developer_id = $_SESSION['auth']['id'];
$type = preg_replace('/[^-a-zA-Z0-9_]/', '', $_GET['type']);
$file = preg_replace('/[^-a-zA-Z0-9_\.]/', '', $_GET['file']);
$file = preg_replace('/[\.]{2,}/', '', $file);
$project_id = preg_replace('/[^0-9]/', '', $_GET['project_id']);
$developer_id = preg_replace('/[^0-9]/', '', $developer_id);
if ($type == "image")
$file = FILEPATH ."files/$developer_id/$project_id/images/thumbs/88x88/$file";
else if ($type == "full_image")
$file = FILEPATH ."files/$developer_id/$project_id/images/originals/$file";
else if ($type == "audio"){
$file = FILEPATH ."files/$developer_id/$project_id/audio/$file";
}
else {
exit;
}
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
尝试使用这种 header(PHP 代码),例如 header('Cache-Control: must-revalidate');
下载私人文件
$mime_types = array(
'pdf' => 'application/pdf',
'txt' => 'text/plain',
'html' => 'text/html',
'exe' => 'application/octet-stream',
'zip' => 'application/zip',
'doc' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'gif' => 'image/gif',
'png' => 'image/png',
'jpeg' => 'image/jpg',
'jpg' => 'image/jpg',
'php' => 'text/plain'
);
if ($mimeType == '') {
$file_ext = strtolower(substr(strrchr($file_path.$file_name_gen, '.'), 1));
if(array_key_exists($file_ext, $mime_types)) $mime_type = $mime_types[$file_ext];
else $mime_type = 'application/force-download';
}
ob_start();
header('Content-Disposition: attachment; filename="' . $file_name_gen . '"');
header('Content-Type: '.$mime_type);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_path.$file_name));
ob_clean();
flush();
readfile($file_path.$file_name);
并使用具有最佳解决方案选项的缓存控制,例如
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
顺便说一句。 $file_name_gen
是服务器上的真实文件名,$file_name
是用户查看更多文件隐私的文件名。
郑重声明,这主要是因为 session.cache_limiter
的默认值为 nocache
。
请参阅 http://php.net/manual/en/function.session-cache-limiter.php 了解如何设置适合您需要的不同值。
如何生成图像?您有 public 本地目录还是由 CDN(远程)加载?
我认为这是一个duplicate。
但是由于有赏金,让我们尝试根据那里建议的解决方案调整您的代码。
您需要检查 Apache 是否启用了 mod_expires 和 mod_headers 并正常工作。
然后在开始实际输出之前检查文件是否被修改:
...
$last_modified_time = filemtime($file);
$etag = md5_file($file);
// always send headers
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("Etag: $etag");
// exit if not modified
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
@trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
header("HTTP/1.1 304 Not Modified");
exit;
} else {
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
}