views:

109

answers:

3

I finally figured out a good/easy way to make clean URLs with regex on my site in this format below, however it will require a very large .htaccess file, I know from the post on here that it is supposed to not be to bad on performance to use mod_rewrite but I have never really seen it used where the way I am, with a seperate entry for almost every page of my site.

Below is an example of an entry, there is 2 entries for 1 page, the first entry re-writes

http://www.example.com/users/online/friends/
to
http://www.example.com/index.php?p=users.online.friends

It works great but if the user is not on the first page then there is another thing added to the URL for paging and I had to write another entry to rewrite when this happens, is this the correct way or should these be combined somehow?

RewriteRule ^users/online/friends/*$ ./index.php?p=users.online.friends&s=8
RewriteRule ^users/online/friends/(\d+)/*$ ./index.php?p=users.online.friends&s=8&page=$1

The second one would do this

http://www.example.com/users/online/friends/22/
to
http://www.example.com/index.php?p=users.online.friends&page=22

+3  A: 

Yes, that's fine. I guess they could be combined into a single rule but there's not really any need.

You might consider leaving page as part of the URL so instead of:

http://www.domain.com/users/online/friends/22/

just have:

http://www.domain.com/users/online/friends?page=22

and then have one rule something like:

RewriteRule ^users/online/friends/?$ ./index.php?p=users.online.friends&s=8 [L,QSA]

to append the query string

Edit: There are a couple of ways of reducing the number of rewrite rules you have.

Firstly, use wildcards in the search terms, like:

RewriteRule ^users/(\w+)/(\w+)$ /index.php?p=users.$1.$2 [L,QSA]

will reduce quite a number of rules.

Secondly, if you're passing everything through /index.php just consider delegating all requests there:

RewriteRule ^(users/*)$ /index.php/$1 [L,QSA]

That rule uses a third technique: instead of passing the path information via a query string parameter, pass it via the extra path info. That can be accessed via $_SERVER['PATH_INFO'].

That being said, lots of rules isn't necessarily bad. At least it's explicit about all your actions. The thing you have to watch out for is creating a maintenance nightmare however.

cletus
thanks, and do you think it is ok to have a HUGE htaccess file, I will probably have around 120 rewrites at this pace? The s=8 is just my old begginner method I used to destinguish which "online" page I was on to highlight an section menu, like I have online users, onli8ne friends, online girls, online boys and so on, in the user section I would pass something like s=8 to highlight the menu to show that I was on the online friends page in the online users section, i know not the greatest way but 2 years ago when I designed this section, it was a quick fix
jasondavis
If it becomes too slow, you could look at mod_rewrite's RewriteMap instead. It can use a hash table in a file to map URLs. Or an external program you write.
Harold L
+3  A: 

It depends what you think is more readable, but here's how you could do it with a single rule:

RewriteRule ^users/online/friends(/(\d+))?/*$ ./index.php?p=users.online.friends&s=8&page=$2

(Edited to be more faithful to treatment of trailing slash in original question. Was: RewriteRule ^users/online/friends/((\d+)/*)?$ ./index.php?p=users.online.friends&s=8&page=$2)

Here I've just put "(...)?" around the final part of the url to make it an optional match, and changed the backreference to $2.

Of course, this actually rewrites http://www.domain.com/users/online/friends/ as:

http://www.domain.com/index.php?p=users.online.friends&page=

So your PHP code would have to check whether the page parameter is non-empty.

Todd Owen
that is perfect however it gives a 500 error on the server
jasondavis
Sorry, I didn't test it. Could be that the * was in the wrong place...I just edited it.
Todd Owen
thanks that works
jasondavis
+2  A: 
# Initial step
RewriteCond %{QUERY_STRING} !(?:^|&)p=
RewriteRule ^([^/]+)/(.+) /$2?p=$1 [QSA]

# Subsequent steps
RewriteCond %{QUERY_STRING} ((?:[^&]*&)*?)p=([^&]*)(.*)
RewriteRule ^([^/]+)/(.+) /$2?%1p=%2.$1%3

# Last step with page number
RewriteRule ^(\d+)/?$ /index.php?page=$1 [QSA,L]

# Last step without page number
RewriteCond %{QUERY_STRING} (?:((?:[^&]*&)*?)p=([^&]*))?(.*)
RewriteRule ^([^/]+)/?$ /index.php?%1p=%2.$1%3 [L]

This would rewrite the URL in several steps:

  1. http://www.domain.com/users/online/friends/22/
  2. http://www.domain.com/online/friends/22/?p=users
  3. http://www.domain.com/friends/22/?p=users.online
  4. http://www.domain.com/22/?p=users.online.friends
  5. http://www.domain.com/index.php?p=users.online.friends&page=22

An easier method would be the following, but would require you to change your scripts:

RewriteRule ^(.*?)(?:/(\d+))?/?$ /index.php?p=$1&page=$2 [QSA,L]

It would do everything in one step, with a little difference:

  1. http://www.domain.com/users/online/friends/22/
  2. http://www.domain.com/index.php?p=users/online/friends&page=22

Adding the s=8 query argument would require more work:

  1. Creating a text-file with the menu numbers for each page.
  2. Adding a RewriteMap directive.
  3. Changing the second-last rule to use the same RewriteCond as the last rule has.
  4. Adding &s=%{menumap:%2|0} to the last two rules.
MizardX