Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webp .htaccess not working #45

Open
mauserrifle opened this issue Nov 21, 2019 · 8 comments
Open

Webp .htaccess not working #45

mauserrifle opened this issue Nov 21, 2019 · 8 comments

Comments

@mauserrifle
Copy link
Contributor

First thanks for the amazing work!

I could not get the webp .htaccess rules working. I had to add the following lines to some existing OctoberCMS rules:

RewriteCond %{REQUEST_URI} !webp.php$

Without this apache2 would parse all the rules multiple times. I even had situations I reached the max 10 internal redirects.

I also had alot of issues with the DOCUMENT_ROOT rewrites (slash issues, I think dependend on how the document_root is set invhost). Eventually I picked the rules from the Wordpress webp express plugin:

    # Redirect to existing converted image in same dir (if browser supports webp)
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_FILENAME}.webp -f
    RewriteRule ^/?(.*)\.(jpe?g|png)$ $1.$2.webp [NC,T=image/webp,E=EXISTING:1,E=ADDVARY:1,L]


    # Redirect images to webp-on-demand.php (if browser supports webp)
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^(/?(.+)\.(jpe?g|png))$ /plugins/offline/responsiveimages/webp.php?path=$1 [NC,L,E=REQFN:%{REQUEST_FILENAME},E=WPCONTENT:app]

With these changes everything worked perfectly! :)

Hope you understand the issues I have had and find it useful to improve things.

My full .htaccess:

## START OFFLINE.ResponsiveImages - webp-rewrite
#  DO NOT REMOVE THESE LINES
<IfModule mod_setenvif.c>
    # Vary: Accept for all the requests to jpeg and png
    SetEnvIf Request_URI "\.(jpe?g|png)$" REQUEST_image
</IfModule>
<ifModule mod_rewrite.c>
    RewriteEngine On

    # Redirect to existing converted image in same dir (if browser supports webp)
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_FILENAME}.webp -f
    RewriteRule ^/?(.*)\.(jpe?g|png)$ $1.$2.webp [NC,T=image/webp,E=EXISTING:1,E=ADDVARY:1,L]


    # Redirect images to webp-on-demand.php (if browser supports webp)
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^(/?(.+)\.(jpe?g|png))$ /plugins/offline/responsiveimages/webp.php?path=$1 [NC,L,E=REQFN:%{REQUEST_FILENAME},E=WPCONTENT:app]

</ifModule>
<IfModule mod_headers.c>
    Header append Vary Accept env=REQUEST_image
</IfModule>
<IfModule mod_mime.c>
    AddType image/webp .webp
</IfModule>
## END OFFLINE.ResponsiveImages - webp-rewrite

<IfModule mod_rewrite.c>

    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    ##
    ## You may need to uncomment the following line for some hosting environments,
    ## if you have installed to a subdirectory, enter the name here also.
    ##
    # RewriteBase /

    ##
    ## Uncomment following lines to force HTTPS.
    ##
    # RewriteCond %{HTTPS} off
    # RewriteRule (.*) https://%{SERVER_NAME}/$1 [R,L]

    ##
    ## Black listed folders
    ##
    RewriteCond %{REQUEST_URI} !webp.php$
    RewriteRule ^bootstrap/.* index.php [L,NC]
    RewriteRule ^config/.* index.php [L,NC]
    RewriteRule ^vendor/.* index.php [L,NC]
    RewriteRule ^storage/cms/.* index.php [L,NC]
    RewriteRule ^storage/logs/.* index.php [L,NC]
    RewriteRule ^storage/framework/.* index.php [L,NC]
    RewriteRule ^storage/temp/protected/.* index.php [L,NC]
    RewriteRule ^storage/app/uploads/protected/.* index.php [L,NC]

    ##
    ## White listed folders
    ##
    RewriteCond %{REQUEST_URI} !webp.php$
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteCond %{REQUEST_FILENAME} !/.well-known/*
    RewriteCond %{REQUEST_FILENAME} !/storage/app/uploads/.*
    RewriteCond %{REQUEST_FILENAME} !/storage/app/media/.*
    RewriteCond %{REQUEST_FILENAME} !/storage/temp/public/.*
    RewriteCond %{REQUEST_FILENAME} !/themes/.*/(assets|resources|dist)/.*
    RewriteCond %{REQUEST_FILENAME} !/plugins/.*/(assets|resources)/.*
    RewriteCond %{REQUEST_FILENAME} !/modules/.*/(assets|resources)/.*
    RewriteRule !^index.php index.php [L,NC]

    ##
    ## Block all PHP files, except index
    ##
    RewriteCond %{REQUEST_URI} !webp.php$
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteCond %{REQUEST_FILENAME} \.php$
    RewriteRule !^index.php index.php [L,NC]

    ##
    ## Standard routes
    ##
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

</IfModule>
@tobias-kuendig
Copy link
Member

Thank you very much for your feedback!

RewriteCond %{REQUEST_URI} !webp.php$

That's strange, this rule should not be required since the .htaccess should never reach October's PHP blacklist rules.

I have updated the rules a bit, would you mind testing if this works on your server (without the explicit whitelisting of the webp.php?) If I remove the %{DOCUMENT_ROOT} in the webp.php RewriteRule, it no longer works on my server 🤔

https://github.com/OFFLINE-GmbH/oc-responsive-images-plugin/blob/develop/views/webp-rewrite.htm#L6-L17

@mauserrifle
Copy link
Contributor Author

mauserrifle commented Nov 22, 2019

The latest updates work. But only worked with the RewriteCond %{REQUEST_URI} !webp.php$ lines. Thus I searched further. This behavior is documented by apace2 at: https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_l

So we need to use the END flag instead of L 👍

It works using:

RewriteRule (.+)$ %{DOCUMENT_ROOT}/plugins/offline/responsiveimages/webp.php?path=$1 [NC,END]

Other point: It's important to only match the storage folder. For example. My theme images are now always served using webp.php. Example theme file:

/themes/XXXX/assets/dist/app/apple-touch-icon.png

which is not a good thing to do. These files should just be served static.

@tobias-kuendig
Copy link
Member

Wow, thank you for this input! I did not know about the END flag. Also, very good point concerning the storage folder. I came up with this new ruleset:

<ifModule mod_rewrite.c>
    RewriteEngine On

    # If the Browser supports WebP images, and the .webp file exists, use it.
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_URI} ^/?storage/.*\.(jpe?g|png)
    RewriteCond %{REQUEST_FILENAME}.webp -f
    RewriteRule ^/?(.*)$ $1.webp [NC,T=image/webp,END]

    # If the Browser supports WebP images, and the .webp file does not exist, generate it.
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_URI} ^/?storage/.*\.(jpe?g|png)
    RewriteCond %{REQUEST_FILENAME}\.webp !-f
    RewriteRule ^/?(.*)$ %{DOCUMENT_ROOT}/plugins/offline/responsiveimages/webp.php?path=$1 [NC,END]
</ifModule>

@mauserrifle
Copy link
Contributor Author

Yep this is it 😃 . Works great!

@mauserrifle
Copy link
Contributor Author

I also made a further little change to my project rules which makes sure only resized images are served as webp (RewriteCond %{REQUEST_URI} ^/?storage/.*/public/.*\.(jpe?g|png)). But is a personal preference. I had big original images that were converted to webp, but timed out during the proces.

@schillerenrico
Copy link

schillerenrico commented Feb 23, 2021

I think the main problem is, that the plugin creates a new file with the file extension itself. For example
image.jpg becomes image.jpg.webp
and the htaccess file recognize the following rule as true:

    RewriteCond %{REQUEST_URI} ^/?storage/.*\.(jpe?g|png)

The plugin should create the new file without the jpg extension. I added a webp extension rule to exclude this case like so:
see # !important!

## START OFFLINE.ResponsiveImages - webp-rewrite
#  DO NOT REMOVE THESE LINES
<IfModule mod_setenvif.c>
    # Vary: Accept for all the requests to jpeg and png
    SetEnvIf Request_URI "\.(jpe?g|png)$" REQUEST_image
</IfModule>
<ifModule mod_rewrite.c>
    RewriteEngine On

    # If the Browser supports WebP images, and the .webp file exists, use it.
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_URI} ^/?storage/.*\.(jpe?g|png)$
    RewriteCond %{REQUEST_FILENAME}\.webp -f
    RewriteRule ^(.*)$ $1.webp [L,T=image/webp,R=301]

    # If the Browser supports WebP images, and the .webp file does not exist, generate it.
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{REQUEST_URI} ^/?storage/.*\.(jpe?g|png)
    RewriteCond %{REQUEST_URI} !\.(webp)$ # !important!
    RewriteCond %{REQUEST_FILENAME}.webp !-f
    RewriteRule ^/?(.*)$ plugins/offline/responsiveimages/webp.php?path=$1 [N,END]


</ifModule>
<IfModule mod_headers.c>
    Header append Vary Accept env=REQUEST_image
</IfModule>
<IfModule mod_mime.c>
    AddType image/webp .webp
</IfModule>
## END OFFLINE.ResponsiveImages - webp-rewrite

@tobias-kuendig
Copy link
Member

I'm drawing a blank. I currently fail to see the problem.

The frontend will issue a request for /stroage/any/file.jpg, since this is in your markup. The htaccess rule sees that and checks for the same filename witht he webp extension. If it exists, it serves it. Otherwise it will redirect the request to the webp.php.

Where do things go wrong?

@schillerenrico
Copy link

Thats working great and is not the problem :)
Requests like "...file.jpg.webm" are handled like a .jpg file not like a webm file.
In my case I wanted the url to be the real webm path, so I did a 301 to the webm file if an image is requested and a webm does exists.
If a webm doesnt exist, your case will trigger and create it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants