3

I have just copy and pasted a rewrite rule for a redirect from some website. It contains:

^(.*)

I want to know what it means. Why is it so complicated? Can it be simplified?

The whole .htaccess file currently contains:

# turn on the rewrite engine
RewriteEngine On

# unconditional redirect to the new web
RewriteRule ^(.*) https://www.example.com [R=301,L]
1
  • 2
    Apache's mod_rewrite module uses regex (regular expressions) common to Perl. You can find the character meaning in Apache's documentation here. This expression is a catch-all, permanently redirecting every request to https://www.example.com.
    – dan
    Apr 30, 2019 at 7:22

2 Answers 2

6

As @dan mentioned in comments, this is a regular expression ("regex" for short and often referred to as a "pattern" in Apache docs). Specifically, Apache uses the PCRE (Perl Compatible Regular Expressions) flavour of regex.

The first argument to the RewriteRule directive is a regex that matches against the URL-path component of the requested URL. In .htaccess this URL-path does not include the slash prefix. So, given a URL of the form https://example.com/foo/bar.html, the URL-path that this regex matches against is foo/bar.html.

^(.*)

This regex matches everything. The ^ at the start of the regex is a start-of-string anchor (it matches from the start of the URL-path). It also captures ((.*)) the entire URL-path in a backreference (so it can be used later).

As regex go, this is relatively simple. However, as per your question, this can be "simplified". In this particular regex, the ^ anchor is superfluous since the .* part is greedy and consumes the entire string by default. There is also no need for the capturing backreference (the parentheses surrounding (.*)), since this is not being used later in the substitution (2nd argument) part of the directive.

So, this regex can be immediately simplified to:

.*

However, since the goal of this regex is to simply process every URL, it doesn't need to explicitly match anything. It just needs to be successful. So, it can be further optimised. Instead of explicitly matching everything, as it does with .* (the regex parser traversing the entire URL-path) you can use an alternative regex, such as:

  • ^ - A single start-of-string anchor is successful for everything (since the assertion is always successful), but it doesn't actually "match" anything (so is more efficient). You could also use the end-of-string anchor instead, ie. $ - however, it is less common to see this used in this way.

  • .? - This matches an optional single character. The . matches any character (except newline) and the trailing ? makes the preceding pattern optional. In a per-directory context (such as .htaccess), this single character needs to be optional, because the URL-path could be empty (in the case of the document root). (In a server context, you would remove the ? to leave a single dot, since in a server context there is always at least one character in the URL-path; the slash prefix.)

Whichever you use is really a matter of preference.

Aside: In your example, you should ideally include a trailing slash on the target URL. Something has to. If you omit it then you are relying on the browser appending (fixing) the trailing slash to the hostname (which it will do) before issuing the redirected request.

So, in summary:

RewriteRule ^ https://www.example.com/ [R=301,L]

Regex are incredibly powerful. But, naturally, with that "power" comes additional complexity.

Further reading:

1
  • 2
    As I was writing my comment, I was thinking that I could explain the meaning of each character and try to simplify it further, but a comment with links is limited in length...and I had full confidence that @MrWhite, the master of all things regex, would surely come along and do that to a tee :-) Nice job as always.
    – dan
    Apr 30, 2019 at 22:12
2

Another simpler method is to use redirects from mod_alias. A similar redirect directive from mod_alias is just one line. It doesn't require turning rewrite engine on. The syntax is pretty clear:

Redirect permanent / https://www.example.com/

That means redirect the root of the website and all sub-URLs to the other website. Any additional path is automatically appended to the redirect URL.

Your mod_rewrite rule redirects everything to the home page of the new site. That is not usually what you want. You usually want to preserve the URL path for usability and SEO. To get that behavior from mod_rewrite you would need to change the rule to:

RewriteRule ^(.*) https://www.example.com/$1 [R=301,L]

In that case the parenthesis around the .* "capture" the path and put it into the $1 variable which is used as part of the redirect. It looks to me like your redirect rule is over-complicated because somebody removed the path variable without also simplifying the regular expression.

1
  • "...preserve the URL path." - Yes, it didn't strike me until after I'd written my answer that the substitution string might even be "wrong".
    – MrWhite
    Apr 30, 2019 at 14:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.