Search code examples
regexapache.htaccessmod-alias

htaccess redirectMatch all files of a type except a certain one


Say I have a web folder with:

/index.html
/assets/css/styles.css
/assets/images/logo.png
/something.html
/holdingpage.html
/finale.html
/folder/somefile.html
/else.html
/PDFs/something.pdf

I want to put in place an htaccess RedirectMatch for this to "catch" all the files that are html files except the finale.html and redirect to there.

What I have so far is:

RedirectMatch 302 ".*/$" "/finale.html"

Which correctly catches all folder without filenames (indexes). What I need is to catch all the html but not that destination one.

RedirectMatch 302 ".*(\.html)$" "/finale.html" # This loops obviously. 

So I tried to be more specific;

RedirectMatch 302 ".*!(finale.html)$" "/finale.html" 

RedirectMatch 302 ".*!(finale\.html)$" "/finale.html" 

But this doesn't catch other files. Also by the looks of it I'd expect this to also catch assets and images.

I am trying to find a redirectMatch that finds every .html page that is NOT finale.html and redirect it to that page.

IT should be a redirectMatch and NOT a rewriteCond / rewriteRule. The user needs to see they're being redirected.

I imagine I want something like:

RedirectMatch 302 ".*((\.html) BUT NOT (finale.html))$" "/finale.html" 

I have read the Apache Documentation but this doesn't really elaborate on this concept very much.


Solution

  • You can use a negative lookahead to match all .html files except for /finale.html (in the document root).

    For example:

    RedirectMatch 302 (?!^/finale\.html$)^/.+\.html$ /finale.html
    

    IT should be a redirectMatch and NOT a rewriteCond / rewriteRule. The user needs to see they're being redirected.

    I'm not sure of the logic here. mod_rewrite can produce external redirects just the same as RedirectMatch and in fact, you should probably be using mod_rewrite here if you have existing mod_rewrite directives (primarily to avoid unexpected conflicts).

    With mod_rewrite, you can do it similar to above with a negative lookahead. For example:

    RewriteEngine On
    
    RewriteRule (?!^finale\.html$)^.+\.html$ /finale.html [R=302,L]
    

    Or, use an additional condition to make an exception for finale.html, instead of using a negative lookahead. For example:

    RewriteCond %{REQUEST_URI} !^/finale\.html$
    RewriteRule \.html$ /finale.html [R=302,L]
    

    Which is arguably easier to read and possibly more efficient (the regex at least).

    This matches all URLs that end in .html, except for /finale.html (exactly) and externally 302 redirects to /finale.html.


    Aside:

    RedirectMatch 302 ".*!(finale.html)$" "/finale.html" 
    

    The ! in the middle of the regex is a literal character here. The ! prefix-operator is a feature of mod_rewrite. (It is a prefix-operator, not part of the regex syntax itself.