I am switching CMS and have about 600 URLs that need to get redirected to the new scheme. The URL on the old site looks like the following on my test server:


The new URL scheme will exist as:


Some old URLs use p=, others id= or catid=. I have tried various redirects like the following, all failing for various reasons:

RewriteEngine on
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteCond %{REQUEST_URI}  ^/$
RewriteCond %{QUERY_STRING} ^p=100
RewriteRule .* 100.php

The result is that it redirect to 100.php but appends the query string to the url and ends up like:


That is the closest to a solution. I have also tried the following with the failure message noted below:

RewriteCond %{REQUEST_URI}  ^/$
RewriteCond %{QUERY_STRING} ^p=100
RewriteRule ^(.*)$ 100.php
# Fails as it appends query string

RewriteCond %{REQUEST_URI}  ^/$
RewriteCond %{QUERY_STRING} ^p=100
RewriteRule .* 100.php$
# Fails with The requested URL /100.php$ was not found on this server.

RewriteEngine on
RewriteCond %{QUERY_STRING} ^p=100$
RewriteRule ^index\.php$ 100.php [L,R=301]
# Fails redirecting to /index.html

RewriteRule p=100 100.php  [R=301,L]
# Fails redirecting to /index.html

RewriteRule ^p=100$ 100.php  [R=301,L]
# Fails redirecting to /index.html

I tried many of the above with/without http:// preceding the redirect to URL.

  • Is there are relationship between the old and new URLs? Your example code seems to suggest that /p=NNN maps to NNN.php - however, this does not correlate to the URL example at the top (where p=100 seems to map to blog.php?p=2792)? Is p=NNN (or id= or catid=) the only part of the old URL that matters?
    – MrWhite
    Jul 24, 2015 at 16:44
  • 1
    My apologies. The 2792 should have been switched to 100. I just corrected it. So yes the $id or $p or $catid is the relationship. The goal is to redirect to a simple URL like 100.php, but without the additional parameters baggage.
    – Bob M
    Jul 24, 2015 at 16:58

2 Answers 2


This assumes that p, id or catid always appears at the start of the query string, and that the value of this parameter is the "file" basename in the new URL, as per your code examples.

RewriteEngine On
RewriteCond %{QUERY_STRING} ^(p|id|catid)=(\d+)
RewriteRule ^$ /%2.php? [R=301,L]

The ^$ pattern only processes requests for the document root (ie. example.com/). The %2 back reference refers to the 2nd parenthesised sub pattern in the CondPattern (ie. (\d+)). If you omit the R flag (and don't specify an absolute URL) then it will result in an internal rewrite, not an external redirect as I would assume is required here (ie. the URL in the address bar would not change).

The ? on the end of the RewriteRule substitution strips the original query string from the rewritten URL. This essentially creates an "empty" query string (the ? is not present in the result). Alternatively you can use the QSD (Query String Discard) flag on Apache 2.4+

By default, unless you specify a new query string on the RewriteRule substitution then the original query string will be copied onto the rewritten URL (as you have found). If you ever wanted to merge the original query string with a new one that you specify then you would need to use the QSA (Query String Append) flag.

  • I had to tweak my id name and final URLs, but with your help I have it working for both the category and individual blogs which follow the pattern of being at the beginning of the string. Fantastic. I separated the rule to a separate line for the ID and tweaked it to no avail. That line/pattern looks like index.php/archived-content?id=248, with id=$n at the end. I have about a dozen of these and they will get redirected to completely custom URLs, such as funny-business.php, no relation to the ID. My tweaks are not getting a match.
    – Bob M
    Jul 24, 2015 at 20:03
  • Glad you got it working (the first part at least). If this sufficiently answered the question then please mark it as accepted (click the "tick" on the left) to remove it from the unanswered question queue. Please feel free to ask another question regarding your other redirects/regex.
    – MrWhite
    Jul 24, 2015 at 20:44

I figured out how to solve the second part of the question where the ID= was found at the end like the following:


by adding a line to the .htaccess like:

RewriteCond %{QUERY_STRING} ^id=206
RewriteRule (.*) /some-file-name.php? [R=301,L]
  • Small tip: You don't need the parenthesis around the RewriteRule pattern unless you are using a backreference (eg. $1) in the substitution. ie. (.*) is the same as .*.
    – MrWhite
    Jul 26, 2015 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.