webp fallback jpg using htaccess - .htaccess

I use webp format by default in images, I want to show the jpg version in browsers that do not support webp.
I want to do this using htaccess, my code converts jpg to webp, how can I reverse this?
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
RewriteRule (.+)\.(jpe?g|png|gif)$ $1.webp [T=image/webp,E=REQUEST_image]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REQUEST_image
</IfModule>
<IfModule mod_mime.c>
AddType image/webp .webp
</IfModule>

So you're linking to .webp images and you want to serve the corresponding .jpg image if the user does not support image/webp type images, but presumably testing whether the corresponding .jpg image actually exists first before trying to serve it...
RewriteCond %{HTTP_ACCEPT} !image/webp
RewriteCond %{DOCUMENT_ROOT}/$1.jpg -f
RewriteRule (.+)\.webp$ $1.jpg [T=image/jpeg,E=REQUEST_image]
Testing whether the .jpg image exists maybe unnecessary if the user-agent does not actually support webp images anyway. Which is preferable... some kind of image display issue or a 404? Then again, if the .jpg image always exists then the file check is redundant anyway.

Related

Litespeed returns 403 when rewriting the URL of an existing image

My customer is using Litespeed with CPanel v106.0.10.
I have a RewriteRule like this in .htaccess file:
RewriteCond %{HTTP_HOST} ^www.site.com$
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}%{ENV:REWRITEBASE}/img/$1.webp -s
RewriteRule ^img/([_a-zA-Z0-9-]+)\.jpg$ %{ENV:REWRITEBASE}img/$1.webp [B,L]
RewriteCond %{HTTP_HOST} ^www.site.com$
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}%{ENV:REWRITEBASE}/img/$1.webp !-s
RewriteRule ^img/([_a-zA-Z0-9-]+)\.jpg$ %{ENV:REWRITEBASE}webp.php?src=img/$1.jpg [B,L]
The goal is to serve images into WEBP format when the WEBP file exists, if not then call the PHP script to compress the JPG file into WEBP format.
It's working good with Apache but when using Litespeed server I get a 403 error when the WEBP file does not exists.
Also when the URL of the image does not match the real file name (URL rewriting) then it also works.
So I think there is something that blocks URL rewriting when the URL match with a real file.
Who can help?
I found that this is a difference between Apache and Litespeed.
Litespeed does not prioritize the rules defined in .htaccess files in the same way as Apache. Thus PHP files are forbidden in the "/img" directory, when the URL "/img/image.webp" arrives, Apache applies the redirection to the PHP compressor but does not apply the "access denied" on the script because it is not in the "/img" directory, whereas Litespeed applies the redirection to the PHP compressor but blocks access to it (403) because the original URL starts with "/img".
I guess that this is a bug from Litespeed.

How to serve webp from a different folder using .htaccess

I have a folder /assets/admin/images/products which contains .jpg and .png files and another folder /assets/admin/images/products/webp with the webp version of .jpg and .png files with name filename.webp (jpg and png is not added in file names)
How do i serve webp version of image from different folder using htaccess
I found some information at https://github.com/vincentorback/WebP-images-with-htaccess but it only serves from same folder.
I tried below htaccess code, but it didn't work
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}/webp/$1.webp -f
RewriteRule (.+)\.(jpe?g|png|gif)$ %{DOCUMENT_ROOT}/webp/$1.webp [T=image/webp,E=REQUEST_image]
Your code is good but you don't need %{DOCUMENT_ROOT} on the last line with RewriteRule. This is the problem.
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}/webp/$1.webp -f
RewriteRule (.+)\.(jpe?g|png|gif)$ webp/$1.webp [T=image/webp,E=REQUEST_image]

htaccess: serve webp image instead of jpg or png if webp exist results in 404

I generated *.webp files that are named exactly like their png or jpg source. Then I added this to my .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
# Does browser explicitly support webp?
RewriteCond %{HTTP_USER_AGENT} Chrome [OR]
# OR Is request from Page Speed
RewriteCond %{HTTP_USER_AGENT} "Google Page Speed Insights" [OR]
# OR does this browser explicitly support webp
RewriteCond %{HTTP_ACCEPT} image/webp [OR]
# AND does a webp image exists?
RewriteCond %{DOCUMENT_ROOT}/$1\.webp -f
# THEN send the webp image and set the env var webp
RewriteRule (.+\.(?:jpe?g|png))$ $1.webp [NC,L]
</IfModule>
<IfModule mod_mime.c>
AddType image/webp .webp
</IfModule>
What I expect:
all jpg files load normal e.g /test/marc.jpg If a webp with the same name exists, serve a webp file via url /test/marc.jpg
This works of the webp file exists. But if I delete a webp file I get a 404 on the jpg or png url. Even old jpg or png urls then give a 404. Example:
/www/media/
.htaccess
marc.jpg
marc.webp
http://domain/marc.jpg serves the webp. I test this from chrome with cache disabled. When I delete the marc.webp I get a 404 on http://domain/marc.jpg Why? RewriteCond %{DOCUMENT_ROOT}/$1.webp -f should fix this, right?
These two lines are not looking for the files you describe:
# AND does a webp image exists?
RewriteCond %{DOCUMENT_ROOT}/$1\.webp -f
# THEN send the webp image and set the env var webp
RewriteRule (.+\.(?:jpe?g|png))$ $1.webp [NC,L]
In both of these, $1 refers to the first captured match in the RewriteRule, which in this case is (.+\.(?:jpe?g|png)). If you request, "marc.jpg", that whole string matches, and will be placed in $1. The two lines therefore evaluate as:
If the file "marc.jpg.webp" exists, respond with "marc.jpg.webp"
Since it doesn't, the rule will not be run.
The condition you wanted was:
If the file "marc.webp" exists, respond with "marc.webp"
So you want $1 to contain only the "marc" part of the requested file; that's just a matter of moving the closing parenthesis:
RewriteRule (.+)\.(?:jpe?g|png)$ $1.webp [NC,L]
This doesn't explain why your rule appeared to work, and stopped working when you deleted a file. I suspect you have another rule somewhere else which is confusing the situation.

Remove duplicate extension on file with .htaccess

I've been playing around with .htaccess to try and rewrite images for a specific browser (Safari).
I have images uploaded that are named like: myimage.png.webp and would like to have the .webp removed leaving the myimage.png so that the <img> tags point to a duplicate file that isn't a WebP.
This is what I tried patching together so far, but it just resulted in a 500 Error and I'm getting myself confused with the rules now. Can anyone help?
#RewriteCond %{HTTP_USER_AGENT} Safari
# check if an image was requested
#RewriteCond %{REQUEST_FILENAME} .(jpe?g|gif|bmp|png|svg).webp -f
#RewriteRule ^.*/uploads/(.*).(svg|png|jpe?g|gif|bmp).webp$ https://%{HTTP_HOST}/uploads/$1.$2 [L,R=302]
Your directives appear to do the opposite of what you're trying to do, as if you were linking to the myimage.png.webp file and externally redirecting to the myimage.png file?
I assume you are already linking to the myimage.png file (as stated). We then need to do some feature sniffing to make sure that the browser can support webp files (and that the .webp file actually exists) before rewriting the request.
For example:
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}/$1.$2.webp -f
RewriteRule (.+)\.(png|jpe?g|gif)$ /$1.$2.webp [T=image/webp,L]
The T flag ensures we send back the appropriate mime-type for the webp response.
UPDATE: It seems you are actually linking to the .webp image and wish to rewrite the corresponding png/jpg/gif when webp is not supported (ie. Safari)...
# Rewrite images to WebP if they exist
RewriteCond %{HTTP_USER_AGENT} Safari
RewriteCond %{DOCUMENT_ROOT}/$1.$2.webp -f
RewriteRule (.*).(png|jpe?g|gif).webp$ $1.$2 [T=image/$2,L]
This isn't strictly correct:
Safari isn't the only browser that doesn't support webp images. Notably, there is IE11 (which still has a reasonable market share, certainly comparible to Safari in some demographics) and other minor browsers (eg. KaiOS). By checking the user-agent, you need to also update the rule when these browsers do support webp images. It is therefore preferable to instead test whether the browser actually supports image/webp images (or not) by checking the Accept HTTP request header.
The 2nd condition is checking whether the .webp image exists, before rewriting to the non-webp image. Presumably you want to check that the non-webp image exists (or remove this condition altogether - since the request will presumably "fail" anyway if the user-agent does not support webp images).
The returned mime-type will be incorrect if your images are .jpg (as opposed to .jpeg) since image/jpeg is the correct mime-type, not image/jpg. This is harder to fix, unless you split this into its own rule.
Try the following instead:
# Rewrite images to non-WebP if webp are not supported and they exist
RewriteCond %{HTTP_ACCEPT} !image/webp
RewriteCond %{DOCUMENT_ROOT}/$1.$2 -f
RewriteCond $2#jpeg ^jpe?g#(.+)|(.+)#
RewriteRule (.+)\.(png|jpe?g|gif)\.webp$ $1.$2 [T=image/%1%2,L]
The (rather cryptic) 3rd condition extracts the required mime-type "part": png, jpeg or gif respectively, regardless of whether .jpg or .jpeg is requested. These are saved in the %1 and %2 backreferences. Note that these are mutually exclusive. Either %1 holds jpeg (and %2 is empty), OR %2 holds png or gif (and %1 is empty). So together they form the correct response.
Note that literal dots in the RewriteCond TestString don't need to be escaped, since this is an "ordinary" string. However, the literal dots in the RewriteRule pattern do need to be backslash escaped since this is a regex.
You may try this rule in your site root .htaccess:
RewriteCond %{HTTP_USER_AGENT} Safari
RewriteCond %{REQUEST_FILENAME}.webp -f
RewriteRule ^.+\.(?:svg|png|jpe?g|gif|bmp)$ $0.webp [L,NC]
I managed to get it working the way I need, and with a bit of help from the other two answers, my htaccess rule is doing what I expect:
# Rewrite images to WebP if they exist
RewriteCond %{HTTP_USER_AGENT} Safari
RewriteCond %{DOCUMENT_ROOT}/$1.$2.webp -f
RewriteRule (.*).(png|jpe?g|gif).webp$ $1.$2 [T=image/$2,L]
So this will take an image URL like this:
https://example.com/uploads/test.png.webp and swap it to a fallback duplicate image on Safari/iOS (where webp still isn't supported), and output to the browser: https://example.com/uploads/test.png

mod_rewrite change extensions .gif/.jpg to .png

The rule I have been fruitlessly working with doesn't work, I am trying to get all images in 1 directory to load as .png The images in the directory are a mixture of .png, .jpg and .gif
I want to be able to load the file tree.jpg by going to tree.png (no files have the same name). I am sure my mistake is obvious or my entire attempt is wrong, I just can't work it out.
The htaccess file is in the same folder with the images, which is called /thumbs
RewriteEngine On
RewriteRule ^([^.]*)\.gif$ /thumbs/$1.png [R,L,NC]
I tried this also, but it just givens a broken link to both .gif and .png versions
RewriteEngine on
RewriteRule ^(.+)\.gif$ $1.png
I tried this too, but it adds in my server path to the URL for some reason
RewriteEngine on
RewriteRule ^([^.]*)\.gif$ $1.png [R,L,NC]
You can use this rule:
RewriteEngine on
RewriteRule ^([^.]+)\.png$ /$1.gif [L,NC,R]

Resources