You need the RewriteCond
because RewriteRule
s only see the path portion of the URL, not the query string. From the documentation:
"What is matched?
In VirtualHost
context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html").
In Directory
and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule
(e.g. "app1/index.html" or "index.html" depending on where the directives are defined).
If you wish to match against the hostname, port, or query string, use a RewriteCond
with the %{HTTP_HOST}
, %{SERVER_PORT}
, or %{QUERY_STRING}
variables respectively."
I would also strongly recommend reading the "Per-directory Rewrites" box below that, since that's exactly what you're doing here.
One way to accomplish what you want might be like this:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/$ [OR]
RewriteCond %{QUERY_STRING} !^(category|do)=[a-z]+$
RewriteRule ^ - [R=404,L,NS]
Note how the RewriteRule
simply matches everything, and the actual checks are done with the RewriteCond
s. The first RewriteCond
matches if the path portion of the URI doesn't equal /
; the second will match either if the first one did (because of the OR
flag) or if the query string (sans ?
) doesn't match category=[a-z]+
or do=[a-z]+
.
(Note: I have not actually tested this code. I think it should work as intended, but it's hard to be sure there are no bugs without testing.)