Apache .htaccess query string redirects

by Simon. Average Reading Time: about 2 minutes.

One of the most common tasks performed by Apache and htaccess is the manipulation of a URL and configuring a redirect for a specific page. Creating a single page redirect in Apache is a simple task, which uses mod_alias module.

Redirect /page.php http://www.example.com/target.php

More commonly, however, you’re likely to want to do a mass-redirection of pages. To accomplish this, you may use the RedirectMatch directive.

RedirectMatch ^/category/(.*)$ http://www.example.com/topic/$1

This will redirect any page from the category folder to the corresponding one in topic folder with a convenient one-by-one redirect.

However, neither Redirect nor RedirectMatch allow you to specify a query string for the redirect source. In other words, the following statements are invalid and they’ll simply be ignored.

# single page redirect
Redirect /page.php?id=1  http://www.example.com/page/1
Redirect /page.php?id=10  http://www.example.com/page/10
# multi-page redirect
RedirectMatch ^/page.php?id=([0-9]*)$  http://www.example.com/page/$1

The solution requires a change of focus from Apache’s mod_alias module to the mod_rewrite module. Here’s an example.

RewriteEngine On
RewriteCond %{REQUEST_URI}  ^/page\.php$
RewriteCond %{QUERY_STRING} ^id=([0-9]*)$
RewriteRule ^(.*)$ http://www.example.com/page/%1.php [L,R=301]

The mod_rewrite module uses a rule-based rewriting engine (based on a regular-expression parser) to rewrite requested URLs on the fly. It supports an unlimited number of rules and an unlimited number of attached rule conditions for each rule, to provide a really flexible and powerful URL manipulation mechanism. The URL manipulations can depend on various tests, of server variables, environment variables, HTTP headers, or time stamps.

So what does this all mean with respect to the above example?

The first line enables the RewriteEngine module. Note that mod_rewrite Apache module must be installed and enabled in order to use the RewriteEngine.

The RewriteCond statements set all the rewrite conditions. The fourth line, the real rewrite directive, will be executed if and only if all conditions are satisfied by the current request.

The first condition is for the page I need to redirect. This condition is included to prevent any unexpected errors if other pages are using the ID variable. Next, I base the rewrite rule on the value for the current request’s query string. The ID value within the regular expression is “wrapped” to be able to reuse the match later as a back-reference.

The final line is the rewrite rule. This line looks similar to the RedirectMatch statement. It specifies the redirection source, then the redirection target. The value captured by the second RewriteCond is referenced in the target with the %N keyword (in this example %1). The RewriteRule also includes a comma-separated list of flags that should be applied to the rule. In this case, L stops the rewriting process immediately whilst R=301 specifies a permanent external redirect (301 is an HTTP Status Code).

Further reading:

This article has been tagged

, , , , , , ,

Other articles I recommend

Apache RewriteRule and query strings

At first glance, the way the Apache mod_rewrite module handles query strings can be a little intimidating. mod_rewrite works by sitting on your server in a file called htaccess, and “catching” requests for URL‘s. It then checks these URL request against a series of rules and conditions you have set. If the request meets any of the rules and conditions, it applies then necessary changes to the URL, then reprocesses the request with the changes you have directed.

Enabling Search Engine Safe URLs with Apache and htaccess

An increasingly popular technique among websites and in particular, blogs, is the idea of making URLs search engine friendly, or safe, on the premise that doing so will help search engine optimisation. By removing the obscure query string element of a URL and replacing it with keyword rich alternatives, not only makes it more readable for a human being, but also the venerable robots that allow our page content to be found in the first place.

Setting up PHP on Mac OSX 10.6 (Snow Leopard)

Since Apple launched Mac OS X 10.5 (Leopard), PHP has been installed by default, albeit disabled. Here is a quick run through of what you need to do to get it up and running.

  • Great article Simon – thanks.

    I actually have a load of urls with query strings such as:

    but they all need to redirect to urls with no specific pattern. For example, the one above might need to redirect to:

    Any idea how one would go about this?



  • @jim You’d need some form of database solution to work out the page slugs based on a pageid. It’d be well worth you looking at how WordPress does this, or perhaps other CMS solutions.

  • Thanks for this, your post is the closest I’ve come to finding the answer that I’m looking for…  I keep thinking that what I want to do should be less complicated, but maybe I’m wrong.

    I don’t need to take the values from the query string and use them in the new url. All I want to do is remove the query string from a series of urls. For example:


    Then, all of them have the same query string “?programs&degrees” that I would like to remove… hopefully just using a couple lines of redirects (instead of using 50+, which I can do).

    It may seem odd that I would have to do this, but it has to do with a search functionality I have on one of my sites and if the user only chooses one of the three options (states, programs, degrees) they get one of the above urls which creates duplicate pages.

    Looking for a redirect that could remove the query string just from these pages that start with “/states/” and no others. Do you have any idea how I would do this?

    Any help is much appreciated! Thanks!

  • Santosh Suryawanshi

    Thank you for Posting Query String redirection article.
    It’s help me lot.

  • I am trying to get ?attachment_id=340 to redirect to the TLD, but can’t with the above samples, so I must be missing something?

    Thanks if you can help.