Skip to content
Advertisement

Why Apache RewriteRule treats the same way with ‘&’ and ‘?’

I’m trying to code a custom rewrite rule for ‘.htaccess’ file in my Apache webserver.

The main idea is to handle requests in the form:

example.com/foo

to ‘index.php’ file in the www_root:

example.com/index.php?queryString1=foo

As everyone knows, this is easy to do. Just by adding below lines to ‘.htaccess’ file:

RewriteEngine on
RewriteCond %{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !-d
RewriteCond %{REQUEST_URI} !-l
RewriteRule ^(.*)$ index.php?queryString1=$1 [QSA,L]

But the problem is that when we want to add another query string to the request, for example as follows:

example.com/foo?queryString2=bar&queryString3=baz

contrary to my expectations, the following URL does the same:

example.com/foo&queryString2=bar&queryString3=baz

I don’t want the second case (in which second query string starts with ‘&’) to be executed. Also, if you write in ‘index.php’ file:

<?php echo '<pre>'.print_r($_SERVER['QUERY_STRING'], TRUE).'</pre>'; ?>

then, the output of both URLs (example.com/foo?queryString2=bar&queryString3=baz and example.com/foo&queryString2=bar&queryString3=baz) will be unique:

queryString1=foo&queryString2=bar&queryString3=baz

Can anyone explain what’s wrong with my codes in ‘.htaccess’ file? Thanks.

Advertisement

Answer

After above discussion, apache2 does not handle & and ? in the same way. “?” is separator of URL from QUERY_STRING, but & is a normal character as part of URL matched by apache2 RewriteRule.

In pattern of https://www.example.com/URL?QUERY_STRING, URL is only matched by RewriteRule in .htaccess file, it’s the string after the hostname and port if given, and before the query string ref., without the leading slash /.

Be careful, in apache2 configuration files vhosts.conf or alike, read when apache2 server starts, RewriteRule mathches against /URL string (yes with the leading slash).

The OP’s case is just a chance, not general rule. I’ve tested this for the solution by triggering a 404 Not Found error if & is involved in URL:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^([^&]*)$ index.php?queryString1=$1 [QSA,L]

example.com/foo&queryString2=bar&queryString3=baz will yield a 404 error.

%{REQUEST_FILENAME} is better than %{REQUEST_URI}.

The character range [^&] means any character but not &. With regex ^([^&]*)$, we select a string containing no & from beginning represented by ^, to the end reprerented by $, so & sign free.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement