Кэширование изображений в браузере с параметрами URL и XSendFile

Я пытаюсь настроить сайт так, чтобы пользователи имели доступ только к своим собственным изображениям и аудиофайлам. Для этого я использую переменные в 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) . '"');

Можете ли вы опубликовать ответ на запрос изображения на вкладке сети инструментов Chrome dev?

jsdeveloper 10.03.2019 23:13

@jsdeveloper Хотя я часто использую консоль, я не слишком привык использовать вкладку сети (ответ). Однако я вижу свой запрос, но в ответе говорится: «Запрос не имеет доступных данных для ответа».

kojow7 11.03.2019 03:52

просто для уточнения, вы хотите, чтобы браузер мог кэшировать изображения?

Vidal 20.03.2019 13:16

@kojow7 Какой HTTP-сервер вы используете?

Tomasz Kajtoch 20.03.2019 13:56

@TomaszKajtoch Я не совсем понимаю ваш вопрос. Мой вопрос помечен как Apache. Есть ли что-то еще, что вы ищете?

kojow7 20.03.2019 15:47

@Vidal Да, в настоящее время, если я перейду на одну страницу, она загрузит изображения, если я уйду на другую страницу, а затем вернусь на первую страницу, мне придется снова загрузить изображения.

kojow7 20.03.2019 15:51

Не могли бы вы опубликовать свой код get_file.php, пожалуйста?

Alex 23.03.2019 02:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
8
7
960
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Попробуйте использовать этот тип заголовка (код 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 чтобы избежать кеширования прокси-серверами.
UjinT34 19.03.2019 09:39

Для справки, это в основном связано с тем, что значение по умолчанию для session.cache_limiter равно nocache.

См. http://php.net/manual/en/function.session-cache-limiter.php о том, как установить другое значение, которое соответствует вашим потребностям.

Как вы генерируете изображения? У вас есть общедоступный локальный каталог или он загружается через CDN (удаленно)?

Может поможет: КАК КЭШИРОВАТЬ ИЗОБРАЖЕНИЯ, СОЗДАННЫЕ PHP

Изображения хранятся в каталогах на том же сервере. Каждый пользователь имеет свой собственный каталог пользователя, помеченный своим идентификатором пользователя.

kojow7 21.03.2019 15:23

Хорошо, так проще управлять кешем с локальными изображениями. Вы можете попробовать решение по ссылке и посмотреть, сработает ли оно. Но что произойдет, если кто-то попытается получить доступ к изображениям напрямую?

dm777 21.03.2019 18:07

Они не могут получить доступ к изображениям напрямую, поскольку они не находятся в папке, доступной через Интернет.

kojow7 21.03.2019 18:47
Ответ принят как подходящий

Я думаю, что это дубликат.

Но поскольку есть щедрость, давайте попробуем адаптировать ваш код вместе с предложенным там решением.

Вам нужно убедиться, что в 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, он отменяет свой запрос и вместо этого использует свой кеш?

kojow7 23.03.2019 04:44

да. Вот как браузер может повторно использовать кэшированные HTTP-ответы.

Alex 23.03.2019 04:49

Вероятно, завтра не будет времени полностью проверить это, но мне кажется, что это лучший ответ.

kojow7 24.03.2019 08:06

Другие вопросы по теме