Кэширование изображений в браузере с параметрами URL и XSendFile - PullRequest
9 голосов
/ 10 марта 2019

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

Ответы [ 4 ]

0 голосов
/ 23 марта 2019

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

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

Вам необходимопроверьте, что в 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) . '"');
}
0 голосов
/ 20 марта 2019

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

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

0 голосов
/ 21 марта 2019

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

Может быть, это поможет: КАК КЕШИТЬ ИЗОБРАЖЕНИЯ, ПОСТАВЛЯЕМЫЕ PHP

0 голосов
/ 16 марта 2019

Попробуйте использовать этот тип заголовка (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 - это имя файла, которое пользователи видят для большей конфиденциальности файла.

...