Can htaccess "try" different extensions?

Viewed 101

I have a folder with images uploaded by users in a few different formats. The files get numbered by my upload script with a unique ID.

When displaying them via php, I want to be able to link to them without knowing (or having to save in the database) their extension (i.e. images/42, images/69 and not images/42.png, images/69.jpeg. I have been doing some research but can't really come up with a way to write my .htaccess correctly. What I've done so far doesn't work and I had no success either trying to come up with my rewrite conditions. Any suggestions?

RewriteRule ^(.*)/?$    $1.(png|jpg|jpeg|gif)    [QSA,L]

I've found this but can't really adapt to my problem: https://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_s

1 Answers

Yes, you can manually try each extension in turn. Each extension will require a different rule. The first extension that matches will "win". If an extension matches then force the respective mime-type.

I assume your image URLs are of the form /images/<number>. This needs to be specific otherwise we will unnecessarily test the wrong URLs.

For example, near the top of your root .htaccess file:

# Check for ".webp" file (and check browser support)
# NB: If webp not supported then there needs to be a fallback (.png or .jpg)
RewriteCond %{HTTP_ACCEPT} (?:^|,)image/webp(?:,|$)
RewriteCond %{DOCUMENT_ROOT}/$0.webp -f
RewriteRule ^images/\d+$ $0.webp [T=image/webp,L]

# Check for ".png" file
RewriteCond %{DOCUMENT_ROOT}/$0.png -f
RewriteRule ^images/\d+$ $0.png [T=image/png,L]

# Check for ".jpg" file
RewriteCond %{DOCUMENT_ROOT}/$0.jpg -f
RewriteRule ^images/\d+$ $0.jpg [T=image/jpeg,L]

# Check for ".jpeg" file
RewriteCond %{DOCUMENT_ROOT}/$0.jpeg -f
RewriteRule ^images/\d+$ $0.jpeg [T=image/jpeg,L]

# Check for ".gif" file
RewriteCond %{DOCUMENT_ROOT}/$0.gif -f
RewriteRule ^images/\d+$ $0.gif [T=image/gif,L]

The $0 backreference contains the entire URL-path that is matched, eg. image/42. Each RewriteCond directive checks for the existence of the file with the respective file extension before internally rewriting the request to that file. The T flag ensures the correct Content-Type header is sent with the response.


images uploaded by users in a few different formats.

An alternative approach is to convert the image into a specific format as part of the upload process. So you always rewrite to .png (for example) - which will be more performant. And this has the added "security" benefit that malicious files (scripts that are "pretending" to be images) will get rejected since the image conversion will likely fail.


MultiViews (alternative)

Alternatively, you could simply enable MultiViews and let mod_negotiation do the work. mod_negotiation then checks various file extensions that return the appropriate mime-type and will return a resource that matches.

For example:

Options +MultiViews

No mod_rewrite directives are necessary.

HOWEVER, you don't have as much control over this, unless you manually create a type map in the server config and this might conflict and cause problems if you have other mod_rewrite directives. MultiViews will apply to everything unless you restrict it to certain paths.


RewriteRule ^(.*)/?$    $1.(png|jpg|jpeg|gif)    [QSA,L]

You can't do it in a single rule like this. This directive also matches everything (ie. ^(.*)/?$) - which naturally includes every URL that does not map to an image. The substitution string is an ordinary string, not a regex, so a construct like (png|jpg|jpeg|gif) is seen as literal text. The QSA flag is irrelevant here. The query string is appended by default anyway, but do you image URLs have a query string to begin with?

Related