Web Developer / Blog

June
5th, 2009

Writing your own URL shortener in 25 lines of PHP

Digg this article · Save to del.icio.us · Stumble it!

So you want to write a URL shortener? Let’s make it short and painless. You’ll need two pieces: a key generator and redirector. The key generator is used to represent a shortened url with a series of characters, often a-zA-Z0-9. This is what you see at the end of tinyurl and bit.ly links. The redirector needs to link the key to a url and perform a HTTP redirect. Shall we?

First things first
The source code that I based this post on is available on GitHub.

Generating URL shortener keys
Understanding how to properly generate a key is the most important part of a url shortener. If you get this wrong, you’ll find out that your urls aren’t very short and you can’t go back and fix it. The sequence can be thought of a base 62 sequence (using a-zA-Z0-9). Following this logic, the 1,000,000th sequence would be emjb. Expanding that out would look like the following equation.

// e=4
// m=12
// j=9
// b=1
// 1*62^0 + 9*62^1 + 12*62^2 + 4*62^3 = 999,999

I deviated from this logic when writing the getNextKey function. Nonetheless, it’s good to understand the compactness of the keys. The getNextKey takes a key and calculates the next one. If a key isn’t passed in then it defaults to a.

// don't use globals, put these in a class
$range = array_merge(range('a','z'), range('A','Z'), range(0,9));
$trans = array_flip($range);

function getLastKey()
{
  // fetch last key and return
  return 'a';
}

function getNextKey($key = null, $tail = '')
{
  global $range, $trans; // bad
  if($key === null)
    $key = getLastKey();
  if(empty($key))
    return "a{$tail}";

  $keylen = strlen($key);
  $lastChar = $key[$keylen-1];

  if($lastChar != '9')
    return substr($key, 0, ($keylen-1)) . $range[$trans[$lastChar]+1] . $tail;
  else
    return getNextKey(substr($key, 0, -1), "a{$tail}");
}

Redirecting shortened requests
When a request comes in you need to yank the key from the url, look up its long url and perform the redirect. A sample database schema for storing URLs would look like this:

CREATE TABLE `url_redirect` (
  `ur_id` int(10) unsigned NOT NULL auto_increment,
  `ur_key` varbinary(255) NOT NULL,
  `ur_url` varchar(255) NOT NULL,
  `ur_dateCreated` int(10) unsigned NOT NULL,
  PRIMARY KEY  (`ur_id`),
  UNIQUE KEY `ur_key` (`ur_key`)
);

The next piece is to set Apache up to handle all requests. Place the following, which uses mod_rewrite, into your VirtualHost definition.

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) /index.php?__key__=$1 [L,QSA]

This makes sure all requests are handled by index.php.

$key = addslashes(substr($_GET['__key__'], 1));
$dbh = mysql_connect('localhost', 'root', ''); // bad
$redirect = mysql_fetch_assoc(mysql_query("SELECT ur_id, ur_url FROM url_redirect WHERE ur_key='{$key}'"));

if(!$redirect)
  throw new Exception("Did not find redirect key {$_SERVER['REQUEST_URI']} in database");

header('HTTP/1.1 301 Moved Permanently');
header("Location: {$redirect['ur_url']}");

Wrapping it up
These are the basics of setting up a URL shortener. Their value is a topic of much debate. I personally feel that they do more harm than good. Regardless, they’re here to stay.

You can download these samples on GitHub (http://github.com/jmathai/playground/tree/master).

21 Responses to “Writing your own URL shortener in 25 lines of PHP”

  1. Markandey Singh Says:

    This is gr8 articlte i love it.
    (I have a small complain though)
    Your code snippent pluging is not properly viwed in Chrome.

    Thanks lots and lots of love for this article .

  2. Randy Merrill Says:

    1* 62^0 + 8*62^1 + 12*62^2 + 4*62^3 = 999937

    OR

    1 + 496 + 46128 + 953312 = 999937

    Is that right?

  3. Randy Merrill Says:

    The example is incorrect, it should be:

    // e=4
    // m=12
    // j=9
    // b=1
    // 1*62^0 + 9*62^1 + 12*62^2 + 4*62^3 = 999,999

  4. jaisen Says:

    @Randy, you’re correct. I had j=8 when it should be j=9. I fixed the error. Thanks.

  5. jaisen Says:

    Fyi, some have pointed out that PHP has a native base_convert function that simplifies getting the next key.

    The only drawback is that the base_convert function only works up to base 36. Your urls won’t have as good of compression but your code will be much smaller.

  6. Daily Digest for June 10th | Squirrel Hacker Says:

    [...] Writing your own URL shortener in 25 lines of PHP :: Jaisen Mathai — 12:09pm via [...]

  7. Phil Sturgeon Says:

    You should check for duplicate URL’s within the database before creating a new key for it, will save space as the database gets bigger.

  8. jaisen Says:

    @Phil, good point. The shortner I wrote needed unique entries even if the url already existed in the database. But for general purposes, you’re right, checking the db will help preserve space in the urls.

  9. Thomas Lukasik Says:

    Does anyone handle filtering the random offensive words that will be generated? I’ve never seen any mention of this in any discussion of URL shortening.

  10. Ryan Says:

    Once I get to key = 0 (after a-z, A-Z) getNextKey(0) returns a instead of 1.

  11. Ryan Says:

    What’s weird is getNextKey(”0″) returns “a” but getNextKey(”1″) returns “2″.

  12. Ryan Says:

    It’s because the test empty($key) when $key=0 returns true.

    If I change to if(empty($key)&&$key!=0) then the correct response is returned.

  13. Roonaan Says:

    If you are willing to include slashes as an allow character for your hashes, you could just save your database the stress and use apache multiviews with some basic redirect files in a directory trss as caching structure. Hell, you could just skip out on mysql all together.

  14. Julius Beckmann Says:

    Create your own url shortener with this easy to use PHP Class…

    After using Twitter some time now, i saw several URL shortening services and a few scripts that would do the work. But i did not see any PHP Class for doing this job easily. So i wrote one myself …

    The most mentioned code example for this applicatio…

  15. Julius Beckmann Says:

    Hi there,
    i wrote a nice class for url shortening too, you can find in here:
    http://juliusbeckmann.de/blog/create-your-own-url-shortener-for-twitter-with-this-easy-to-use-php-class.html
    I took few parts of your code and included some ideas from your comments.
    Regards, Julius.

  16. URL-Shortener für den eigenen Webspace | Links, Scripts, Tools, URLs | Dr. Web Magazin Says:

    [...] Writing your own URL-Shortener Der Autor zeigt, wie man einen eigenen URL-Shortener mit nur 25 Zeilen PHP-Code erstellt. Die Kommentatoren verbessern den Beitrag. [...]

  17. maurice Says:

    why write your own? my project http://smrls.net/ allows anyone to create a free url shortener.. :)

  18. Mike Says:

    How about adding a billing system linked to PayPal for selling the offensive words at a premium?

  19. How to write your own URL shortener in 25 lines of PHP code « Web Page Authority Blog Says:

    [...] Writing your own URL shortener in 25 lines of PHP :: Jaisen Mathai So you want to write a URL shortener? Let’s make it short and painless. You’ll need two pieces: a key generator and redirector. The key generator is used to represent a shortened url with a series of characters, often a-zA-Z0-9. This is what you see at the end of tinyurl and bit.ly links. The redirector needs to link the key to a url and perform a HTTP redirect. Shall we? [...]

  20. URL-Shortener-Skripte | datenstreifen.org Says:

    [...] Angebote wie a.ndy.li zu gestalten. Einige Tutorials wie How To Create Your Own URL Shortener oder Writing your own URL shortener in 25 lines of PHP können vielleicht manch einem schon weiter helfen, jedoch wahrscheinlich nicht der breiten Masse, [...]

  21. Helen Dangote Says:

    Thanks for this piece of code. I’m new to your blog and have already found it quite informative. I particularly like this URL shortner example, and will definitely spend time to improve and post back here.

    Thanks again

Leave a Reply


About this site:
This is my (Jaisen Mathai) personal site for potential employers who want to see my resume or portfolio. My ideal job would be to work as a Web developer on a large scale consumer website. My experience is in using PHP, MySQL, Ajax and JSON. I really enjoy creative brainstorming...taking a problem apart and narrowing 100 solutions down to the best one.

Thanks for stopping by. Be sure to drop me a line.