Tiffany B. Brown

a mish-mosh of stuff

Creating clean URIs with PHP

UPDATED to fix a broken link and correct some technical issues.

I recently switched from dynamic URIs to faux-static ones. Here’s how
to do the same on your site.

I’m going to assume that you’ve already got your own PHP/MySQL-driven publishing system in place, and that you currently use
dynamic URIs on your site.

Step one: Change your URIs

I use ‘perma-links’ on this site, as most ‘blogs do. The perma-link gives site visitors a target if they want to link to a specific entry on your site. If you use dynamic URIs, your perma-links are probably structured like this: filename.php?id=000.

Let’s clean up that URI: filename.php?id=000 will become
filename.php/000. You’ll notice that we’ve dropped the question mark, and the variable name (id).

Step two: Get the new URI

Next, you’ll need to modify the code on your template (in this
example, filename.php) so that it processes the new URIs. But first, you’ll need to get the user-requested URI by using:
$_SERVER['REQUEST_URI'].

$_SERVER['REQUEST_URI'] will return the location of the file on your server relative to your web root. In other words, if a visitor requested http://www.tiffanybbrown.com/example.php/200, the result of $_SERVER['REQUEST_URI'] would be /example.php/200.

Step three: Process the URI

In order to ‘process’ the URI, we’re going to use the explode() function. The code>explode() function "splits a string by a string" and creates an array variable.

In this example, we're going to split the entire request URI of the string by the PHP script name, and save it as a variable:

$entry=explode("/example.php/", $_SERVER['REQUEST_URI']);

The first parameter says where to split the string. The second parameter is the string to split. In this case, it's the request U R I. Note: you could also use / as the split point.

Now you can use each portion of the U R I by referring to the array.

60-second introduction to arrays:

Arrays are a special type of variable that holds a group of associated items. Think of an array as books on a shelf. The entire collection would be $shelf. To use the first book on the shelf, you'd use $shelf[0]. For the second book $shelf[1], and so on (Remember in programming, counting starts at zero).

To get the unique identifier of the entry, then, we'd do this:

$id=$entry[1];

Then you can use the variable $id in your SQL query. If you're using numeric identifiers, don't forget to check that the requested entry is a valid numeric string. And of course, use quotes around properly escape all variables to protect yourself from SQL injection attacks.

  • http://www.maryndesign.com/ BJ

    great tutorial, been looking for a good explanation of how to do this. My only question is this:

    So you have all hrefs use faux links, and I get how you build them and break them down… but how do you get the server to understand which page you’re trying to access? Do you use a auto_preppended that finds the script name in the faux link and header() over to that page, then do the breakdown?

    If I’m not being clear, please let me know, because I’d really like to do this on my site. Thanks for the help!

    BJ

  • http://www.maryndesign.com BJ

    great tutorial, been looking for a good explanation of how to do this. My only question is this:

    So you have all hrefs use faux links, and I get how you build them and break them down… but how do you get the server to understand which page you’re trying to access? Do you use a auto_preppended that finds the script name in the faux link and header() over to that page, then do the breakdown?

    If I’m not being clear, please let me know, because I’d really like to do this on my site. Thanks for the help!

    BJ

  • http://www.tiffanybbrown.com/ tiffany

    The server will treat use index.php or page.php as the file name. PHP will still recognize /index.php/234 as the requested URI. But as far as the server is concerned (at least with Apache), the requested page was index.php.

  • http://www.tiffanybbrown.com/ tiffany

    The server will treat use index.php or page.php as the file name. PHP will still recognize /index.php/234 as the requested URI. But as far as the server is concerned (at least with Apache), the requested page was index.php.

  • Brian

    Good tutotial. I wish you would actually show the code within the actual pages to better explain what you’re doing and where the code needs to go.

  • Brian

    Good tutotial. I wish you would actually show the code within the actual pages to better explain what you’re doing and where the code needs to go.

  • http://www.tiffanybbrown.com/ tiffany

    Brian, that is the code. Split the URL using explode and use $entry[1] in your SQL.

    A simple “select * from posts where id=$entry[1],” properly escaped of course.

  • http://www.tiffanybbrown.com/ tiffany

    Brian, that is the code. Split the URL using explode and use $entry[1] in your SQL.

    A simple “select * from posts where id=$entry[1],” properly escaped of course.

  • Brian

    thanks. i figured it out. but i am stuck on one issue. maybe you can help me with it… i am trying to send an error message from one page to the next using this method. the problem is when the receiving page gets the message, somehow the URL makes the page paths invalid. i now have to use all absolute paths instead of relative. is there a way around this?

    example:
    when the URL was http://www.index.php?error=Error everthing was fine.
    when the URL is http://www.index.php/Error i have problems because the paths in my index.php think they’re in a folder called “Error”.

    i hope that makes sense. if you have any suggestions that would be great, if not, thanks anyway.

  • Brian

    thanks. i figured it out. but i am stuck on one issue. maybe you can help me with it… i am trying to send an error message from one page to the next using this method. the problem is when the receiving page gets the message, somehow the URL makes the page paths invalid. i now have to use all absolute paths instead of relative. is there a way around this?

    example:
    when the URL was http://www.index.php?error=Error everthing was fine.
    when the URL is http://www.index.php/Error i have problems because the paths in my index.php think they’re in a folder called “Error”.

    i hope that makes sense. if you have any suggestions that would be great, if not, thanks anyway.

  • http://www.tiffanybbrown.com/ tiffany

    ah…i think i had this problem as well. if i remember correctly, this tutorial will only work with numbers.

    if you want to do something like ‘index.php/Error,’ you’ll need to use mod_rewrite (on Apache server).

  • http://www.tiffanybbrown.com/ tiffany

    ah…i think i had this problem as well. if i remember correctly, this tutorial will only work with numbers.

    if you want to do something like ‘index.php/Error,’ you’ll need to use mod_rewrite (on Apache server).

  • http://biometria.gov.ar/ Nicolas

    Hey Tiffany:

    Could you add an example of how to do this with the page title instead? i.e.: this one! (http://tiffanybbrown.com/2003/12/22/creating_clean_uris_with_php)
    Also, when you say “a simple SELECT properly escaped to avoid SQL injection”, what do you mean?
    thanks a lot.

  • http://biometria.gov.ar Nicolas

    Hey Tiffany:

    Could you add an example of how to do this with the page title instead? i.e.: this one! (http://tiffanybbrown.com/2003/12/22/creating_clean_uris_with_php)
    Also, when you say “a simple SELECT properly escaped to avoid SQL injection”, what do you mean?
    thanks a lot.

  • http://www.tiffanybbrown.com/ tiffany

    Hey Nicolas,

    I’m not sure I understand what you’re trying to do with a page title. It should just be a matter of escaping the page with htmlentities(), or using str_replace() to replace the offending characters.

    “Also, when you say “a simple SELECT properly escaped to avoid SQL injectionâ€?, what do you mean?”

    If you are accepting user input, you want to make sure that the user hasn’t inserted some nasty command or poor syntax that could give you bad data — or worse, destroy your database.

    One way to do this is to use mysql_real_escape_string($varName) around your variables.

    Another way is to check that the value you receive is the same type as the one you were expecting. Say, for example, your SQL query is “SELECT * FROM posts WHERE id=$_GET['id'].” In that case, you definitely want to check whether or not $_GET['id'] is a numeric string using either is_numeric() or ctype_digit().

  • http://www.tiffanybbrown.com/ tiffany

    Hey Nicolas,

    I’m not sure I understand what you’re trying to do with a page title. It should just be a matter of escaping the page with htmlentities(), or using str_replace() to replace the offending characters.

    “Also, when you say “a simple SELECT properly escaped to avoid SQL injectionâ€?, what do you mean?”

    If you are accepting user input, you want to make sure that the user hasn’t inserted some nasty command or poor syntax that could give you bad data — or worse, destroy your database.

    One way to do this is to use mysql_real_escape_string($varName) around your variables.

    Another way is to check that the value you receive is the same type as the one you were expecting. Say, for example, your SQL query is “SELECT * FROM posts WHERE id=$_GET['id'].” In that case, you definitely want to check whether or not $_GET['id'] is a numeric string using either is_numeric() or ctype_digit().

  • http://www.keything.com/ Rewt

    Instead of fooling with mod_rewrite, just use .htaccess:

    ErrorDocument 404 /index.php

    Then, in your index.php file:

    $request = explode(‘/’, $_SERVER['REQUEST_URI']);
    array_shift($request);

    Now any file name (like index.php or example.com/newsletter) becomes $request[0]… since we’re exploding the slash, you can do:

    http://www.example.com/articles/how-to/build-friendly-uri

    Since Apache won’t find that URL, it defaults to index.php, which then breaks it up.

    $request[0] = articles
    $request[1] = how-to
    $request[2] = build-friendly-uri

    At this point, you can pass variables to mySQL, or do whatever you want with them. Pretty easy.

    You can see by using the ErrorDocument directive, you can just easily create these.

    Andy

  • http://www.keything.com Rewt

    Instead of fooling with mod_rewrite, just use .htaccess:

    ErrorDocument 404 /index.php

    Then, in your index.php file:

    $request = explode(‘/’, $_SERVER['REQUEST_URI']);
    array_shift($request);

    Now any file name (like index.php or example.com/newsletter) becomes $request[0]… since we’re exploding the slash, you can do:

    http://www.example.com/articles/how-to/build-friendly-uri

    Since Apache won’t find that URL, it defaults to index.php, which then breaks it up.

    $request[0] = articles
    $request[1] = how-to
    $request[2] = build-friendly-uri

    At this point, you can pass variables to mySQL, or do whatever you want with them. Pretty easy.

    You can see by using the ErrorDocument directive, you can just easily create these.

    Andy

  • http://sweet-brier-beauty.loinloin.nx.cn/ Christopher

    I would like to come here again. It sounds god to me, and there’s a lot of interesting information here

  • http://sweet-brier-beauty.loinloin.nx.cn/ Christopher

    I would like to come here again. It sounds god to me, and there’s a lot of interesting information here