Variable in htaccess, RewriteRule question - .htaccess

How could i use a RewriteRule accesing a variable?
If i have:
SetEnv MY_VAR (a|b|c)
RewriteRule ^%{ENV:MY_VAR}$ index.php?s=$1 [L,QSA]
RewriteRule ^%{ENV:MY_VAR}-some-one$ index.php?s=$1 [L,QSA]
I have these examples but doesn`t work.
Later edit
Ok Tim, thank you for the answer. Let say that i have:
RewriteRule ^(skoda|bmw|mercedes)-([0-9]+)-([0-9]+)-some-think$ index.php?a=$1 [L,QSA]
RewriteRule ^some-one-(skoda|bmw|mercedes)/pag-([0-9]+)$ index.php?a=$1 [L,QSA]
RewriteRule ^a-z-(skoda|bmw|mercedes)$ index.php?a=$1 [L,QSA]
(forget second part of RewriteRule) .. I don-t want to put everywhere (skoda|bmw|mercedes) this list. Is more quickly to make a variable then to use it in rule...

You can't do that, because mod_rewrite doesn't expand variables in the regular expression clauses.
You can only use variables in the input argument to a RewriteCond, and as the result argument to a RewriteRule. There's overhead in compiling the regular expressions (especially if you're forced to do it per-request as with .htaccess files), so if you allowed variable content in them, they'd have to be recompiled for every comparison to ensure accuracy at the cost of performance. It seems the solution therefore was to not let you do that.
What exactly did you want to do that for, anyway?

I`ve received another answer on a mod_rewrite forum from jdMorgan:
Mod_rewrite cannot use a variable in a regex pattern. The .htaccess directives are not a scripting language...
I'd recommend:
RewriteCond $1<>$3 ^<>-([0-9]+)-([0-9]+)-some-think$ [OR]
RewriteCond $1<>$3 ^some-one-<>/pag-([0-9]+)$ [OR]
RewriteCond $1<>$3 ^a-z+-<>$
RewriteRule ^([^\-/]+[\-/])*(skoda|bmw|mercedes)([\-/].+)?$ index.php?a=$2 [QSA,L]
Here, the RewriteRule pattern is evaluated first (See Apache mod_rewrite documentation "Rule Processing").
If the pattern matches, then whatever comes before "(skoda|bmw|mercedes)" in the requested URL-path is placed into local variable "$1".
Whatever follows "(skoda|bmw|mercedes)" is placed into local variable $3.
The value of the requested URL-path matching "(skoda|bmw|mercedes)" is placed into $2.
Then each of the RewriteConds is processed to check that the format of the requested URL without the "(skoda|bmw|mercedes)" part is one of the formats to be accepted.
Note that the "<>" characters are used only as a separator to assist correct and unambiguous parsing, and have no special meaning as used here. They simply "take the place of" the variable-string that you do not want to include in each line. You can use any character or characters that you are sure will never appear in one of your URLs without first being URL-encoded. I prefer to use any of > or < or ~ myself.
Note also that the RewriteRule assumes that the "(skoda|bmw|mercedes)" substring will always be delimited by either a hyphen or a slash if any other substring precedes or follows it. I am referring to the two RewriteRule sub-patterns containing "[^-/]" ("NOT a hyphen or a slash") and "[-/]" ("Match a hyphen or a slash"). This greatly improves efficiency of regular-expressions pattern matching, so use this method if possible instead of using an ambiguous and inefficient sub-pattern like ".*" (Match anything, everything, or nothing").

Related

.htaccess 301 redirect from old RewriteRule to new

I have a problem with making a 301 redirection. I was using "flat" link system on website with RewriteRule:
domain.com/rubric-news
domain.com/article-815/news-title
RewriteRule ^rubric-([^*]*) news.php?kat=$1
RewriteRule ^article-([^*]*)/([^*]*)-([^*]*) article.php?id=$1&kat=$2&title=$3
Today I started to build better internal links system for SEO so now RewriteRules looks like this:
domain.com/news
domain.com/news/title-815
RewriteRule ^([a-z0-9]+)$ news.php?kat=$1 [L]
RewriteRule ^([^*]*)/([^*]*)-([^*]*) article.php?id=$3&kat=$1&title=$2 [L,NC,QSA]
now I should make 301 redirection from old links to the new ones and I don't know how to make it. Can anyone help me?))
The redirect directives would follow exactly the same principles as you have already used for the rewrites. (Although there are potential issues with the rewrites/regex you are currently using - see below).
Try it like this before your existing rewrites:
# Redirect "/rubric-<news>" to "/<news>"
RewriteRule ^rubric-([a-z0-9]+)$ /$1 [R=301,L]
# Redirect "/article-<815>/<news>-<title>" to "/<news>/<title>-<815>"
RewriteRule ^article-(\d+)/(\w+)-(\w+)$ /$2/$3-$1 [R=301,L]
I have assumed your "id" parameter is all numeric (as per your example). (Although your existing directives do not enforce this.)
Any query string will be be passed through by default (you do not need the QSA flag here).
You should test first with 302 (temporary) redirects to avoid potential caching issues. Clear your browser cache before testing.
Aside:
RewriteRule ^([^*]*)/([^*]*)-([^*]*) article.php?id=$3&kat=$1&title=$2 [L,NC,QSA]
The regex [^*]* matches anything that is not an asterisk (*) 0 or more times. You should be matching anything that is not a slash 1 or more times, ie. [^/]+. And you are missing the end-of-string anchor on the end of the regex (as you have on the preceding rule). With the very generic regex you are currently using (ie. [^*]*) this does not strictly matter, however, it is potentially ambiguous, ...
Your regex should be more restrictive (similar to the preceding rule). If your id consists of digits only then match only digits. If the title is only alphanumeric then match only letters and numbers, not everything. Currentrly it "looks like" the news and title parameters could contain hyphens, but that would introduce an ambiguity.
The NC flag is naturally superfluous here.
Consider something like this instead:
RewriteRule ^(\w+)/(\w+)-(\d+)$ article.php?id=$3&kat=$1&title=$2 [L,NC,QSA]
If your title can contain hyphens then change the regex accordingly. eg. ^(\w+)/([\w-]+)-(\d+)$

Htaccess - Redirect if URL does not contain at least three numbers

I'm struggling to get this htaccess redirect to work. I want to redirect any URL that does not contain at least three numbers in a row. I started with the following and it worked perfectly for redirecting any URL that DID have three numbers in a row:
RewriteCond %{REQUEST_URI} [0-9]{3,20} [NC]
RewriteRule (.*) "https\:\/\/info\.mywebsite\.com\/" [R=301,L]
However, I tried to modify that with the exclamation mark to make the condition NOT match three numbers in a row:
RewriteCond %{REQUEST_URI} !([0-9]{3,20}) [NC]
RewriteRule (.*) "https\:\/\/info\.mywebsite\.com\/" [R=301,L]
But that doesn't seem to work as expected. Am I missing something with turning this expression into a not match?
Having previously experimented with the opposite 301 (permanent) redirect then the results are most probably cached (by the browser) from the earlier redirect. It is a good idea to test with 302 (temporary) redirects to avoid caching issues.
Note also that the REQUEST_URI server variable contains the URL-path only, so if the digits are contained in the query string part of the URL-path then your condition will fail.
The quantifier {3,20} matches from 3 to 20 characters, if you want "at least three" then use the quantifier {3,} (no upper bound).
You don't need the capturing subpatterns, ie. surrounding parentheses (...) on the regex since you are not using backreferences anywhere. Incidentally, you can't capture subpattern on a negated regex.
You don't need the additional condition (RewriteCond directive) - this can all be done with the RewriteRule directive only.
The NC flag is not required here - you are checking digits only.
For example:
RewriteRule !\d{3,} https://info.mywebsite.com/" [R=302,L]
As noted in comments, the RewriteRule substitution string is a regular string, not a regex, so does not require any special backslash escaping (although colons and slashes don't need escaping anyway in Apache regex).

URL mod-rewriting

I want to mod_rewrite this Url:
Before:
website.altervista.org/page.php?name=value
After:
website.altervista.org/value
Solution:
RewriteCond %{REQUEST_URI} !page.php$
RewriteRule ^(.+)$ /page.php?name=$1 [L]
Explanation:
The mod_rewrite RewriteRule has 3 parameters:
Pattern
Substitution
Flags
Implemented as such:
RewriteRule pattern substitution [flags]
Starting at server root, enter the requested URL path in the RewriteRule "pattern" parameter, and the desired path in the "substitution" parameter. In this case:
RewriteRule ^(.+)$ /page.php?name=$1 [L]
If the URL varies and you don't want to (or can't) write a rule for every situation then use the regular expression ^(.+)$ to capture the dynamic value and inject it into your substituted path using the RE capture variable $1. The first set of parenthesis is $1, the second set is $2, etc. And capturing parenthesis can be nested.
^(.+)$ This regular expression can be read as: ^ at the start of the string, $ all the way to the end of the string, look for . any character + one or times and () capture that value into a variable.
Problem:
Even though we have the flag [L] (last rule evaluated), the mod_rewrite engine (behind the scenes) sends the newly constructed request /page.php?name=somevalue back through the mod_rewrite engine until no rules are met or, apparently, there are no changes to the request. Fortunately there is a supplimentary directive to expand on the conditional power provided by the RewriteRule called RewriteCond.
The mod_rewrite RewriteCond applies to the next occurring RewriteRule and also has 3 parameters:
Test String
Conditional Pattern
Flags (optional)
The Test String can be derived from a few sources. Often a Server Variable, relating to the current request, is used here as the subject of this condition.
The Conditional Pattern is, again, text or a regular expression, but has some additional special conditions that may be evaluated. Read the Apache online mod_rewrite documentation for a detailed explanation.
In this case: RewriteRule ^(.+)$ /page.php?name=$1 [L], our newly substituted request is sent back through mod_rewrite as /page.php?name=somevalue and matches our "catch-all" rule, therefore our original "somevalue" is lost and replaced with our newly requested resource page.php. To prevent our "catch all" from catching our "page.php" requests let's exclude it from the rule using RewriteCond.
RewriteCond %{REQUEST_URI} !page.php$
RewriteRule ^(.+)$ /page.php?name=$1 [L]
This RewriteCond can be read as: %{REQUEST_URI} get the requested resource and does it ! NOT $ end with page.php. If this condition is true, continue to the next condition or rule. If this condition is not true, skip this rule set and continue to the next rule set.

RewriteRule - only two directories and a file

I am trying to rewrite URLs through .htaccess and what I want is that a rule be taken into account only if the URL is like "www.mysite.com/basedir/directory/file.htm".
I don't want "www.mysite.com/basedir/file.htm" or "www.mysite.com/basedir/directory/directory/file.htm", I want the exact described structure. At the moment I am trying to do it with this:
RewriteRule ^(basedir)/([^/\.]+)/(.*)\.(htm)$ /template.php?&page=$3 [L]
but it doesn't work. It accepts any number of directories after basedir.
Thanks for your help
Your second match area needs to have a character exclusion like the first:
RewriteRule ^(basedir)/([^/\.]+)/([^/]*)\.(htm)$ /template.php?&page=$3 [L]
That way you don't allow additional slashes to be matched, only the two explicit slashes earlier in the pattern.
Also, what exactly are you trying to match with $3? You only need to use parentheses around things that you need to match. If $3 is supposed to match file.htm, then you could instead write:
RewriteRule ^basedir/[^/\.]+/([^/]*\.htm)$ /template.php?&page=$1 [L]
or if it should just match "file" then:
RewriteRule ^basedir/[^/\.]+/([^/]*)\.htm$ /template.php?&page=$1 [L]

mod_rewrite - check for string

I want to check if a URL contains the sting "-EN.htm", if so apply the rewrite.
That should be done with ^-EN.htm as follows, but the rule is not working:
RewriteCond %{REQUEST_URI} ^/(.*?)/([-_0-9a-zA-Z./=]*)^-EN.htm
RewriteRule ^(.*)$ /indexEN.php?folder=%1&follow=%2 [L]
What am I doing wrong?
Thank you for every help,
Scott
Your regular expression doesn't look right. You can also lose the condition and just move the pattern to the rewrite rule instead. Something along the lines of
RewriteRule ^/?(.*?)/([-_0-9a-zA-Z./=]*)^-EN.htm /indexEN.php?folder=$1&follow=$2 [L]
You need to make the leading slash optional (in htaccess this is stripped off) and instead of using % backreferences, use the $ ones.
Now on to your pattern, it's not valid. The ^ matches the beginning of the string (the URI), so if you have two of them and you're not trying to literally match the ^ character (which you'd need to escape), then the expression will never match anything. Without any examples of URLs that you're having to deal with, I assume you probably just want to ditch the second ^:
RewriteRule ^/?(.*?)/([-_0-9a-zA-Z./=]*)-EN.htm /indexEN.php?folder=$1&follow=$2 [L]

Resources