views:

314

answers:

5

I'm developing my first decent-sized PHP site, and I'm a bit confused about what the "right way" (assuming there ever is such a thing) to handle clean/friendly/pretty URLs in the application.

The way I see it, there are two main options (I'll use a simplified social news site as an example):

1. Use mod_rewrite to handle all potential URLs. This would look similar, but not identical, to the following:

RewriteRule ^article/?([^/]*)/?([^/]*)/?([^/]*) /content/articles.php?articleid=$1&slug=$2
RewriteRule ^users/?([^/]*)/?([^/]*) /content/users.php?userid=$1&username=$2
RewriteRule ^search/?([^/]*)/? /content/search.php?query=$1

2. Pass everything to some handler script and let it worry about the details:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) handler.php?content=$1

Clearly this is all untested "air code," but you get the point.

  • Is one of these two ways going to be seriously slower than the other? Presumably the mod_rewrite is slower, since I'll be forced to use .htaccess files for this.
  • Are there serious disadvantages to either of these approaches?
  • Is there a "best practice" for this sort of thing, or is it something that each developer tends to decide for themselves? I know WordPress uses option two (though it was more trouble than it was worth when I investigated exactly how they did it).
+4  A: 

Option 1 (.htaccess and several .php files) was often used "in the past" ; now, I see option 2 (every request going through one .php file) used a lot more.

The main advantages I see with option 2 are :

  • you can add / modify any kind of URL without having to change any physical file like .htaccess
    • which means the format of the URLs can be configured in the admin section of your application, for example
  • you only have one entry point to your PHP code.
    • which means everything goes though index.php : if you need some code executed for all requests, put it there, and you're sure it'll always be executed.
    • That's used a lot with MVC frameworks, for instance.


A couple of years ago, I would have gone with option 1 ; now that I use MVC and Frameworks, I always go with option 2.

Pascal MARTIN
The "in the past" point is well taken. I looked around and found a lot about mod_rewrite for this sort of thing so I looked into it (to the point of reading a whole book on it over the last couple days). I guess it helps to have learned that, in case I ever need it, but I should definitely be looking more to the future. Thanks!
AgentConundrum
You're welcome :-) ;; "in the past" doesn't means it's not used anymore, nor is never usefull ; just that, nowadays, you'd rather go with MVC and a single entry point -- even if, in some cases, it's always good to know how to write a couple of rewriterules ;-)
Pascal MARTIN
I realize that. I suppose I should have realized that I was trying to put application logic outside the application. It seems a bit obvious now. People have been recommending Symfony in this thread, but I just looked at it and I realize now that it's a full framework rather than just the routing code. I've been trying mainly to learn with this project, so I've been avoiding frameworks for now. Shouldn't be too hard to roll my own though (famous last words) :)
AgentConundrum
Well, learning how to develop with a (well-known) framework, like symfony or Zend Framework, can be useful too ;-) ;; rolling your own framework ? well, that's a great experience too, and you'll learn plenty of usefull things (and a couple of "I will never do that again", which are usefull too ^^ ) ;; have fun !
Pascal MARTIN
+1  A: 

As far as I can see, any possible performance differences between those methods are really minuscule and relevant only for really, really high-traffic sites.

I think there is no "best practice" as such, both methods are equally often used. If your project structure allows it, and you're more at home with parsing the URL in PHP (where the rest of your project is), put everything through one controller file, and let your application handle the rest.

If performance is really of the essence, I suspect that having Apache handle the addresses is faster, because there is no interpreted language in between. (I have no hard data for this, though). But as I said, you're probably best of choosing whichever is going to be most maintainable for you in the long term.

Pekka
I would have expected that PHP would have been the faster of the two, but that could be because the book I've been reading really hammered the ".htaccess slows things down, at least compared to doing it in your config" point in. Still, while I hope the site becomes quite popular, I doubt it would ever get to the point where "really miniscule" differences in this one choice would become a primary bottleneck.
AgentConundrum
+4  A: 

Really this is the "are frameworks worth using?" question in disguise.

Using mod_rewrite to define your URL routes is quick and easy (if you understand regular expressions...) but your application code is oblivious to the URLs unless you duplicate the information somewhere.

Usually, people duplicate this information many times without thinking about it, by hard-coding URLs in the links in their views, or in redirects. This is really messy, and will one day cause pain when you decide to change the URL structure of your site halfway through development. You're bound to miss one and end up with a 404 somewhere.

Using a routing component in your application (such as the one in Symfony) means you can attach names to your routes, allowing you to define your URLs once and re-use them many times:

# apps/frontend/config/routing.yml
homepage:
  url:   /
  param: { module: default, action: index }

This makes it really easy to link to pages of your site without repeating yourself:

<?php echo url_for('@homepage') ?>
Ben James
I hadn't heard of Symfony before this (relatively new to this sort of thing, obviously), but it's definitely something for me to look into more closely. Seems like a good solution. Thanks!
AgentConundrum
+1  A: 

Clean pretty URLs appear to be provided by PHP-script-based popular content management system Drupal using a combination of modrewrite rules in .htaccess and plug-in PHP Drupal modules such as path and pathauto.

Given the success and popularity of this tool - and its ability to run on the most modest of shared hosting, I think this would be your answer.

Rob
I looked at WordPress since that's what I use on my blog (i.e. I have the source easily accessible), but I didn't think of checking out the Drupal source. WordPress is fairly well known to have some ugly code, so Drupal (being a better written, or so I've heard, yet similar platform should have been on my short list of code to review. Thanks for planting this suggestion in my head!
AgentConundrum
+2  A: 

Use option #2 - why? RewriteRules in .htaccess are powerful tool, but they're some kind of static. I mean you cannot easily manage then using PHP (or whatever you're going to use). Also .htaccess doesn't provide so much flexibility, but has some advantages (for example: it's a bit faster).

Option #2 also need .htaccess as you noticed, but in most cases RewriteRule takes the following form:

RewriteRule (.\*) index.php

Where index.php is your front controller.

The biggest advantage (IMO) of this soultion is that each route is described in PHP (or whatever you use) so accessing these routes, modifying them is much easier. Furthermore these routes can be used then not only for changing URL into set of variables, but also in opposite way - to create URL from set of variables.

I think the following example (from Symfony framework) will explain what I am talking about:

// apps/.../config/routing.yml - Describes routing rules
post:
   url:          /read/:id/:slug
   params:       { module: blog, action: index }
   requirements: { id: \d+, slug: \w+ }

// apps/.../modules/blog/templates/indexSuccess.php - template for index action
<?php echo link_to($post['title'], '@post?id=' . $post['id'] . '&slug=' . $post['slug']); ?>
//creates: <a href="/read/123/my-first-blog-post.html">My first blog post</a>

Now whenever you change your rounting.yml file and change /read/:id/:slug into /:slug_:id all your links in application will turn into /my-first-blog-post_123.html.

Doing such and others things when you use option #2 is much easier.

Crozin