James Cridland

Roll your own shortlinks server

Using bit.ly and all that stuff is all very well; but it's probably not the cleverest plan in the world - because you're not in charge of tr.im or bit.ly or whatever tinyurl server you're using; and they could go out of business at any time.

So, here's the code I use on muk.fm. http://muk.fm/1 for example redirects off to my own website.

This script:
- is designed to be nice and quick to deploy and use
- is made to keep load on your shortlinks server very low indeed (utilising caching wherever possible)
- should never give the same URL more than one shortlink
- has an API which mimics the tinyurl response (a plain-text response) and works with Tweetie2
- has only one API key because it's designed for your own personal shortlinks server
- does not keep statistics or anything like that

This requires PHP (v4 or above should be fine) and MySQL. Installation instructions are at the bottom.

<?

// Quick and dirty shortlinks server
// v0.1: first public release
// http://james.cridland.net/code/
// james@cridland.net
// Installation instructions at the bottom of this file

// Configuration block (you'll need to change this)
$config['database_location']='localhost';
$config['database_username']='username';
$config['database_password']='password';
$config['database_name']='databasename';
$config['default_website']='http://www.mediauk.com/'// Where we go if we have no link given
$config['api_key']='123456'// This -must- be six characters long.

// The rest of the code follows. You don't need to change this.
//
// Have fun
//


// Config check in case you can't read
if (strlen($config['api_key'])<>6) { die("Webmaster: The API key must be six characters long in your config."); }

// Set the headers. These links are perma-links and thus will never expire.
// For the world, they all expire next Monday (and were built last Monday).
header("Expires: " gmdate('D, d M Y H:i:s'strtotime('next Monday')) . ' GMT');
header("Last-Modified: " gmdate('D, d M Y H:i:s'strtotime('last Monday') ) . ' GMT');

if (
trim($_SERVER['REQUEST_URI'])=="/") {
    
// We have been asked for nothing. So let's just pop off to the default website.
    
header('Location: '.$config['default_website'], TRUE301);
    exit;
}

if (
substr($_SERVER['REQUEST_URI'],0,4)=="/api") {
    
// This would be the API, then.
    // http://muk.fm/api/180371/http://www.mediauk.com/

    // This is the key
    
if (substr($_SERVER['REQUEST_URI'],5,6)!=$config['api_key']) {
        die(
"No valid API key given. Format is http://".$_SERVER['HTTP_HOST']."/api/:key/:url");
        }

    
$url=substr($_SERVER['REQUEST_URI'],12);

    
db_connect();

    
$query="INSERT INTO shortlinks (shortlink_url) VALUES ('".mysql_real_escape_string($url)."') ON DUPLICATE KEY UPDATE shortlink_id=LAST_INSERT_ID(shortlink_id),shortlink_dummy=NOT shortlink_dummy;";
    
mysql_query($query);
    
$thing=mysql_query("SELECT LAST_INSERT_ID()");
    
$row=mysql_fetch_row($thing);
    
header('Content-type: text/plain;'TRUE200);
    echo 
'http://'.$_SERVER['HTTP_HOST'].'/'.base_convert($row[0],10,36);
    exit;
}


// Bespoke kludgy bit for muk.fm
if (strpos(substr($_SERVER['REQUEST_URI'],1),'/')>AND $_SERVER['HTTP_HOST']=='muk.fm') {
    
// We have been asked for something with more than one slash.
    // This is a kludgy Media UK shortlink. Apologies for this bit. You can edit this out.
    
header('Location: http://www.mediauk.com/'.substr($_SERVER['REQUEST_URI'],1), TRUE301);
    exit;
}
// End of bespoke kludgy bit for muk.fm


//We've been fed a shortlink.

db_connect();

$query="select shortlink_url from shortlinks where shortlink_id=".mysql_real_escape_string(base_convert(substr($_SERVER['REQUEST_URI'],1),36,10)).";";
$page=mysql_query($query);

if (!
mysql_numrows($page)) {
    
// No page found at all, oh dear oh dear
    
header("HTTP/1.0 404 Not Found"TRUE404);
    echo 
"<HTML><HEAD><TITLE>404 page not found</TITLE></HEAD><BODY><h1>Page not found</h1><P>This page wasn't found. Sorry and all.</P><HR><STRONG>muk.fm</STRONG></BODY>";
    exit;
}

else

{
    
//We have a page, so pop off and get it then
    
$page_info=mysql_fetch_object($page);
    
$url=$page_info->shortlink_url;
    
$url=str_replace("%26","&amp;",$url);
    
header('Location: '.$urlTRUE301);
    exit;
}

function 
db_connect() {
    GLOBAL 
$config;
    
$database mysql_connect($config['database_location'],$config['database_username'],$config['database_password']);
    if (!
$database) {
        die(
'Erk. We cannot see the database, which is bad. Try refreshing this page and see if it works then.');
    }
    
$select_db mysql_select_db($config['database_name'],$database);
    }


/*

Setup instructions:

1. Create a shortlinks table in your database. Use this SQL code to achieve this.

CREATE TABLE IF NOT EXISTS `shortlinks` (
  `shortlink_id` int(11) NOT NULL auto_increment,
  `shortlink_url` varchar(255) collate utf8_unicode_ci NOT NULL default '',
  `shortlink_dummy` smallint(6) NOT NULL default '0',
  PRIMARY KEY  (`shortlink_id`),
  UNIQUE KEY `shortlink_url` (`shortlink_url`),
  KEY `shortlink_id` (`shortlink_id`,`shortlink_url`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=5945 ;


2. Write an .htaccess file in the root of your shortlinks webserver. It should read like this:

Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)$ index.php?i=%1

... this redirects absolutely every single thing called to this script.

3. Edit the configuration variables at the top of this file to suit.

4. Save this file as 'index.php' in the root of your shortlinks webserver.

5. Profit.

*/


?>

Download this code