1

I run multiple sites on one server, from one .htaccess file with a custom site design that uses one page (index.php?pageid=x). Depending on the pageid it triggers different content/layouts.

For each site I'm using an IF statement within .htccess, for example:

<If "%{HTTP_HOST} == 'site.com'">     
RewriteRule goes here
</If>

If I'm out of the IF statement I use a rewrite rule like this:

RewriteRule ^fr/cookie-policy/$ /index.php?pageid=11 [L]

The above rule works as planned, but if I use this rule within the IF statement it doesn't work. I have to remove the leading ^ and swap it for a /. But this is far from ideal as it will matches anything the ends with a designated pattern.

Can anyone suggest a solution? What I'm I missing?

PlatformDating
  • 167
  • 1
  • 13
  • Probably has something to do with the order these directives get evaluated in. Does it work if you just _add_ the leading slash, i.e. `RewriteRule ^/fr/…`? If not, then there might be more path segments before this that have not been stripped off at this point. – 04FS Sep 21 '20 at 11:18
  • @04FS If I add the leading slash as you suggest within the IF statement it fails with a 404. – PlatformDating Sep 21 '20 at 11:24
  • Then figure out what the actual URL path you are dealing with at this point is first. `RewriteRule (.*) https://example.com?path=$1 [R=302]` should capture the full path at this point, and make an external redirect to `https://example.com?path=…` - that parameter won’t do anything on the receiving end, but checking where you got redirected to in the browser address bar should clearly show you what the actual URL path was at this point. (And yes, I mean `https://example.com` here, literally, do not replace it with your own domain.) – 04FS Sep 21 '20 at 11:37

1 Answers1

2

The <If> container changes the order of processing. <If> containers are merged very late. See: how sections are merged in the Apache docs

This results in the RewriteRule directives inside the <If> matching against the absolute filesystem path that the request has mapped to, including the directory-prefix, which is ordinarily removed when matching in a directory context (ie. .htaccess). (Maybe the request has been mapped back to the filesystem at the time the <If> section is processed?)

RewriteRule ^fr/cookie-policy/$ /index.php?pageid=11 [L]

So, if fr/cookie-policy/ is relative to the document root and the DocumentRoot is /var/www/user/public_html then to match this exactly, you need to match against /var/www/user/public_html/fr/cookie-policy/.

I don't see any way to avoid this unless you use an additional condition (and check against the REQUEST_URI server variable) - but that would seem to defeat the point (and would be less efficient).

it will matches anything the ends with a designated pattern.

Without specifying the full absolute file-path, you could perhaps just include the parent directory (ie. one above the document root) to lessen the chances of this happening. eg. public_html/fr/cookie-policy/$.


A few other (bizarre) caveats I've noticed with using mod_rewrite inside an <If> section:

  • You can't rewrite to a relative path (ie. not starting with a slash or scheme+hostname). It needs to start with a slash (ie. root-relative). Rewriting to a relative path in a directory context ordinarily results in the directory-prefix being added back. However, inside the <If> container, the directory-prefix appears to be seen as *If/ - which will likely result in a "400 Bad Request". (Maybe this is because at the time the <If> section is merged, the directory-prefix has already been added back?)

  • Related to above, the RewriteBase directive is "ignored".

  • Other mod_rewrite directives outside of the <If> section (in the same context at least) appear to take on the same behaviour and now also only match against the full absolute filesystem path.

  • Despite <If> sections being merged "late". They are still processed before other mod-rewrite directives outside of the <If> section. Regardless of the order of the directives. (In the same context at least.)

  • See also: <If> condition with HTTP_HOST in htaccess breaks PHP

Ordinarily, if you need to check the HTTP_HOST before applying a particular rewrite then you'd check this in a preceding RewriteCond (condition). But you know that already

MrWhite
  • 43,179
  • 8
  • 60
  • 84