htaccess rewrite query string vs back reference? - .htaccess

I'm trying to rewrite this:
http://www.domain.com/johns-wishlist-12
to this:
index.php?route=wishlist/shared_wishlist&id=12&name=johns
I've read some good tutorials, but none of them really explain how back references work (when using more than one)... I also don't understand when to use {QUERY_STRING}, as opposed to just back references?
Could use a little help... this is what I have for the above:
RewriteRule ^([a-z0-9]*)-wishlist-([0-9]*)/?$ index.php?route=wishlist/shared_wishlist&id=$1&name=$2 [L,QSA]
Obviously "johns" and "12" will change based on the user...
so should I be using a rewrite condition {QUERY_STRING} in this case? why?

The %{QUERY_STRING} variable is used to match against the request's query string. In your case, the request is for http://www.example.com/johns-wishlist-12, so there is no query string there. You are rewriting to a URI with a query string, though, so the only thing that matters is the next time around when the rules loop (which may not happen), if you had another rule that matched against the %{QUERY_STRING} variable, the query string that you created will show up there.
The $ something in your rule's target are backreferences to a "grouped" match in the rule's pattern. Whenever you have a () in your pattern, that groups the match which can then be backreferenced using a $. In the case of a condition, the backreferences are % instead.

Related

How to efficiently match a .htaccess RewriteRule for a complete word only if it's the last part of the URL

I'm unsure how to word this request, so please bear with me as I explain with an example. I'll try to make it clear.
I wish to redirect a URL if it ends with one of two words, let's say foo or bar. It must match only as a complete word, so food or new-foo shouldn't match. The URL might end with a slash, so /foo and /foo/ are both valid.
Also, the word might be by itself at the beginning of the URL or at the end of a longer path.
Thus, any of the following should match, with or without a trailing slash:
https://example.com/foo
https://example.com/new/foo
https://example.com/bar
https://example.com/some/other/bar
But, none of the following should match (with or without a trailing slash):
https://example.com/foo-new
https://example.com/old-bar
https://example.com/bar/thud
https://example.com/plugh/foo/xyzzy
Clarification: It's OK if the word is repeated, e.g. the following should still redirect, because foo is at the end of the URL:
https://example.com/foo/new/foo
The best that I've managed to come up with is to use two redirects, the first checking for the word on its own, and the second checking for the word being the last part of a path:
RewriteRule ^(foo|bar)/?$ https://redirect.com/$1/ [last,redirect=permanent]
RewriteRule /(foo|bar)/?$ https://redirect.com/$1/ [last,redirect=permanent]
There will, eventually, be several words, not just the two…
RewriteRule ^(foo|bar|baz|qux|quux|corge|grault|garply)/?$ https://redirect.com/$1/ [last,redirect=permanent]
RewriteRule /(foo|bar|baz|qux|quux|corge|grault|garply)/?$ https://redirect.com/$1/ [last,redirect=permanent]
… so using two RewriteRule statements seems error-prone and possibly inefficient. Is there a way to combine the two RewriteRule statements into one? Or, maybe, you have a better idea? (I toyed with FilesMatch, but I was confused as to how to go about it.)
Thank you
This probably is what you are looking for:
RewriteEngine on
RewriteRule (?:^|/)(foo|bar)/?$ https://example.com/$1/ [L,R=301]
(?:^|/) is a "non capturing group", so $1 still refers to what is captured by (foo|bar), while the whole expression matches a requested URL with only those words or with those words as final folder in a path sequence.

htaccess RewriteRule - pattern not matching

I'm trying to use categories in a clean way in my urls like this:
website.com/category
In the url the categories are written like this: Some random examples:
Animals
Consumer-Electronics
Books-&-Comics
External-Hard-Discs
Form,-Beauty-&-Health
Black-&-White-TV
The-Adventures-Of-Tintin
Fryers,-Waffle-makers-&-Cooking
etc...
As you can see, there is a random combination of words (with starting upper case), characters "-", ",", and "&". There are more combinations than the examples.
With rewrite I'm trying to get the categories in a variable like this:
RewriteRule ^([\w-&]+)$ /categories.php?mcn=$1 [L,NC]
This is not working. If I read out the variable I wanted with "Books-&-Comics" in categories.php, I only get "Books-" while it should be "Books-&-Comics".
When I add a "," in the character class like this:
RewriteRule ^([\w,-&]+)$ /categories.php?mcn=$1 [L,NC]
I get an internal server error.
How should my RewriteRule look like to match the category examples and get them correctly in the variable?
For your first problem, the issue is that your parameters are being decoded and thus the & is starting a new URL parameter. You can fix this by adding a B flag to your rule.
Your second issue is that the pattern ^([\w,-&]+)$ is invalid. It is trying to match any word character, or any character between , and &. (Ascii 44 & 38) because this is out of order, the regex fails. As you want to match the - character rather than using it as a range indicator, it should be escaped.
With these changes made your rule is:
RewriteRule ^([\w,\-&]+)$ /categories.php?mcn=$1 [L,NC,B]
A regex helper like regex101 can be a huge help in creating your rules.

RewriteRule doesn't match a certain URL

RewriteRule ^(.*)/([^\/]+)/([a-z0-9\-\_]*)/?(company|person)/?$ $1/$2/index\.php\?misc=$3&$4
This doesn't match http://example.com/zufang/zjqj_2-/person/.
What RewriteRule can I use to match both example.com/zufang/zjqj_2-/person/ and xxx.com/zufang/person/?
Your rule appears to be trying to match the example.com part. The domain is not matched in a RewriteRule, however. Also, since the entire second section is optional note that you may have a problem with your resulting misc=$3&$4 since that would be misc=&person when the second section isn't present. Here's an updated rule with some other minor cleanup:
RewriteRule ^([^\/]+)/([a-z0-9\-\_]*)?/?(company|person)/?$ /$1/index.php?misc=$2&$3
One additional item I'm not 100% sure about, I don't think characters have to be escaped within character match blocks. If that's the case, the following would be slightly cleaner:
RewriteRule ^([^/]+)/([a-z0-9-_]*)?/?(company|person)/?$ /$1/index.php?misc=$2&$3

htaccess - mod_rewrite "same" rules have to work for both

I really had troubles making a title. So if you have something better, please edit it.
Now to the question:
I'm trying to rewrite some URL's with mod_rewrite in my .htaccess file.
So, what I'm trying to do is to make 2 of the same queries, which of course won't work. Only for one of the rules. So I was thinking if there's some way to tell that if the first rule fails go to the next one? Or - if a rule fails keep looking for another?
Those are my rules which is identical except for the last parameter.
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&val=$2
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&p=$2
Correct me if I'm wrong but, if you are passing the arguments in via GET, then index.php should handle the error that would happen if it were missing a GET variable.
In index.php, treat $_GET["p"] like you would treat $_GET["val"], actually, why not use isset() and set p equal to val (if p isn't already set)
The rewrite won't check to see if the page you are calling in your rule is actually valid. It will just try to serve it up and then because you don't have [L] it will try to serve up the next one too.
What you should probably do is change your first URL to pass that $2 value as two different parameters
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&val=$2
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&p=$2
should be
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&val=$2&p=$2
Then let your index.php do the work of picking which parm to use "val" or "p" based on logic in the php script.
For sure in your php code use "isset" to test for the variable.
$value = (isset($_REQUEST["val"]) ? $_REQUEST["val"] : (isset($_REQUEST["p"]) ? $_REQUEST["p"] : "error"));
$value will hold the contents of "val" or "p" or the word "error" if neither of the others are set.

Trying to redirect using .htaccess any url that has index2 in it regardless of what comes after

I've got legacy URLs like:
mysite.com/index2.php?option=com_mtree&task=print&link_id=383&Itemid=168
and I'd like to redirect any URL that has index2.php in it (regardless of what comes after index2.php) to mysite.com/my-nice-url
I've tried
RewriteRule ^index2(.+) /my-nice-url/and-more/ [l,r=301]
But that makes /my-nice-url/and-more/?option=com_mtree&task=print&link_id=383&Itemid=168 which i don't want. Could anyone provide a bit of guidance please?
1) Rewrite rule pattern can only mathc path part of URL -- query string has to be matched separately (via RewriteCond)
2) By default, query string is passed to new URL if new URL does not has its' own query string. Solution -- provide empty query string (by adding ? at the end of URL):
RewriteRule ^index2\.php$ /my-nice-url/and-more/? [L,R=301]
This should work, even if it's not exactly what you want:
RewriteRule ^/index2(.+)$ /my-nice-url/and-more/?
From the rewriterule Apache docs:
Note: Query String
The Pattern will not be matched against the query string. Instead, you
must use a RewriteCond with the %{QUERY_STRING} variable. You can,
however, create URLs in the substitution string, containing a query
string part. Simply use a question mark inside the substitution
string, to indicate that the following text should be re-injected into
the query string. When you want to erase an existing query string, end
the substitution string with just a question mark. To combine a new
query string with an old one, use the [QSA] flag.

Resources