Create short urls for your website

Posted on Saturday October 01, 2011 / by Eric Potvin

On September 12st, Dbugger from StackOverFlow asked how to redirect short/custom URLs to create tinyurl-like service for my company. The solution was easy to share since I already implemented this solution for my site. Here's in details how I did it.

Create and setup the sub-domain/domain

You can either register a new domain (like Google do, goo.gl) or create a sub-domain. In this article, will use the go.domain.com example. For either solution, you will have to point this domain/sub-domain DNS to your server.

Setup folder and VirtualHost

Once the DNS is setup, this new domain or sub-domain will have to point to a different web root other than the main one. This will simplify your code, avoid redirect rules if you have some on your current website and many more.

sudo mkdir -p /usr/local/apache/htdocs/shorturl_html/

Let's create the entry in the apache2.conf or httpd.conf (or any other if you have any)

<VirtualHost *:80>
  DocumentRoot "/usr/local/apache/htdocs/shorturl_html/"
  ServerName go.domain.com
  ServerAlias go.domain.com
  <Directory "/usr/local/apache/htdocs/shorturl_html/">
    allow from all
    Options +Indexes
  </Directory>
</VirtualHost>

The Database

Let's create the table we will use to create all the URLs we need to be shorten.

CREATE TABLE `short_urls` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `url` varchar(255) NOT NULL DEFAULT '',
  `short_url` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `short_url` (`short_url`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Example URLs:

INSERT INTO short_urls SET url = 'http://www.domain.com/page/section/', short_url = '3A4ra';

The Code

Now that the DNS, the folder and virtual host are setup, let's see how the code works.

.htaccess

Here's the code you need to put in your /usr/local/apache/htdocs/shorturl_html/.htaccess

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^index\.php
RewriteRule ^([a-z0-9\-]+)(\/?)$ index.php?code=$1 [L,NC,QSA]

*note: You can also put these rules in the VirtualHost configuration

PHP Code

header("Expires: 0");
header("Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0");
header("Pragma: no-cache");

define('BASE_LINK', 'http://www.domain.com/');

if(!isset($_GET['code'])) {
	$_GET['code'] = '';
}

# Validate the code
if(ctype_alnum($_GET['code'])) {

  // Memcached logic here (view note)

  $DB = new PDO('mysql:host=myserver;dbname=mydatabase', 'myuser', 'mypass', array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE));
  $DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
  $DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  $sql = "SELECT `url` FROM `short_urls` WHERE `short_url` = '" . $_GET['code'] . "'";
  $stmt = $DB->query($sql);
  if($DB->errorCode() != '00000') {
    // Log error if you need using $DB->errorCode());
  }
  $data = $stmt->fetch(PDO::FETCH_ASSOC);
  if(!$data) {
    $link = BASE_LINK;
  }
  else {
    $link = $data['url'];
  }
}
else {
  $link = BASE_LINK;
}

# Redirect
header('Location: ' . $link, TRUE, 301);
header("Connection: close");
die();

I recommend to use a caching method, such as MemCached. This way, you will not query the database over and over. Visit Validate if an IP is banned using memcached to view an example.

Conclusion

The short url http://go.domain.com/3A4ra will redirect to: http://www.domain.com/page/section/.

Here's a simple solution for your own URL shortening service.