.htaccess: how to make a digit parameter optional? - .htaccess

In my example, this URL works with these parameters:
www.website.com/search/dogs-10-cats-5
what I want is to have one of the parameters (a digit or empty) to be optional like:
www.website.com/search/dogs--cats-3
Is this possible? Here is my current rewrite rule:
RewriteRule ^search/dogs-?([0-9]+)-cats-?([0-9]+)/? index.php?SearchResults&Dogs=$1&Cats=$2 [L]

dogs-?([0-9]*)-cats-?([0-9]+)
instead of
dogs-?([0-9]+)-cats-?([0-9]+)
+ means "one or more", * means "zero or more"
I would also recommend to omit the ?s, because this makes every second dash optional (may be intended, but I guess not)
dogs10-cats5

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.

mod_rewrite RewriteRule backreference use in pattern

Is it possible to use a backreference in the middle of the RewriteRule pattern?
I envision this as such:
RewriteRule ^(.)([a-z]*)$1([a-z]*) $2-$3
^
(note, this fellow, here, refers to that first "(.)")
If the received url is XboopXdoop, the result would of course be boop-doop.
I am attempting to use this to specify a delimiter at the beginning of the incoming url that can be used to parse the rest of the string, without forcing the use of a specific character as that delimiter.
Thank you.
$1 works on the right side (rewrite), but not in the regex. You need to use \1.
Try:
RewriteRule ^(.)([a-z]+)\1([a-z]+) $2-$3
I ran into a bizarre edge case with the * where it split based on the second character of the string, and not the second. XtestingXtest resulted in es-ing ... so yeah, not sure what was happening there. If I use a + it works fine.
Also, since * and + are greedy, if you have multiple delimiter characters, it will split on the last occurrence of the character:
XbaseXtest -> base-test
XbaseXteXst -> baseXte-st
XbaseXtestX -> baseXtest-

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.

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