Metacharacters
Example:
RewriteRule ^old(.*)$ /new.php [L,R=301]
They are used to define character groups or "labels" in a pattern. For example, labels for the start or end of a line.
| \ | The "escaping" backslash. The character following it is treated as a regular character, not a special one. The backslash is placed before special characters if they are needed in their literal form. For example, the expression "jpe\+g" matches only the single string "jpe+g". |
| ^ | The ^ symbol denotes the start of a line. |
| $ | The $ symbol denotes the end of a line. |
| ! | Negation symbol. |
| . | The . symbol denotes any character (except the line break character). |
| .* | Replaces any sequence of characters. |
| ".*" | Finds all substrings between quotes. |
| | | The | symbol denotes alternation. For example, the expressions "A|B" and "(ABC|DEF)" mean "A or B" and "ABC or DEF", respectively. |
| () | Parentheses () are used to group characters. |
| [...] | Square brackets [] are used to list allowed characters. For example, the expression "[abc]" is equivalent to "a|b|c", but the square bracket version is usually more efficient in terms of performance. Ranges can be used inside brackets: for example, the expression "[0-9]" is equivalent to "[0123456789]". |
| [^...] | Inverted character class. If the characters inside square brackets start with ^, it means any character except those listed in the brackets. For example, the expression "[^0-9]+" means a string consisting of any characters except digits. |
| [...]* | For example, [abc]* — the command will find consecutive characters from the specified set. [^abc]* — does the opposite. |
| \w | A letter, digit, or underscore _. |
| \d | Replaces any digit. |
| \D | Replaces any character that is not a digit. |
| [0-9] | Replaces any digit. |
| [a-z] | Any letter from a to z (the entire Latin character set) in lowercase. |
| [A-Z] | Any letter from A to Z in UPPERCASE. |
| [a-zA-Z] | Any letter from a to Z in any case. [a-Z] — same thing. |
Note. Everything located after the '#' symbol is considered a comment.
Modifiers
Example:
RewriteRule (.*) $1? [R=301,L]
Modifiers are used after regular characters, special characters, or their groups and allow expanding the capabilities of patterns for rule matching.
| ? | Repeats 0 or 1 time. The ? symbol is placed after a character (or group of characters) that may or may not be present. For example, the pattern "jpe?g" matches both "jpg" and "jpeg". |
| * | Repeats from 0 to 65536 times. The * symbol is placed after a character (or group of characters) that may be absent or present an unlimited number of times consecutively. For example, the pattern "jpe*g" matches "jpg", "jpeg", and "jpeeeeeeg". |
| + | Repeats from 1 to 65536 times. The + symbol works similarly to * with the only difference being that the preceding character must be present at least once. For example, the pattern "jpe+g" matches "jpeg" and "jpeeeeg", but not "jpg". |
| {n} | Exactly n times. |
| {n,} | From n to 65536 times inclusive. |
| {n,m} | From n to m times inclusive. |
Usage examples:
^stena
Any strings starting with the word "stena". A string starting with "dom-stena" will not meet the criteria.
stena$
Any strings ending with the character sequence "stena". A string ending with "stena-dom" will not match.
.*
Any character repeated any number of times. All strings will match this criterion.
^(.*)$
Select any string and save it as variable $1 for further use.
[0-9]{1,6}$
Select all strings ending with 1 to 6 digits from the range 0–9.
^(.+)/(.+)$
Split the string into two parts: before and after the slash. The string parts will be available via variables $1 and $2.
Important! Since the modifier is greedy, the first group will capture the maximum number of characters matching the pattern. The slash is treated as just another character.
Usage example:
RewriteRule ^(.+)/(.+)$ /?a=$1&b=$2 [R=301,L]
http://www.site.com/1/2/3/4/5 →
http://www.site.com/?a=1/2/3/4&b=5
Flags
Example:
RewriteRule ^htaccess-fake$ - [G] RewriteRule (.*) page.php\?%1 [L]
Flags are additional options. They are listed in square brackets separated by commas, e.g., [NC] or [R=301,L].
| R | (redirect) stops the rewriting process and returns the result to the client browser as a redirect to this page (302, MOVED TEMPORARY). With this flag, you can specify a different result code; for example, "R=301" will return a redirect with code 301 (MOVED PERMANENTLY). |
| F | (forbidden) returns a 403 (FORBIDDEN) error. |
| G | (gone) returns a 410 (GONE) error. |
| P | (proxy) - with this flag, Apache performs a sub-request to the specified page using the mod_proxy module, and the user is not aware of this sub-request. If the mod_proxy module is not included in your Apache build, using this flag will cause an error. |
| L | (last) stops the rewriting process, and the current link is considered final. |
| N | (next) restarts the rewriting process from the first rule in order. |
| C | (chain) chains multiple rules together. If the first rule in the chain does not match, the entire chain is ignored. |
| NS | (nosubreq) allows the rule to match only for actual requests, ignoring sub-requests (a sub-request can be triggered, for example, by including a file using the SSI directive). |
| NC | (nocase) disables case sensitivity when matching the rule. |
| QSA | (qsappend) appends the original query string to the substitution. If the substitution does not include new query parameters, the original query parameters are added automatically. If it does include new query parameters, the original query parameters will be lost without the QSA flag. |
| PT | (passthrough) stops the rewriting process and passes the resulting new link further down the chain so that directives such as Alias, ScriptAlias, Redirect, and similar ones can process it (whereas with the L flag, the new link is considered final and is not subject to further processing). |
| S | (skip) skips the next rule if the current rule matches. You can skip multiple rules by specifying the number, for example: "S=3". |
| E | (env) sets an environment variable, for example: "E=variable:value". |
Tests
Example:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !
RewriteCond %{REQUEST_FILENAME}\.html
RewriteRule ^(.*)$ $1.php
The following tests can be used in conditions:
1. You can prefix the pattern with a '!' character to indicate that the pattern should not match.
2. You can perform lexicographical string comparison:
| <Condition | Lexicographically less than |
| >Condition | Lexicographically greater than |
| = Condition | Equality |
| <= Condition | Lexicographically less than or equal to |
| >= Condition | Lexicographically greater than or equal to |
3. Comparison as integers:
| -eq | Numerically equal |
| -ge | Numerically greater than or equal |
| -gt | Numerically greater than |
| -le | Numerically less than or equal. To avoid confusion with the uppercase letter -l, use -L |
| -lt | Numerically less than. To avoid confusion with the uppercase letter -l, use -L |
4. Tests for various file attributes:
| -d | Is a directory. |
| -f | Is a regular file. |
| -F | File exists. |
| -l | Is a symbolic link. |
| -L | Is a symbolic link. Equivalent to the -l flag. |
| -s | Is a regular file with non-zero size |
| -U | Specified URL exists |
| -x | File is executable. |
5. All these checks can also be preceded by an exclamation mark ('!') prefix to invert their value.
Variables
Example:
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
| HTTP_USER_AGENT | Contains information about the type and version of the visitor's browser and operating system. |
| HTTP_REFERER | Specifies the address of the page from which the visitor arrived at the current page. |
| HTTP_COOKIE | List of cookies sent by the browser. |
| HTTP_FORWARDED | The page from which the user directly navigated. |
| HTTP_HOST | Server address, for example host.com. |
| HTTP_ACCEPT | Describes the client's preferences regarding document type. |
| REMOTE_ADDR | Visitor's IP address. |
| REMOTE_HOST | Visitor's address in standard form, for example, rt99.net.com. |
| REMOTE_IDENT | Remote user name. Has the format name.host, for example, kondr.www.rtt99.net.com. |
| REMOTE_USER | Same as REMOTE_IDENT, but contains only the name. Example: kondr. |
| REQUEST_METHOD | Allows determining the type of request (GET or POST). It must be analyzed, as it determines the subsequent method of processing information. |
| SCRIPT_FILENAME | Full path to the web page on the server. |
| PATH_INFO | Contains everything that was passed to the script. |
| QUERY_STRING | Contains the string passed as a query when invoking a CGI script. |
| AUTH_TYPE | Used for user identification. |
| DOCUMENT_ROOT | Contains the path to the server's root directory. |
| SERVER_ADMIN | Email address of the server owner, specified during installation. |
| SERVER_NAME | Server address, such as kondr.host.com. |
| SERVER_ADDR | IP address of your site. |
| SERVER_PORT | Port on which Apache is running. |
| SERVER_PROTOCOL | HTTP protocol version. |
| SERVER_SOFTWARE | Server name, for example, Apache/1.3.2 (Unix). |
| TIME_YEAR TIME_MON TIME_DAY TIME_HOUR TIME_MIN TIME_SEC TIME_WDAY TIME | Variables designed for working with time in different formats. |
| API_VERSION | This is the version of the Apache module API (internal interface between the server and the module) in the current server build, as defined in include/ap_mmn.h. |
| THE_REQUEST | The full HTTP request string sent by the browser to the server (i.e., "GET /index.html HTTP/1.1"). It does not include any additional headers sent by the browser. |
| REQUEST_URI | The resource requested in the HTTP request line. |
| REQUEST_FILENAME | Full path in the server's file system to the file or script corresponding to this request. |
| IS_SUBREQ | Will contain the text "true" if the request is currently being executed as a subrequest, "false" otherwise. Subrequests can be generated by modules that need to handle additional files or URIs to perform their own tasks. |
Rule Execution Logic (RewriteRule)
Executing a rule involves the following steps: first, the rewriting engine searches for additional conditions for this rule (RewriteCond directives). Keep in mind that, for historical reasons, additional conditions are placed before the rules (RewriteRule). If there are no additional conditions for this rule, the rewriting engine simply performs the transformation specified in the rule on the current URL and proceeds to the next rule. However, if there are additional conditions specified BEFORE the executing rule (RewriteRule) in RewriteCond directives, an internal loop is initiated to process these additional conditions in the order they are listed, from top to bottom.
If at least one of the additional conditions for the rule is NOT met, this stops the initiated rule execution process, and the URL transformation specified in the rule is NOT performed. For the initiated rule to execute completely and modify the URL, ALL additional conditions specified in the RewriteCond directives before this rule must be met!
It is important to clarify here that RewriteCond directives are combined with the AND operator into a single compound condition by default. This operator (AND) is simply not written by default. This is why the logic dictates that all additional conditions must be true (since they are combined via AND) for the URL transformation to complete successfully. However, RewriteCond directives can be combined using the OR condition with flags (see the directive syntax). This should be kept in mind when setting additional conditions.
Syntax of the RewriteRule directive:
RewriteRule Шаблон Подстановка [Флаги]
Example:
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
Where:
1. RewriteRule is the name of the rule directive.
2. Pattern is the condition whose fulfillment triggers the execution of the rule. This condition - Pattern - is a Perl-compatible regular expression applied to the current URL.
3. Substitution is the algorithm for changing the URL, i.e., the rule for changing (transforming) the URL.
4. [Flags] of substitution - The third argument of the RewriteRule directive. Flags are uppercase special characters separated by commas, enclosed in square brackets. Flags supplement the URL transformation.
Parameters in the rule are written on a single line starting with the directive name and separated from each other by a space.
Now let's analyze an example of a RewriteRule:
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
1. ^(.*)$ is a Pattern, a regular expression that will be applied to the current URL. Those familiar with regular expressions can read it as: search the current URL string from the beginning of the string (caret ^) to the end of the string (dollar sign $) for any character (dot .) occurring zero or more times (asterisk *). Since this regex contains parentheses (), the part of the URL that matches the condition inside the parentheses will be captured into the substitution variable $1, which we can later use in Substitution or in MatchedString (this is in the RewriteCond directive, discussed below).
2. index.php?/$1 is the Substitution – this is essentially the URL rewriting rule. The entry index.php?/$1 means that the new, transformed URL string should be composed of two parts, where the first part is the constant value index.php?/ and the second part is the value from the substitution variable $1. Here we recall that $1 stores the part of the URL that matched the regex in parentheses from the Pattern parameter. As a result, we get a transformed URL in the form index.php?/URL_that_was_requested. In other words, for all requests, an internal redirect to the index.php file is performed.
3. [L,QSA] are flags, where 'last|L' means the last rule, indicating to stop the rewriting process at this point and not apply any further rewriting rules to the URL. 'qsappend|QSA' means append query string – this flag instructs the rewriting mechanism to append, rather than replace, the query string from the URL to the existing one in the Substitution string. Use this when you want to add additional data to the query string using rewriting directives.
Cheat Sheets
mod_rewrite Cheat Sheet
The mod_rewrite cheat sheet contains a list of flags for the RewriteRule and RewriteCond directives, a list of server variables, a regular expression guide, and several examples of common rules.
- Download in PDF ~79 KB
- Download in PNG ~79 KB
Regular Expressions Cheat Sheet
The cheat sheet is a general guide to regular expression patterns without regard to the specifics of any particular language.
- Download in PDF ~96 KB
- Download in PNG ~81 KB
Conclusion
Remember to escape special characters in regular expressions. Sometimes people forget to escape the dot when it should represent an actual dot, rather than its usual meaning in regular expressions – any character.
Also, remember to wrap the entire block of rules for mod_rewrite in the tag: <IfModule mod_rewrite.c></IfModule>
Avoid writing excessive directives for mod_rewrite; only include the rewrite rules that you truly need. Be especially careful with external redirects. These are redirects that are executed by sending the client a server header with a status code other than 200 (which indicates a full page response), typically 301 or 302, causing the client's browser to redirect to a different URL, thereby initiating a new request from the client.
Therefore, any external redirect always results in additional time spent processing the request, as the server must send a response, the client must read it, and then repeat the request using the new URL. This is a time-consuming process. Consequently, redirects should only be used when they are genuinely necessary.
