3

What is the best way to create user vanity URLs under a LAMP configuration?

For example, a user profile page could be accessed as follows:

http://www.website.com/profile.php?id=1

Now, if a user enters a "vanity URL" for their profile I would want the the vanity URL to load the page above.

For example, if a user selects "i.am.a.user" as their vanity URL and their user id in the database is 1 then http://www.website.com/profile.php?id=1 would be accessible by that URL and http://www.website.com/i.am.a.user .

I'm aware of mod rewrites in .htaccess but not sure how that would work here.

As I mentioned my site is in PHP, MySQL, Linux and Apache.

Thanks.

Tom
  • 4,467
  • 17
  • 59
  • 91

4 Answers4

4

Rewrite for site.com/user/USERNAME:

In your root web directory, place a .htaccess file:

RewriteEngine on
RewriteRule ^user/(.+)$ profile.php?name=$1 [L]

This routes all requests that starts with "user" to profile.php and pass the URI to $_GET['name']. This method is preferred if you have a lot of files / directories / other rewrites.

Rewrite for site.com/USERNAME:

RewriteEngine on
# if directory or file exists, ignore
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ profile.php?name=$1 [L]

This routes to profile.php ONLY if the requesting file or directory does not exists, AND when the request URI is not empty (ie, www.site.com)

PHP backend

Now in profile.php, you can have something like this:

if (!empty($_GET['name'])
    $user = ... // get user by username
else 
    $user = ... // get user by id
jlee
  • 492
  • 5
  • 15
  • I wouldn't recommend that, as if you don't have the /user/ part, the htaccess file would either get really messy, or the entire url after your domain will be passed to `$_GET('name')` – Pwnna May 04 '11 at 02:01
  • How does Facebook do it then? They are running LAMP. Sure it's on a massive scale but the concept should be the same. – Tom May 04 '11 at 02:05
  • Have a look at http://martinmelin.se/rewrite-rule-tester/ to test your mod_rewrite setup (disclaimer: only just found that site, but I wish I had thought to look a couple of years ago). – Rebecca Scott May 04 '11 at 02:08
  • The concept is similar, however you are then stuck with one PHP script that handles all requests. So you have to check on every request if a valid user shortcut exists, otherwise find the correct page. – clmarquart May 04 '11 at 02:08
  • @Tom: You'll just have a DB table with URL/PHP pages pairs and check against that. – nico May 04 '11 at 05:44
  • @Tom, edited post to add rewrite for site.com/USERNAME as per your request. – jlee May 04 '11 at 05:45
  • @jsunlee - How would I protect against a 404 like /doesnotexist.php? Instead of displaying my 404 page, if a user tries to access something like that they get the profile page which then redirects to my home page because there are no valid parameters (id or name)? – Tom May 04 '11 at 13:58
4

Say your other pages had specific URLs that you could check against, the following should help.

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9-_]*)$ /profile.php?user=$1 [L]

This helps to maintain current URLs, while allowing for the user shortcut URLs. Also, the RewriteRule will only match URLs that don't contain a /, which will help protect against non-intended redirects. So,

/i-am-a-user -> MATCHES
/i_am_a_user -> MATCHES
/i-!am-a-user -> NOT MATCHED
/i.am.a.user  -> NOT MATCHED
/i.am.a.user/ -> NOT MATCHED
/some/page/ -> NOT MATCHED
/doesnotexist.php -> NOT MATCHED
/doesnotexist.html -> NOT MATCHED

Hope that helps.

EDIT

I've updated the rules above so that actual files/directories aren't redirected as well as making sure that any .php or .html file is not sent to profile.php either.

clmarquart
  • 4,721
  • 1
  • 27
  • 23
  • How would I protect against a 404 like /doesnotexist.php? Instead of displaying my 404 page, if a user tries to access something like that they get the profile page which then redirects to my home page because there are no valid parameters (id or name)? – Tom May 04 '11 at 13:57
  • @Tom, I've updated the rule so that it will only match requests without a `/` and without `.`. Just realized though that now `i.am.a.user` will not work, whereas `i-am-a-user` would. I'll tweak it again... – clmarquart May 04 '11 at 14:07
  • Yeah, I think if we can get that rule to work with "." we will have a solution. – Tom May 04 '11 at 14:19
  • I actually went back to your original as I don't think I will be allowing users to choose a vanity URL with "." in them. Could that RegEx be modified to only allow for vanity URLs with alphanumeric characters and dashes? Something like /iam!invalid should map trigger a 404 while /iam-valid would not. Man, I hate to keep tweaking like this but I am just awful with regular expressions. – Tom May 04 '11 at 14:30
  • No problem :) Updated it again, should now only include non-existent, alpha-numeric URLs – clmarquart May 04 '11 at 14:39
  • Thanks again, however that updated code gives a 500 Internal Server Error across the board on every request =) – Tom May 04 '11 at 14:42
  • Can you make sure that no extra spaces were copied in? Also, if you're putting the `RewriteRule` in the apache config and not a `.htaccess` file, you will need a leading slash `RewriteRule ^\/([a-zA-Z0-9-_]*)$ /profile.php?user=$1 [L]` – clmarquart May 04 '11 at 14:49
  • @clm - Pretty sure there are no leading spaces and I'm putting the RewriteRule in an .htaccess file... – Tom May 04 '11 at 14:57
  • Interesting...those 3 lines work for me as-is. The previous rule (`RewriteRule ^([^\/]*)$ /profile.php?user=$1`) worked though? Do you have other rules? Also, make sure there are no spaces in the `[L]` section of the rule, any space between the `[]` brackets will cause 500 errors. – clmarquart May 04 '11 at 15:04
  • I do have other rules but your code doesn't work even if I take them all out and just leave yours, still get the 500 error. Here's my .htaccess in its entirety: https://docs.google.com/document/d/1Eo_GQOZMd-zEWDvZCfEGqJCGRQjlKTYPGnH0Morj4PI/edit?hl=en&authkey=CM6TytMH – Tom May 04 '11 at 15:15
  • Try adding `RewriteBase /` after the `RewriteEngine on` line. I tried your full `.htaccess` and it works for me without the 500 error. Can you check your logs and see if anything stands out? If you change back to the previous rule allowing `.`, does it work again? – clmarquart May 04 '11 at 15:29
  • The old rule works. When I check the error log I see this for the new rule: `[Wed May 4 11:39:47 2011] [alert] [client 12.248.68.70] /home/torrillo/public_html/development/.htaccess: RewriteRule: cannot compile regular expression '^([a-zA-Z0-9-_]*)$'\n` – Tom May 04 '11 at 15:42
  • Try: `RewriteRule ^([a-zA-Z0-9\-\_]*)$ /profile.php?user=$1 [L]` – clmarquart May 04 '11 at 15:45
  • That did it. I tweaked it to just allow for alphanumeric and dashes. If I could give you twenty check marks I would, thanks a million =) – Tom May 04 '11 at 15:56
  • Glad it worked! 1 check is good..but, hey, if one of those up-votes isn't yours, that would be appreciated :) – clmarquart May 04 '11 at 15:58
1

First setup your .htaccess file to send all requests for files and directories that don't exist to a single php file:

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) router.php [NC,L]

Then inside your router.php, look at $_SERVER['REQUEST_URI'] to get the username that you can then use in your query to get the data about the user.

This assumes that all URLs that are not user profile pages exist as physical files on your server.

If that's not the case, you can do some logic in router.php to decide what to do on each request. Do a google search for url routing in php and you'll get plenty of examples.

bradym
  • 4,880
  • 1
  • 31
  • 36
1

Well, you could solve this using an apache RewriteMap as well of course. The RewriteMap can be a plain text file (that you update regularly based on what your users enter), or alternatively you could point it to a script (Perl, PHP, whatever suits you) to do the rewriting for you.

For a quick summary on how to set this up using PHP refer to Using a MySQL database to control mod_rewrite via PHP.

wimvds
  • 12,790
  • 2
  • 41
  • 42