Я пытаюсь настроить сайт так, чтобы пользователи имели доступ только к своим собственным изображениям и аудиофайлам. Для этого я использую переменные в URL, такие как:
<img src = "/public/get_file.php?type=image&file=pic001.png" />
Во внешнем интерфейсе я использую React JS (не уверен, что это важно для этой проблемы). Но на бэкэнде PHP-скрипт подтвердит, что пользователь вошел в систему (просто проверив простую переменную SESSION), и найдет этот файл в каталоге данных пользователя (на основе идентификатора пользователя в их переменной SESSION). Если он существует, он вернет его пользователю с помощью XSendFile.
Проблема, с которой я сталкиваюсь, заключается в том, что каждый раз, когда пользователь пытается получить доступ к файлам, происходит небольшая задержка перед их загрузкой. Это говорит мне о том, что они, вероятно, не кэшируются браузером.
Почему файлы не кэшируются? Это связано с параметром URL или использованием PHP/XSendFile?
Что я могу сделать, чтобы мои файлы (изображения/аудио) кэшировались?
Обновлять
По запросу вот мой 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) . '"');
@jsdeveloper Хотя я часто использую консоль, я не слишком привык использовать вкладку сети (ответ). Однако я вижу свой запрос, но в ответе говорится: «Запрос не имеет доступных данных для ответа».
просто для уточнения, вы хотите, чтобы браузер мог кэшировать изображения?
@kojow7 Какой HTTP-сервер вы используете?
@TomaszKajtoch Я не совсем понимаю ваш вопрос. Мой вопрос помечен как Apache. Есть ли что-то еще, что вы ищете?
@Vidal Да, в настоящее время, если я перейду на одну страницу, она загрузит изображения, если я уйду на другую страницу, а затем вернусь на первую страницу, мне придется снова загрузить изображения.
Не могли бы вы опубликовать свой код get_file.php, пожалуйста?






Попробуйте использовать этот тип заголовка (код 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 — это имя файла, которое пользователи видят для большей конфиденциальности файлов.
Cache-Control: private чтобы избежать кеширования прокси-серверами.
Для справки, это в основном связано с тем, что значение по умолчанию для session.cache_limiter равно nocache.
См. http://php.net/manual/en/function.session-cache-limiter.php о том, как установить другое значение, которое соответствует вашим потребностям.
Как вы генерируете изображения? У вас есть общедоступный локальный каталог или он загружается через CDN (удаленно)?
Может поможет: КАК КЭШИРОВАТЬ ИЗОБРАЖЕНИЯ, СОЗДАННЫЕ PHP
Изображения хранятся в каталогах на том же сервере. Каждый пользователь имеет свой собственный каталог пользователя, помеченный своим идентификатором пользователя.
Хорошо, так проще управлять кешем с локальными изображениями. Вы можете попробовать решение по ссылке и посмотреть, сработает ли оно. Но что произойдет, если кто-то попытается получить доступ к изображениям напрямую?
Они не могут получить доступ к изображениям напрямую, поскольку они не находятся в папке, доступной через Интернет.
Я думаю, что это дубликат.
Но поскольку есть щедрость, давайте попробуем адаптировать ваш код вместе с предложенным там решением.
Вам нужно убедиться, что в 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) . '"');
}
Я не уверен, что полностью понимаю, но веб-браузер запрашивает файл, но затем, если он получает сообщение 304, он отменяет свой запрос и вместо этого использует свой кеш?
да. Вот как браузер может повторно использовать кэшированные HTTP-ответы.
Вероятно, завтра не будет времени полностью проверить это, но мне кажется, что это лучший ответ.
Можете ли вы опубликовать ответ на запрос изображения на вкладке сети инструментов Chrome dev?