phpreactjsapachebrowser-cachex-sendfile

Caching images in browser with URL parameters and XSendFile


I am trying to set up a site so that users only have access to their own images and audio files. To to this I am using variables in the URL such as:

 <img src="/public/get_file.php?type=image&file=pic001.png" />

On the front-end I am using React JS (not sure if that is important to this issue). But on the backend, the PHP script will validate that the user is logged in (just by checking a simple SESSION variable) and look for that file in the user's data directory (based on the user id in their SESSION variable). If it exists it will return it to the user using XSendFile.

The problem I am having is that every time that the user tries to access the files there is a bit of a delay before they load. This is telling me that they probably are not being cached by the browser.

Why are the files not getting cached? Does it have to do with the URL parameter or the use of PHP/XSendFile?

What can I do to allow my files (images/audio) to be cached?

Update

As requested here is my 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) . '"');

Solution

  • I think this is a duplicate.

    But since there is a bounty lets try to adapt your code together with the suggested solution there.

    You need to check that Apache has mod_expires and mod_headers enabled and working properly.

    And then before you start real output check if file was modified:

    ...
    $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) . '"');
    }