Search code examples
regexapache.htaccessmod-rewrite

.htaccess how to check REQUEST_URI doesn't contain any file type


i have 2 type of routing mechanism

  1. if it is a png or jpeg, redirect to a folder named assets
  2. if it is not a png or jpeg, redirect to index.php

now i want to extend file types but i don't want to write them one by one, how can i check if is there any extension at the end of the url?

Current redirect(manual one);

RewriteCond %{REQUEST_URI} \.(jpe?g|bmp|png|gif|svg|webp|mp3|mp4|css|js|woff2|woff|ttf|html|map)$
RewriteCond %{REQUEST_URI} frontend/assets
RewriteRule ^(.*)$ $1 [NC,L,END]

what i've tried;

RewriteCond %{REQUEST_URI} !^\.(.*)$
RewriteCond %{REQUEST_URI} frontend/assets
RewriteRule ^(.*)$ $1 [NC,L,END]

Solution

  • You could do it like this instead:

    DirectoryIndex index.php
    
    RewriteEngine On
    
    # 1. Exception for URL requests that contain a file extension
    #  - Prevents further processing
    RewriteRule \.\w{2,5}$ - [END]
    
    # 2. Rewrite everything else (including directory requests) to "index.php"
    RewriteRule . index.php [END]
    

    A "file extension" is deemed to be a dot followed by between 2 and 5 characters from the character from the range a-z, A-Z, 0-9 and _ (underscore).

    Although the above two rules could be combined into one:

    # 1 + 2. Rewrite everything that does not have a file extension to "index.php"
    RewriteRule !\.\w{2,5}$ index.php [END]
    

    (Minor difference is that this rule also rewrites the root directory to index.php instead of relying on mod_dir.)

    And if you simply want to route everything to index.php, except for files and directories then just use the following instead (this replaces everything above):

    FallbackResource /index.php
    

    A look at your current rules:

    RewriteCond %{REQUEST_URI} \.(jpe?g|bmp|png|gif|svg|webp|mp3|mp4|css|js|woff2|woff|ttf|html|map)$
    RewriteCond %{REQUEST_URI} frontend/assets
    RewriteRule ^(.*)$ $1 [NC,L,END]
    

    This is an "exception". It prevents further processing if the conditions are met. (It doesn't actually do anything to further process the URL, it just prevents the request being rewritten to the front-controller, which presumably follows.)

    There's seemingly no need to check that the requested URL ends in a file extension AND the URL-path contains frontend/assets. If all your assets are contained in a known location then it would be arguably preferable to just exclude that known location. Although you also mention a .php extension in the comments, which may not fall under "assets".

    There's also no need to captured the requested URL-path and rewrite the request to the same. To indicate "no substitution" just use a single hyphen (as I did in the rule above).

    The NC and L flags are also superfluous here. END is a "stronger" version of L that prevents any further passes by the rewrite engine.

    RewriteCond %{REQUEST_URI} !^\.(.*)$
    :
    

    This negated expression is kind of doing the opposite of what you are trying to achieve, except that the regex is also incorrect. This condition is successful when the requested URL-path does not match a URL of the form .<anything>. This is always going to be successful since the REQUEST_URI server variable always starts with a slash.