skip to Main Content

I’m trying create a caching system for an "on demand" PHP image resizer.

I need to be able to check if the following file and query string exists in cache:

https://www.example.com/images/img.jpg?w=400&h=300&fit=crop

My PHP script generates the cached file by replacing all special chars (?,&,=) with underscore.
This is what the cached object looks like:
/cache/images/img.jpg_w_400_h_300_fit_crop

How do I check if the requst + query exists in /cache as file and serve it if it does?

What I currently have that works for files without query vars is this:

# if file exists in /cache/ directory
# serve file from /cache/ directory
RewriteCond  %{DOCUMENT_ROOT}/cache/$1 -f
RewriteRule ^(.*)$ /cache/$1 [L,QSA]

I tried with something like this but it doesn’t work because I suck at htaccess/regex 🙂

RewriteCond %{QUERY_STRING} ^(.*)(:?&|?|=)(.*)$
RewriteCond %{DOCUMENT_ROOT}/cache/$1_%1_%2 -f 
RewriteRule ^(.*)$  /cache/$1 [L]

2

Answers


  1. With your shown samples, could you please try following. Please make sure to clear your browser cache before testing your URLs.

    RewriteEngine ON
    ##Rules for URL like: https://www.example.com/images/img.jpg?w=400&h=300&fit=crop
    RewriteCond %{THE_REQUEST} s/(?:[^?]*)?([^=]*)=([^&]*)&([^=]*)=([^&]*)&([^=]*)=(.*)s
    RewriteCond %{DOCUMENT_ROOT}/cache/$1_%1_%2_%3_%4_%5_%6 -f
    RewriteRule ^(.*)$ /cache/$1?%1_%2_%3_%4_%5_%6 [L]
    
    Login or Signup to reply.
  2. My PHP script generates the cached file by replacing all special chars (?,&,=) with underscore.

    You could do the same thing in .htaccess. This then handles "any number"1 of URL parameters (since you’ve stated this is variable in comments).

    Try the following script near the top of your .htaccess file. Ideally, this needs to be near the top due to the recursive nature of the search/replace looping.

    # 1. Create env var for the image cache filename (IMAGE_CACHE_FN)
    RewriteCond %{ENV:IMAGE_CACHE_FN} ^$
    RewriteCond %{QUERY_STRING} (.+)
    RewriteRule ^images/[w-]+.jpg$ - [E=IMAGE_CACHE_FN:cache/$0_%1]
    
    # 2. Recursively replace "=" and "&" in IMAGE_CACHE_FN with "_"
    RewriteCond %{ENV:IMAGE_CACHE_FN} ^(.*)[=&](.*)$
    RewriteRule ^ - [E=IMAGE_CACHE_FN:%1_%2,N=50]
    
    # 3. Test if image cache file exists and rewrite if so
    RewriteCond %{ENV:IMAGE_CACHE_FN} .
    RewriteCond %{DOCUMENT_ROOT}/%{ENV:IMAGE_CACHE_FN} -f
    RewriteRule ^ %{ENV:IMAGE_CACHE_FN} [L]
    

    I chose to use an environment variable IMAGE_CACHE_FN to hold the value of the image cache filename as it is constructed, rather than modify the query string or URL-path in-place since I expect you are probably using these later in your PHP script.

    1 I’ve limited this to 50 recursive "loops" max (which equates to about 26 URL parameters) in the script above. This is identified by the N=50 flag on the second RewriteRule.

    A potential caveat with this is if the URL parameters are supplied in a different order then you’ll naturally get a different cache filename for essentially the same resource. Although the same will apply to your PHP script, unless you are ordering the parameters first? (But then you potentially have issues with duplicate images and caching unless you redirect the request.) I’m assuming you are supplying the URL params in a specific order.

    You can potentially order the URL parameters in .htaccess, but it can get cumbersome…

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search