htaccess redirect for unordered links - .htaccess

I have an URL:
mysite.com/a/b,c,d,e,f
And the condition that works correctly:
RewriteRule ^a/b,c,d,e,f/([0-9]+)(/?)$ /f/cat=a,b,c,d,e,f [L]
RewriteRule ^a/b,c,d,e,f(/?)+$ /f/cat=a,b,c,d,e,f [L]
Is there a rule that will work even if there is a link like
mysite.com/a/c,b,e,f,d -> /f/cat=a,b,c,d,e,f
mysite.com/a/e,f,d,b,c -> /f/cat=a,b,c,d,e,f
...

This is only feasible if the parts in question are distinguishable, i.e. you can tell the URL query string element a from not a and b from not b, etc.
To get the idea (demo):
(a)/(?=.*(b))(?=.*(c))(?=.*(d))(?=.*(e))(?=.*(f)).,.,.,.,.(/?)
If there is overlap, e.g. the parts are actually just a bunch of numbers, this will not fly.

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.

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

Two RewriteRules interfering, only one works at a time

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.

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