June
5th, 2009
Writing your own URL shortener in 25 lines of PHP
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).
and living in Sunnyvale, CA.
June 9th, 2009 at 9:23 am
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 .
June 9th, 2009 at 11:34 am
1* 62^0 + 8*62^1 + 12*62^2 + 4*62^3 = 999937
OR
1 + 496 + 46128 + 953312 = 999937
Is that right?
June 9th, 2009 at 11:41 am
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
June 9th, 2009 at 1:58 pm
@Randy, you’re correct. I had j=8 when it should be j=9. I fixed the error. Thanks.
June 9th, 2009 at 2:02 pm
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.
June 10th, 2009 at 7:02 pm
[...] Writing your own URL shortener in 25 lines of PHP :: Jaisen Mathai — 12:09pm via [...]
June 10th, 2009 at 11:38 pm
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.
June 11th, 2009 at 7:50 am
@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.
July 2nd, 2009 at 9:04 am
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.
August 4th, 2009 at 11:13 am
Once I get to key = 0 (after a-z, A-Z) getNextKey(0) returns a instead of 1.
August 4th, 2009 at 11:18 am
What’s weird is getNextKey(“0″) returns “a” but getNextKey(“1″) returns “2″.
August 4th, 2009 at 11:22 am
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.
August 11th, 2009 at 12:39 pm
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.
September 10th, 2009 at 6:35 am
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…
September 10th, 2009 at 6:38 am
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.
September 14th, 2009 at 12:34 am
[...] 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. [...]
October 2nd, 2009 at 12:16 pm
why write your own? my project http://smrls.net/ allows anyone to create a free url shortener.. :)
December 5th, 2009 at 8:06 pm
How about adding a billing system linked to PayPal for selling the offensive words at a premium?
January 22nd, 2010 at 11:51 am
[...] 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? [...]
February 2nd, 2010 at 1:16 pm
[...] 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, [...]
February 6th, 2010 at 5:37 pm
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