Rewrite Rule for URL with query does not work

I write the following rewrite rule:

<IfModule mod_rewrite.c>
RewriteCond %{QUERY_STRING} rp=\/knowledgebase\/.*
RewriteRule ^\/customer\/index.php /knowledgebase/ [R=301,L]
RewriteRule ^\/customer\/knowledgebase\.php$ /knowledgebase/ [R=301,L,QSA]
</IfModule>

To redirect URL such as

https://www.example.com/customer/index.php?rp=/knowledgebase/5/DataNumen-Excel-Repair to https://www.example.com/knowledgebase/

And redirect URL such as

https://www.example.com/customer/knowledgebase.php to https://www.example.com/knowledgebase/

But both do not work. Why?

Update

I try to put MrWhite's codes from /.htaccess to /customer/.htaccess and make some minor changes to adopt the changes, as below:

RewriteCond %{QUERY_STRING} rp=/knowledgebase/
RewriteRule ^index\.php$ https://www.example.com/knowledgebase/ [QSD,R=301,L,NC]

RewriteRule ^knowledgebase\.php$ https://www.example.com/knowledgebase/ [R=301,L,NC]

Now the redirect works. However, it will only work for case like:

https://www.example.com/customer/index.php?rp=/knowledgebase/9/DataNumen-PDF-Repair

but for case like

https://www.example.com/customer/index.php?a=b&c=d&rp=/knowledgebase/9/DataNumen-PDF-Repair

It will not work. Even after I change ^rp= to rp in RewriteCond.


Solution 1:

RewriteRule ^/customer/index.php /knowledgebase/ [R=301,L]

In .htaccess, the URL-path matched by the RewriteRule pattern (ie. ^\/customer\/index.php) does not start with a slash, so this will never match. The URL-path that is matched is relative to the directory that contains the .htaccess file (less the slash prefix). (Unlike when used in a server context, when the URL-path that is matched is the document-root-relative URL-path, starting with a slash.)

You will also need the QSD flag on the first rule to discard the query string on the original request, otherwise this is passed through as-is.

Minor point... there is no need to backslash-escape slashes in Apache regex, since spaces are the argument delimiter and the slash carries no special meaning otherwise in regex.

Try the following instead:

RewriteEngine On

RewriteCond %{QUERY_STRING} ^rp=/knowledgebase/
RewriteRule ^customer/index\.php$ /knowledgebase/ [QSD,R=301,L]

RewriteRule ^customer/knowledgebase\.php$ /knowledgebase/ [R=301,L]

I anchored the query string in the condition so it matches rp=... at the start of the query string, as in your example. The .* at the end of the regex is not required.

The QSA flag is not required on the 2nd rule since the query string is passed through by default. The QSA flag would only be required if you needed to merge the original query string on the request with a new query string you were appending in the substitution.

The <IfModule> wrapper is not required, unless these directives are optional and intended to be used on multiple servers where mod_rewrite might not be available. See this question on the Webmasters stack: https://webmasters.stackexchange.com/questions/112600/is-checking-for-mod-write-really-necessary

You should test first with 302 (temporary) redirects to avoid potential caching issues.


UPDATE: to make things simple, I put the rewrite rules to the .htaccess file under /customer instead of /. I have updated my post accordingly.

In that case, you would need to remove the customer/ prefix on each of the RewriteRule patterns, as you have done in your updated question.

If the rp URL parameter is intended to match anywhere in the query string then you should change the CondPattern to read (^|&)rp=/knowledgebase/, rather than simply removing the ^ prefix. By removing the ^ prefix you are potentially matching too much, eg. abcrp=/knowledgebase/... would also match, although that may or may not be an issue in reality.

Otherwise, those updated directives look OK, depending on any other conflicts that might exist with other directives. Caching might also be an issue, especially if you are using CDN.