 <p>You have to check if it was clean request or not. Otherwise you will fall into infinite loop</p> <p>Here is an <em>example</em> from one of my projects:</p> <p>.htaccess</p> <pre><code>RewriteEngine On RewriteRule ^game/([0-9]+)/ /game.php?newid=$1 </code></pre> <p>game.php</p> <pre><code>if (isset($_GET['id'])) { $row = dbgetrow("SELECT * FROM games WHERE id = %s",$_GET['id']); if ($row) { Header( "HTTP/1.1 301 Moved Permanently" ); Header( "Location: /game/".$row['id']."/".seo_title($row['name'])); } else { Header( "HTTP/1.1 404 Not found" ); } exit; } if (isset($_GET['newid'])) $_GET['id'] = $_GET['newid']; </code></pre> <p>So, you have to verify, if it was direct "dirty" call or rewritten one.<br> And then redirect only if former one.<br> You need some code to build clean url too. </p> <p>And it is also very important to show 404 instead of redirect in case url is wrong.</p>