PHP: 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 application floating around on Twitter is this one written by jaisen. Its a good start but had some things i would do different.

Goals

Let me start with what i wanted to achieve:
- Write a simple to use PHP Class for saving, shortening and redirecting URLs.
- URLs should be stored in a MySQL database.
- Number of URLs should not be limited too early.
- No duplicate URL entry's in database.
- A simple hit counter for each URL.
- Short URL should be case-insensitive.

Source

Link to the source: http://juliusbeckmann.de/classes/src/url_shortener/url_shortener.zip
And direct source view: http://juliusbeckmann.de/classes/src/url_shortener/

Documentation

Here you can find the documentation: http://juliusbeckmann.de/classes/

Demo

A live demo of my class: http://juliusbeckmann.de/url_shortener/

Process of developing

Some people think that a URL shortener somehow shortens a long URL like "http://google.com" to something like "b7ic3". There is no compression done, the URL will be stored in a database with the unique key "b7ic3". This is the whole magic.

Main problem of this concept, how do we generate the key "b7ic3"? I saw some functions that can do that but i decided to use the PHP build in function base_convert(). I use this function to convert a number like 1234 to its base 36 (a..z and 0..9) equivalent "ya". One downside of this function is, that only lowercase chars will be generated which will result in a lower "compress ratio". But this is wanted because some programs like the original ICQ Chat client sometimes handles case-sensitive URLs incorrect. It is also easier to spell case-insensitive URL on the phone.
The principle with the short URL key works like this:
We insert a new URL to our database and use mysql_insert_id() to get the next id given away from AUTO INCREMENT. This decimal number will be converted to the equivalent base 36 one, and viola - we have our unique key. I know this method is not the best if old URLs get deleted, but it will work always and there will be no duplicate keys.

I build in a special security feature that is often forgotten or even unknown.

$url = str_ireplace(array("\n","\r","\t"), '', $url);

This is important. If an attacker would be able to inject newlines to our url, he could change the "Location: "-Header and create a second request answer.

Options

If you want to use a different base, just configure this parameter:

var $key_base = 36;

Possible values are from 2 up to 36.

I also build in a URL validation. This is to prevent that URLs other than http or https are shortened. To change this validation configure this parameter:

var $regex_valid_url = '@http(s?):\/\/@';

If you want to define bad words or even whole URLs, use this parameter. Each URL that contains a word from this list will not be shortened:

var $url_parts_forbidden = array('http://www.example.com');

Methods

The whole class has only 5 public methods.

function new_redirect($url)

This function creates a new short URL. If the URL is already in the database no new entry will be made. This function will return a array with all relevant data inside, or an empty array on error.

function get_redirect($key)

This function will give you the data for a specific key. The return is the same data like new_redirect().

function log_redirect($key)

If you want to log redirect hits, just call this method and the hit counter for this key will be +1.

function get_redirect_count($key)

If you want to know how much hits a key already got, use this method.

function count_urls()

Simply returns the number of URLs in our database.

Table structure

Here is the table structure my class uses:

CREATE TABLE IF NOT EXISTS `url_redirect` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `url` varchar(255) NOT NULL,
  `md5` char(32) NOT NULL,
  `ts` int(10) UNSIGNED NOT NULL,
  `ip` int(10) UNSIGNED NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `md5` (`md5`)
) ENGINE=MyISAM AUTO_INCREMENT=1000 ;

The id column will be used to identify a URL. The principle is easy. If the key is "ya", the URL with the id 123 is asked. There is also a md5 column in which the md5 of the URL will be stored. This is done for faster searching on duplicate URLs and to validate if a URL is still correct.
Some additional data like timestamp and ip are also stored. ip is stored in a shorter format.

If you want to log the number of hits, this is the used table structure:

CREATE TABLE IF NOT EXISTS `url_hits` (
  `id` BIGINT UNSIGNED NOT NULL ,
  `hits` BIGINT UNSIGNED NOT NULL ,
  PRIMARY KEY (`id`)
) ENGINE = MYISAM;

It is important to say that we need a second table for this because otherwise we would write instantly to the table MySQL needs to read from. This would lead to serious performance troubles.

I inserted about 100.000 URLs, each with at least one hit. The whole database needed about 17MB of space, which are ~180 Byte per URL. This is a good value if you think how much information is saved.

Last Words

Es you can see, the class has all functions needed for a simple and secure URL shortener. You can find a short example index.php with htaccess in the source dir. If you find mistakes or errors, please write a comment.

No related posts.


 
 
 

5 Kommentare zu “PHP: Create your own url shortener with this easy to use PHP Class”

  1. Philippe 3. Mai 2012 um 12:36

    Thank for all, your class is the only one fully documented and ready to use. I use it, and i talk of you on my blog ;-)

  2. Philippe 3. Mai 2012 um 12:44

    Hello, i have a question

    i want too have an url like : short.mywebsite.com
    the folder of the sub domaine is mywebsite.com/short

    i can't make the htaccess work. Can you help me ?

    Thank for all

    Philippe

  3. Julius 10. Mai 2012 um 20:39

    You need a "VHost" for your Webserver and a A-DNS-Record for your Domain to get "short.mywebsite.com" working.

  4. someone 25. September 2012 um 04:13

    there XSS vulnerability in your code...
    try with this;

  5. Julius 3. Oktober 2012 um 08:11

    Do you have a full example, please?