Two RewriteRules interfering, only one works at a time - .htaccess

On htaccess file with two RewriteRules, each works alone, but not both together
RewriteRule ^([1-9]+)/.*/(.*) /sortir/index.php?com=page1&t=$1&l=$2 [QSA]
RewriteRule ^([1-9]+)/([1-9]+)/.* /sortir/index.php?com=page2&t=$1&v=$2 [QSA]
If I delete first, second works.
If I delete second, first works.
The link called for the first is like :
http://example.com/33/xxxx/city so $1 is 33 and $2 is city
The link called for the second is like :
http://example.com/33/432/xxxx/city/yyyyy so $1 is 33 and $2 is 432

Although, as anubhava notes, more details would be helpful, there are at least a few issues I can point out with your current rules.
First, reverse the order of the rules. The second rule is less general since it starts with two sections of numbers and additional sections of text. Match that first, then match the more general rule.
Second, end each rule with the L flag, otherwise processing will continue to the second rule after the first is finished.
Third, update your matches so that they don't match a slash. This forces the pattern to match the exact directory structure you're looking for rather than matching any arbitrary number of directory levels.
With those things in mind, here are some updated rules to play with:
First rule matches http://example.com/33/432/xxxx/city/yyyy
Second rule matches http://example.com/33/xxxx/city
RewriteRule ^([1-9]+)/([1-9]+)/[^/]+/[^/]+/.* /sortir/index.php?com=page2&t=$1&v=$2 [QSA, L]
RewriteRule ^([1-9]+)/[^/]*/([^/]*)$ /sortir/index.php?com=page1&t=$1&l=$2 [QSA, L]
If this is not the exact rule set you need, it should at least get you closer.

Both conditions are overlapping since this regex:
^([1-9]+)/.*/(.*)
will also match
^([1-9]+)/.*/(.*)
hence only one will fire. Why don't you explain your requirements clearly then we can help you write RewriteRule in unambiguous manner.

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 rewrite query string vs back reference?

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.

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.

Make an optional Get variable with this htaccess

I have this rule in my .htaccess:
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3
Which works great for this url:
http://somesite.com/po_systems/build_system/60/495C31/1
But now I need an optional 4th Get variable to this rule that will give me the $_GET variable step like this:
http://somesite.com/po_systems/build_system/60/495C31/1/2
$_GET['step'] // 2
But I also need the rule to work if there is no 4th Get variable. So basically I need both 3 and 4 Get variables to work, making the 4th optional.
I would write it with two separate rules:
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3&step=$4 [S=1]
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3
If there are 4 path components, the first rule will match, and skip the next rule ([S=1]). Otherwise the next rule will try to match.
#Ulrich Palha's solution probably also works, but the regular expression is getting complicated. It will pass an empty step= parameter if there's no 4th path component, which may be fine. My solution will pass no step parameter if there's no 4th path component. Either way should work.
try
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/?([^/]*)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3&step=$4

Resources