3

I am trying to use Apache rewrite to turn something like

https://www.example.com/sub/?v1=123&v2=456

into

https://www.example.com/sub/?v1=789&v2=456

i.e. changing v1 to a specific value and keeping v2. In the real case, there are more parameters.

I have

RewriteCond %{QUERY_STRING} (^|&)v1=123&v2=(\d+).*$
RewriteRule ^sub/$ sub/?v1=789&v2=%1 [NE]

which does everything except keep v2. It gets:

 https://www.example.com/sub/?v1=789&v2=

It seems like the %1 substitution did not find anything to substitute. But I can't see why not?

And I did try removing the [NE] flag, but that just causes the '&' to be lost, and does not keep the value either.

I tried this at https://htaccess.madewithlove.be/ and on our staging site, and its consistent that the substitution is not happening.

John Conde
  • 86,484
  • 28
  • 150
  • 244
Fred Andrews
  • 133
  • 3

2 Answers2

3
RewriteCond %{QUERY_STRING} (^|&)v1=123&v2=(\d+).*$
RewriteRule ^sub/$ sub/?v1=789&v2=%1 [NE]

You are using the wrong backreference in the substitution string. You have 2 capturing subgroups in the preceding condition, so you would need to use %2, not %1 as you have done. %1 is a backreference to the first captured subgroup, ie. (^|&) - which "matches" ^ (start-of-string assertion) in your example URL and will therefore appear as an empty string in the substitution string.

However, instead of changing the backreference to %2, I would also consider changing the first subpattern (alternation group) to be non-capturing instead. ie. (?:^|&). This would prevent a backreference being generated, so %1 would indeed match (\d+).

You don't appear to need the NE flag here (removing this should not "cause the '&' to be lost" in this context?). However, you may need the L flag to prevent further processing and potential conflicts with later directives.

The trailing .*$ would seem to be unnecessary in the example you posted.

So, try the following instead:

RewriteCond %{QUERY_STRING} (?:^|&)v1=123&v2=(\d+)
RewriteRule ^sub/$ sub/?v1=789&v2=%1 [L]
MrWhite
  • 43,224
  • 4
  • 50
  • 90
1

%1 is the contents from the first set of parenthesis in your rewrite condition. You have used TWO sets of parenthesis: (^|&) and (\d+). %1 is matching the first of those which contains nothing but the "start of the expression" (^), so no characters.

You have two possible solutions:

  • Change your rewrite rule from using %1 to using %2.
  • Change your rewrite condition to use non-capturing parenthesis for the first set: (?:^|&)
Stephen Ostermiller
  • 99,822
  • 18
  • 143
  • 364