Rewriting your urls to clean permanent looking links

There are several articles out there on using mod_rewrite and .htaccess to convert from dynamic pages with query strings in the urls, to a cleaner more permanent looking link. But even after reading the documentation on RewriteCond and RewriteRule it took me a few hours of experimentation to get the desired effect. So I thought I would share my settings to help serve as examples for others trying to do something similar.

Using PHP and MySQL I have pages that are dynamically created from a database. The URLs for those pages look like:
http://budgetweb.com/budgetweb/details.php?id=2825&provider=CravisHostFive
I wanted to use mod_rewrite so that the links in my feed would look like
http://budgetweb.com/service/2825/CravisHostFive/
Here's what I added to the .htaccess in the root of my web site
RewriteEngine on
RewriteRule ^service/([0-9]+)/([^/]*)/$ /budgetweb/details.php?id=$1&provider=$2
I also wanted to handle links typed in which did not have the trailing slash. Here's what I added for that.
RewriteEngine on
RewriteRule ^service/([0-9]+)/([^/]*)$ /service/$1/$2/ [R]
RewriteRule ^service/([0-9]+)/([^/]*)/$ /budgetweb/details.php?id=$1&provider=$2
This rewrite rule has [R] which results in a round trip to the browser, so that the link in the browser bar is corrected as well. Then on the subsequent request back to the server the path matches the second pattern.

Lastly I wanted to redirect all the existing links to this new URL structure, so that all the previously indexed pages would get updated. This proves to be more tricky than at first I understood. The path provided to the RewriteRule does not include the query string - i.e. everything after the question mark (?) in the url. So you need to use RewriteCond. Here's what I added.
RewriteCond %{QUERY_STRING} id=([0-9]+)\&provider=(.*)
RewriteRule ^budgetweb/details.php$ /service/%1/%2/? [R=301]
This works great. The %1 and %2 in the RewriteRule match the portions of the regular expression in the RewriteCond surrounded by (). The other trick here was to have the trailing question mark in the RewriteRule. Without that, the original query string is re-appended to the rewritten URL, resulting in an infinite recursion. Lastly, the [R=301] sends a 301 Permanent Redirect back to the browser.

Now one problem combining all the rules above, is that even with the trailing question mark I've still got an infinite recursion. The details.php URL is rewritten to the /service/ URL which is then rewritten back. I couldn't work out how to block this in the rewriten rule, so instead I just created a copy of my PHP from details.php to service.php and ended up with these rules in my .htaccess
RewriteEngine on
RewriteCond %{QUERY_STRING} id=([0-9]+)\&provider=(.*)
RewriteRule ^budgetweb/details.php$ /service/%1/%2/? [R=301]
RewriteRule ^service/([0-9]+)/([^/]*)$ /service/$1/$2/ [R]
RewriteRule ^service/([0-9]+)/([^/]*)/$ /budgetweb/service.php?id=$1&provider=$2
The end result is
http://budgetweb.com/budgetweb/details.php?id=2825&provider=CravisHostFive
Permanently Redirects to http://budgetweb.com/service/2825/CravisHostFive/
http://budgetweb.com/service/2825/CravisHostFive
Temporarily Redirects to http://budgetweb.com/service/2825/CravisHostFive/
http://budgetweb.com/service/2825/CravisHostFive/
Rewrites to...
http://budgetweb.com/budgetweb/service.php?id=2825&provider=CravisHostFive