How to post forms to clean, rewritten URLs without JavaScript

by Matthew James Taylor on 14 January 2008

How to post forms to clean, rewritten URLs without JavaScript: a PHP and mod_rewrite tutorial

Rewritten URLs are valuable because they increase website usability and improve search engine optimisation (SEO), but unfortunately HTML forms and clean URLs were not designed to work together. In this tutorial I will reveal my secret way to make them work; to see a working solution try my website search in the top right of this page and note the clean URL on the search results page.

Let’s start by analysing the root problem. HTML forms only have two ways to pass variables to their target page; they are the GET and POST methods. Neither of these allow for dynamic rewritten URLs.

The POST method: (empty URLs)

Posting a form gives empty URLs

When posting data from a form, the parameters and their values are not visible in the target page URL, they are hidden behind the scenes. The problem with this is a user cannot simply copy the URL and go back to the same page later and see the same content; the exact page content is lost.

The GET method: (ugly, unfriendly URLs)

The Submitting a form with the GET method gives ugly, unfriendly URLs

Forms using the GET method send data via the URL. This means that the URL can be copied and revisited at any time. The problem with this method is the format of the parameters. The values in the URL string are ugly, verbose and unfriendly; this is what we are trying to avoid.

The solution: Post-to-self then redirect to rewritten URL

Form POST to self then redirect to a clean URL

The trick is to use server-side logic to construct a clean URL from posted form data and then redirect to it without the user knowing. Any number of form fields can be used but for simplicity in this tutorial I have used a one field text search as the example. The good thing about this solution is it is completely invisible to the user and the back button always takes you back to the first search page.

Ok, let's see how this works in more detail.

Building the search page

There are two parts to the search page, the HTML form, and the PHP code that handles the posted values. Let’s start by looking at the form.

The search form

Simply set the form method to POST and set the action to the current page (this is important). The easiest way to post a form to itself is to include the action parameter but make it equal to nothing. Here is the HTML of the search form:

<form method="post" action="">
   <fieldset>
      <input type="text" name="q" />
      <input type="submit" value="Search" />
   </fieldset>
</form>

The PHP form handling code

Because the form posts to itself, the PHP code that deals with the posted values MUST be included on every page where the form is displayed. It is important to note that if your search box is part of your website template then it will be visible on every page and so the code must be on every page too. This will also mean that every page must be a dynamic PHP page so server-side logic can be used to process the form data. In other words you cannot use the search on a static HTML page.

Another very important point concerns the placement of the code within the PHP file. For the server-side redirect to work correctly the PHP code that does the actual redirect MUST be before any HTML is output to the browser. If you don’t do this correctly then two pages will load, one after the other and the back button won’t take you back to the first page.

Here is the PHP code that handles the posted form data:

<?
// Collect the posted search query
$q = strtolower(mysql_real_escape_string($_POST['q']));

// Clean up by removing unwanted characters
$qclean = ereg_replace("[^ 0-9a-zA-Z]", " ", $q);

// Remove multiple adjacent spaces
while (strstr($qclean, "  ")) {
   $qclean = str_replace("  ", " ", $qclean);
}

// Replace single spaces with a URL friendly plus sign
$qclean = str_replace(" ", "+", $qclean);

// If validation has passed, redirect to the URL rewritten search page
if ($q != '') {
   header( 'Location: http://matthewjamestaylor.com/search/'.$q );
}
// HTML is output after here – NOT BEFORE!
?>
<html>

Building the search results page

There are four parts to the search results page; the Apache mod_rewrite rule, the PHP keyword processing, the MySQL query and then displaying the results.

Rewriting the search results page URL with mod_rewrite

To change the URL from search.php?q=keyword to a more friendly /search/keyword add the following rule to your .htaccess file:

# Clean up search URL
RewriteRule ^search/([^/\.]+)$ search.php?q=$1

Processing the keywords with PHP

First we collect the search phrase from the URL, validate the entry and then prepare it for inclusion in an SQL statement.

<?
// Collect the search phrase from the URL
$qs = mysql_real_escape_string($_GET['q']);

// Clean up by removing unwanted characters
$qsclean = ereg_replace("[^ 0-9a-zA-Z]", " ", $qs);

// Remove multiple adjacent spaces
while (strstr($qsclean, "  ")) {
   $qsclean = str_replace("  ", " ", $qsclean);
}

// Prefix each keyword with a + (for the SQL statement)
$qsql = "+".str_replace(" ", " +", $qsclean);
?>

Perform a MySQL Boolean full-text search

Once we have our keywords we simply add them to the SQL for our database search. You can read more about full-text searching using MySQL at Zend Developer Zone.

<?
$articles = mysql_query("SELECT title, MATCH(title, descr, body) AGAINST ('".$qsql."') as score from blog where 

MATCH(title, descr, body) AGAINST ('".$qsql."') order by score desc");
?>

Displaying the results

All we need is a simple while loop to print out all results.

<ul>
<?
while ($article = mysql_fetch_array($articles)) {
   print "<li>".$post[0]."</li> ";
}
?>
</ul>

That's it! Now we have the search results page working we can also build beautiful links to search results too. Here's an example: /search/chalk+portrait


Let's recap the main features:

  • Fully compliant with SEO friendly clean URLs
  • Does not break the back button
  • Works with JavaScript turned off
  • Works in all browsers
  • Simple to do with any server-side scripting

Follow me on Twitter @mattjamestaylor

Enjoy this article?

If you find my website useful, feel free to donate any amount you wish. It will help pay for my hosting! =)

Matthew James Taylor

Related articles