.htaccess rewrites and Ampersands (&'s) in variables?

I’m having a problem passing ampersands (& signs) via .htaccess.

Say I’m using the following rewriterule:

RewriteRule ^test/(.*) test.php?testvar=$1

And test.php is simply:

echo $testvar;

Going to /test/some%26data only outputs “some”, rather than “some&data” like I want it to.

Other special characters seem to work fine; e.g., /test/hello%20%24bye correctly outputs “hello $bye”.

Anyone know what the problem is?

Have you tried [NE] flag?
RewriteRule ^test/(.*) test.php?testvar=$1 [NE]

I tried that, but it didn’t help.

Other special characters do work, but %26 does not, so I don’t think escaping is the problem.

Well, maybe you can try one of these, with and wtihout [NE] flag.
Also, you can check what’s going on with RewriteLog, if you have access, or if you have a test server.

RewriteRule ^test/(.)\%26(.) test.php?testvar=$1\%26$2
RewriteRule ^test/(.)\%26(.) test.php?testvar=$1\%2526$2
RewriteRule ^test/(.)\&(.) test.php?testvar=$1\%26$2
RewriteRule ^test/(.)\&(.) test.php?testvar=$1\%2526$2

If you have multiple replacement to do, see this example.

Replacing %26 with %2526 works - THANK YOU! :smiley:

I’m very grateful, this is very helpful :slight_smile: Thanks a bunch.

Edit: I’d also like to note that this helped solve another problem I encountered, that of forward slashes. mod_rewrite treats %2F as an actual forward slash, causing 404 errors. Replacing %2F with %252F fixes that problem.

Thank you for reporting.
As this question comes up a few times per year, other people will find this thread helpful.

I’m a little wondering if the replacement is needed because of Apache or because of PHP.
I know Apache has strange behavior sometimes but not so often,
while PHP does lots of weird things…

It has to be with Apache, I think. In the example above, if I do test.php?testvar=apples%252Foranges, it sets testvar to ‘apples%2Foranges’. If instead it is passed in through mod_rewrite, testvar becomes ‘apples/oranges’. (so the decoding of ‘%25’ as ‘%’ by mod_rewrite before additional decoding seems to be at the heart of the problem)

This poses a bit of a problem, as the variable value now depends on how the script was accessed - directly, or through a rewrite.

Is there any way in PHP to know whether the current page was rewritten via .htaccess?

It seems the left sifde of RewriteRule decodes URL escaped chars (like %3f) before they match against regex.

RewriteRule regex substitute [FLAG]
“regex” is matched against REQUEST_URI stripped of forwarod / or per-directory prefix, AND all URL encoded chars decoded.

But the value in %{REQUEST_URI}, %{THE_REQUEST}, and others keep %nn.
So, If you want URL encoded chars to remain without decoding, you shouldn’t use the backrefs coming from the left side of RewriteRule.

This would keep URL encoded chars (na matter what they are), I guess.
RewriteCond %{REQUEST_URI} ^/test/(.)$
RewriteRule ^/*test/ test.php?testvar=%1

But if you are concerned only about & or another single char,
the method you tested can be adequate.