I would like .htaccess to redirect:




I'm importing a bunch of pages that have ampersands in the title from MediaWiki. These are encoded as %26. Drupal, for various reasons, has decided double encode the URL to have it become %2526. I simply can't create the alias within Drupal so I have to use .htaccess.

This is what I have as my rule so far:

RewriteRule ^w/([^%26]+)\%26(.*)$ w/$1\%2526$2 [R=301]

I asked this question three months ago on StackOverflow and was not able to get it working. I tried hiring a contractor for this but was unable to find one. So this is my last ditch effort before I completely give up. I really appreciate the help.

  • 1
  • 2
    In all honesty, wouldn't it be better for everyone involved to run an UPDATE query against drupal's database to convert all the %26's back to ampersands, so that Drupal stops double-encoding them? – DerfK Jan 3 '11 at 16:49
  • @DerfK That would break links from other sites. Since there's about a 1000 pages with this problem, I would like to avoid this but if I don't find a solution, then that I just have to do it. Thanks – Patrick Jan 3 '11 at 17:02

'noescape|NE' (no URI escaping of output)

This flag prevents mod_rewrite from applying the usual URI escaping rules to the result of a rewrite. Ordinarily, special characters (such as '%', '$', ';', and so on) will be escaped into their hexcode equivalents ('%25', '%24', and '%3B', respectively); this flag prevents this from happening. This allows percent symbols to appear in the output

mod_rewrite Documentation at Apache.org

| improve this answer | |

Have a look at my answer (on Drupal.SE) to the question "How to use the Rules module to implement a custom redirect for an outdated URL?". I bet the solution described there (using the Rules module) also works for this case.

As detailed in that answer: the "clue" to get this to work, is to use the Rules Event "Drupal is initializing". That will ensure that the rule gets triggered BEFORE the actual content is shown.

| improve this answer | |

I had similar problem where the the '&' was incorrectly rewritten by the mod_rewrite. The B flag solved it:

B (escape backreferences) The [B] flag instructs RewriteRule to escape non-alphanumeric characters before applying the transformation.

It allowed me to serve the files containing '&' within their name, eg here

| improve this answer | |
  • The B flag is specific to backreferences, so whether this is relevant to the current question is very much dependent on the directive/method used. – MrWhite Nov 16 '18 at 1:14

To clarify, %26 is a URL-encoded (aka "%-encoded") & (ampersand).

To redirect a request for /something%26else literally (or /something&else, since the ampersand does not need to be escaped in the URL-path) to /something%2526else (ie. /something%26else when decoded) then you could do something like:

RewriteRule ^(something)&(else)$ /$1\%26$2 [R,L]

Or, the more generic /<anything>%26<anything>:

RewriteRule (.*)&(.*) /$1\%26$2 [R,L]

The RewriteRule pattern matches against the %-decoded URL-path (ie. &, not %26). So you should simply specify & (ampersand) literally. Note that this will match a request for both /something_%26_else and /something_&_else.

The % (percent) in the RewriteRule substitution needs to be backslash escaped in order to represent a literal %, otherwise it's going to be seen as a backreference to the last matched CondPattern, and there isn't any, so %2 would otherwise becomes an empty string!

Without the NE (noescape) flag, mod_rewrite will automatically encode the substitution URL, which is actually what we want in this instance: %26 gets encoded as %2526. (Which, when decoded, is seen as a literal %26.)

Alternatively, you could use the NE flag (that @danlefree mentions) and then manually encode the substitution:

RewriteRule (.*)&(.*) /$1\%2526$2 [R,L,NE]

However, this will have issues if there are other %-encoded characters in the URL (unless you match a literal "something" and "else"), as they won't be encoded in the response.

Another alternative is to capture the encoded URL from THE_REQUEST server variable (which contains the URL as it appears on the initial request) and simply pass this through to the substitution which then doubly encodes the target URL (in the absence of the NE flag):

RewriteCond %{THE_REQUEST} \s(.*\%26.*)\s
RewriteRule & %1 [R,L]

The check for %26 in the condition is required in case an unencoded "&" is sent in the request (to prevent a redirect loop). The RewriteRule pattern & matches both & and %26 in the requested URL-path (because the URL-path that is matched by the RewriteRule pattern is first URL-decoded).

A caveat with this approach is that if there are any other %-encoded characters in the requested URL then they will also be doubly encoded.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy