📜 ⬆️ ⬇️

My version of .htaccess

In one of the previous thematic posts about .htaccess for noobs, I wanted to offer my version with different treatments and prohibitions, well, a certain structuring logic, but since karma was in the red, I am posting now.

To your attention, I look at the rules for processing URLs with explanations and comments "why so?".

First logic


I will explain the logic first:
1) All pages have .html endings.
2) all languages ​​for pages have the form pagename.en.html or pagename.html for the default language. No one, of course, forbids having links where the language first comes as / en /
3) there is only one “input” script in docroot.
4) Allow requests to other scripts only in docroot
5) Agreement on the definition of endings in url:
# site.com/
# site.com/index -> site.com/
# site.com -> site.com/
# site.com/file/ -> site.com/file.html
# site.com/file -> site.com/file.html
# site.com/dir/file -> site.com/dir/file.html
# site.com/dir/file/ -> site.com/dir/file.html
But it can be changed.
')

.Htaccess structure


Now let's move on to the .htaccess structure itself. I also note that it will only work for Apaches versions 2.x and later.

First, the complete code:
DirectoryIndex index index.html DirectorySlash off Options -Indexes -MultiViews # Rules # site.com/ # site.com/index -> site.com # site.com -> site.com/ # site.com/file/ -> site.com/file.html # site.com/file -> site.com/file.html # site.com/dir/file ->site.com/dir/file.html # site.com/dir/file/ -> site.com/dir/file.html # no ending slashes RewriteEngine On RewriteBase / RewriteCond %{REQUEST_URI} \.(css|jpg|gif|png|zip|rar|doc|xls|js|tif|tiff|docx|xlsx|ico)$|test\.php$ RewriteRule ^(.*)$ $1 [L,QSA] # nothing to do there in subrequests RewriteCond %{ENV:NS} !=1 RewriteCond %{IS_SUBREQ} =true RewriteRule (.*) $1 [L,QSA] #do NS=0? RewriteCond %{REQUEST_URI} ^/index$ [OR] RewriteCond %{REQUEST_URI} ^/index[.]+(\w+)$ RewriteRule . / [R=301,L] # remove trailing slashes # if want external redirect use correct external redir [R=301,L] or [R=301] for correct internal or simple redir [L] RewriteCond %{REQUEST_URI} !^/$ RewriteCond %{REQUEST_URI} (.*)/$ RewriteRule . %1.html [R=301,L,E=NS:1,QSA] # if whants .html endings RewriteCond %{REQUEST_URI} !^(.+)\.(html|php)$ RewriteRule . %{REQUEST_URI}.html [R=301,L] # fix multidots in endings (missed language) index..html instead of index.en.html RewriteCond %{REQUEST_URI} ^(.+)\.\.+(\w+)$ RewriteRule . %1.%2 [R=301,L] # otherways #RewriteCond %{REQUEST_URI} (.+)\.(html|php)$ # RewriteRule . %1 [R=301,L] # any php filename in root dir # this makes secure loses RewriteCond %{REQUEST_URI} ^[\w\-.]+$ RewriteCond %{REQUEST_FILENAME} (.*)\.(html|php)$ RewriteCond %1.php -s [OR] RewriteCond %1.html -s RewriteRule . %1.%2 [L,QSA] RewriteRule (.*) entry.php?URI=$1 [L,QSA] # 


Debriefing


Now, we will analyze line by line.

 DirectoryIndex index index.html DirectorySlash off Options -Indexes -MultiViews 

Immediately an important point: the automatic substitution of the slash to the end is turned off and MultiViews is turned off (it will not work with it).

 RewriteEngine On RewriteBase / RewriteCond %{REQUEST_URI} \.(css|jpg|gif|png|zip|rar|doc|xls|js|tif|tiff|docx|xlsx|ico)$|test\.php$ RewriteRule ^(.*)$ $1 [L,QSA] 


The third line checks for static files - we skip them without changing the request. Perhaps it would be worthwhile to check for the presence of a file, but let's leave this case to the 404 mechanism. The last |test\.php$ is made for various test files, but in the production this case should be removed.

 # nothing to do there in subrequests RewriteCond %{ENV:NS} !=1 RewriteCond %{IS_SUBREQ} =true RewriteRule (.*) $1 [L,QSA] #do NS=0? 

The most important part is because the extensions are being converted (hereinafter referred to as code), the script will always go to the subquery and may go to an infinite loop. To prevent this from happening, we catch the beginning of the subqueries and send the current request to the URL to the already corrected “input” script. This can be viewed by turning on rewrite_log in Apache.

 RewriteCond %{REQUEST_URI} ^/index$ [OR] RewriteCond %{REQUEST_URI} ^/index[.]+(\w+)$ RewriteRule . / [R=301,L] 

All attempts to get to `/ index 'or` index.html' will be redirected to the URL `/ '.

 # remove trailing slashes # if want external redirect use correct external redir [R=301,L] or [R=301] for correct internal or simple redir [L] RewriteCond %{REQUEST_URI} !^/$ RewriteCond %{REQUEST_URI} (.*)/$ RewriteRule . %1.html [R=301,L,E=NS:1,QSA] 

Solves one of the parts of the “agreement”: removes the trailing `/ 'from referring to the pages. The rules are described in paragraph (5) at the beginning. The comment says that if we want to use external redirect (changing the url in the browser string), then use [R=301,L] , if internal (change the url in the browser string), then [R=301] or [L]

 # if whants .html endings RewriteCond %{REQUEST_URI} !^(.+)\.(html|php)$ RewriteRule . %{REQUEST_URI}.html [R=301,L] 

Decides another part of the "agreement" that all requests for pages must have the ending .html. Small manipulations can do the opposite.

 # fix multidots in endings (missed language) index..html instead of index.en.html RewriteCond %{REQUEST_URI} ^(.+)\.\.+(\w+)$ RewriteRule . %1.%2 [R=301,L] 

Solves the problem of missing language in the query string by redirecting to the page with the default language.

 # any php filename in root dir # this makes secure loses RewriteCond %{REQUEST_URI} ^[\w\-.]+$ RewriteCond %{REQUEST_FILENAME} (.*)\.(html|php)$ RewriteCond %1.php -s [OR] RewriteCond %1.html -s RewriteRule . %1.%2 [L,QSA] 

Solves part of the agreement number 4 - allows requests to other php / html files in the% DOCUMENT_ROOT% folder of the site.

 RewriteRule (.*) entry.php?URI=$1 [L,QSA] 

If everything is as it should, then send a request to the "input" script.

miscellanea


As for the Apache flags: QSA is used everywhere (to complete the query string) - you can not forget about this, so as not to lose the parameters. E=NS:1 sets the environment variable NS to 1 — needed to define a subquery (the subquery created by the transformation rules by “agreement”, and not by any other subquery).

Source: https://habr.com/ru/post/141424/


All Articles