Take the 2-minute tour ×
Webmasters Stack Exchange is a question and answer site for pro webmasters. It's 100% free, no registration required.

NOTE: My terminology may not be entirely correct. I believe StackExchange does something like what I am asking, in case this can make things clearer.

Using PHP on Apache, I would like to handle URLs such as:

http://www.site.com/info/<brand>/<model>/<page>

For example with <brand> = toyota, <model> = camry, <page> = 'safety'

And have all the URLs starting with 'info' (let's say) be handled by a single PHP file like 'info.php' without the URL in the location bar changing.

In other words, someone navigates to:

http://www.site.com/info/toyota/camry/safety

But the code to handle this is in info.php but the URL in the browser stays as is. I do not want to have to create all the /toyota/camera/safety directory structure (there would be 1000s).

My guess is that info.php would get the path components as parameters in order to know what content to serve. So the internal invocation invisible to the user would be:

info.php?brand=toyota&model=camera&page=safety

Seems like the question here are doing something similar since they get URLs like:

http://webmasters.stackexchange.com/questions/13978/how-to-implement-user-friendly-paths-in-php-without-creating-a-file-or-directory

and I presume the path there is not actually created on the server.

share|improve this question
add comment

1 Answer 1

up vote 4 down vote accepted

Because you're using Apache, you want mod_rewrite, which is usually available by default. mod_rewrite lets you rewrite requests as they come in. It can make sub-requests, change the current request, or even redirect the user somewhere else. It's an exceptionally powerful tool with a syntax that can be kind of obtuse at times.

You'll want to set up RewriteRules. RewriteRules use the PCRE regular expression library, so if you've used regexes in Perl or the preg family of functions in PHP, you should be pretty familiar with the syntax.

There are two common patterns when making pretty URLs with mod_rewrite and PHP. In the first, you'll pick a "mount point" under which all the pretty URLs will live, and instead invoke a PHP script that is given the rest of the path after the mount point. For example, a call to /info/toyota/camry/saftey could be rewritten to /info.php/toyota/camry/saftey.

The PHP script would then access $_SERVER['PATH_INFO'], which would contain /toyota/camry/saftey, and process that value as it needs to. Yes, this will totally work. Try it out yourself with a phpinfo script. You'll find the bits after the file extension inside PATH_INFO.

Here's an untested but probably working example:

# ask mod_rewrite to turn itself on
    RewriteEngine On
# If the request is not for an actual file, then...
    RewriteCond %{REQUEST_FILENAME} !-f
# ... capture the part of the path after /info/ and replace it 
# with a call to the PHP script.  In the regex, .+ means "Any 
# character, one or more times"
    RewriteRule ^/info/(.+)$ /info.php/$1

The second pattern is to set up a rewrite rule to actually extract parts of the path and turn it into a plain old regular query string. This would be best if you have an existing script and don't want to make changes to it. It can also be more complex, as you'd need to write one rule per set of candidate URLs.

Here's another untested but probably working example.

# /info/foo => info.php?brand=foo
# [^/]+ means "Any character that is not a /, one or more times
    RewriteRule ^/info/([^/]+)$ /info.php?brand=$1
# /info/foo/bar => info.php?brand=foo&model=bar
    RewriteRule ^/info/([^/]+)/([^/]+)$ /info.php?brand=$1&model=$2
# /info/foo/bar/baz => info.php?brand=foo&model=bar&page=baz
    RewriteRule ^/info/([^/]+)/([^/]+)/([^/]+)$ /info.php?brand=$1&model=$2&page=$3

This is just a tip of the mod_rewrite iceburg. There are lots and lots and lots of tutorials and guides out there that can help you along.

share|improve this answer
    
Well, I've used mod_rewrite before but it always changes the user-visible URL (like a redirect). Is it a config option so that the user-entered URL stays fixed? –  Itai May 18 '11 at 3:23
1  
The first example seems to also catch mistypes URLs. Is that true? Wouldn't this create confusing 404s? I will try the second soon. Thanks for your help! –  Itai May 18 '11 at 3:25
1  
mod_rewrite will send a redirect (thus causing the user to make a new request, changing the URL) if you ask it to, using the R flag. If you omit the flag, it won't throw a redirect. Both examples have the potential to accept input that would be invalid when processed by PHP. You can simply have your script send a 404 page back, if the request would call for such a response. –  Charles May 18 '11 at 3:39
    
The second example is screwing up paths and cant resources anymore. It seems like the path includes the bogus levels rather than the path of info.php (which is in the root). How can I avoid this? –  Itai May 18 '11 at 17:48
    
As I noted, I didn't actually test any of these rewrites. I actually only use the first form in production, and let my PHP code sort out the rest. I think that adding the L flag to each of those RewriteRules should do the trick. –  Charles May 18 '11 at 19:58
show 8 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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