Brian Cray ··· Home > Blog > Php > Free PHP URL shortener script that kicks ass

Free PHP URL shortener script that kicks ass

After seeing some of the other coding approaches to personal short URL services, I decided to write my own PHP URL shortener script and share it with the world.

Benefits

Installation

  1. Make sure your server meets the requirements:
    • Optionally you can run this from your current domain or find a short domain
    • Apache
    • PHP
    • MySQL
    • Access to run SQL queries for installation
  2. Download a .zip file of the PHP URL shortener script files
  3. Upload the contents of the .zip file to your web server
  4. Update the database info in config.php
  5. Run the SQL included in shortenedurls.sql. Many people use phpMyAdmin for this, if you can't do it yourself contact your host.
  6. Rename rename.htaccess to .htaccess
  7. If you want to use the caching option, create a directory named cache with permissions 777

Using your personal URL shortener service

To manually shorten URLs open in your web browser the location where you uploaded the files. You should see a simple form to add your url, which will return a shortened version.

To programmatically shorten URLs with PHP use the following code:

$shortenedurl = file_get_contents('http://yourdomain.com/shorten.php?longurl=' . urlencode('http://' . $_SERVER['HTTP_HOST']  . '/' . $_SERVER['REQUEST_URI']));

A look at the PHP code for curious programmers

Shorten.php - Script shortens URLs

<?php
/*
 * First authored by Brian Cray
 * License: http://creativecommons.org/licenses/by/3.0/
 * Contact the author at http://briancray.com/
 */

ini_set('display_errors', 0);

$url_to_shorten = get_magic_quotes_gpc() ? stripslashes(trim($_REQUEST['longurl'])) : trim($_REQUEST['longurl']);

if(!empty($url_to_shorten) && preg_match('|^https?://|', $url_to_shorten))
{
    require('config.php');

    // check if the client IP is allowed to shorten
    if($_SERVER['REMOTE_ADDR'] != LIMIT_TO_IP)
    {
        die('You are not allowed to shorten URLs with this service.');
    }
    
    // check if the URL is valid
    if(CHECK_URL)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url_to_shorten);
        curl_setopt($ch,  CURLOPT_RETURNTRANSFER, TRUE);
        $response = curl_exec($ch);
        curl_close($handle);
        if(curl_getinfo($ch, CURLINFO_HTTP_CODE) == '404')
        {
            die('Not a valid URL');
        }
    }
    
    // check if the URL has already been shortened
    $already_shortened = mysql_result(mysql_query('SELECT id FROM ' . DB_TABLE. ' WHERE long_url="' . mysql_real_escape_string($url_to_shorten) . '"'), 0, 0);
    if(!empty($already_shortened))
    {
        // URL has already been shortened
        $shortened_url = getShortenedURLFromID($already_shortened);
    }
    else
    {
        // URL not in database, insert
        mysql_query('LOCK TABLES ' . DB_TABLE . ' WRITE;');
        mysql_query('INSERT INTO ' . DB_TABLE . ' (long_url, created, creator) VALUES ("' . mysql_real_escape_string($url_to_shorten) . '", "' . time() . '", "' . mysql_real_escape_string($_SERVER['REMOTE_ADDR']) . '")');
        $shortened_url = getShortenedURLFromID(mysql_insert_id());
        mysql_query('UNLOCK TABLES');
    }
    echo BASE_HREF . $shortened_url;
}

function getShortenedURLFromID ($integer, $base = ALLOWED_CHARS)
{
    $length = strlen($base);
    while($integer > $length - 1)
    {
        $out = $base[fmod($integer, $length)] . $out;
        $integer = floor( $integer / $length );
    }
    return $base[$integer] . $out;
}

Redirect.php - Script handles short url redirects

<?php
/*
 * First authored by Brian Cray
 * License: http://creativecommons.org/licenses/by/3.0/
 * Contact the author at http://briancray.com/
 */

ini_set('display_errors', 0);

if(!preg_match('|^[0-9a-zA-Z]{1,6}$|', $_GET['url']))
{
    die('That is not a valid short url');
}

require('config.php');

$shortened_id = getIDFromShortenedURL($_GET['url']);

if(CACHE)
{
    $long_url = file_get_contents(CACHE_DIR . $shortened_id);
    if(empty($long_url) || !preg_match('|^https?://|', $long_url))
    {
        $long_url = mysql_result(mysql_query('SELECT long_url FROM ' . DB_TABLE . ' WHERE id="' . mysql_real_escape_string($shortened_id) . '"'), 0, 0);
        @mkdir(CACHE_DIR, 0777);
        $handle = fopen(CACHE_DIR . $shortened_id, 'w+');
        fwrite($handle, $long_url);
        fclose($handle);
    }
}
else
{
    $long_url = mysql_result(mysql_query('SELECT long_url FROM ' . DB_TABLE . ' WHERE id="' . mysql_real_escape_string($shortened_id) . '"'), 0, 0);
}

if(TRACK)
{
    mysql_query('UPDATE ' . DB_TABLE . ' SET referrals=referrals+1 WHERE id="' . mysql_real_escape_string($shortened_id) . '"');
}

header('HTTP/1.1 301 Moved Permanently');
header('Location: ' .  $long_url);
exit;

function getIDFromShortenedURL ($string, $base = ALLOWED_CHARS)
{
    $length = strlen($base);
    $size = strlen($string) - 1;
    $string = str_split($string);
    $out = strpos($base, array_pop($string));
    foreach($string as $i => $char)
    {
        $out += strpos($base, $char) * pow($length, $size - $i);
    }
    return $out;
}

config.php - Configures the URL shortener

<?php
/*
 * First authored by Brian Cray
 * License: http://creativecommons.org/licenses/by/3.0/
 * Contact the author at http://briancray.com/
 */

// db options
define('DB_NAME', 'your db name');
define('DB_USER', 'your db usernae');
define('DB_PASSWORD', 'your db password');
define('DB_HOST', 'localhost');
define('DB_TABLE', 'shortenedurls');

// connect to database
mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
mysql_select_db(DB_NAME);

// base location of script (include trailing slash)
define('BASE_HREF', 'http://' . $_SERVER['HTTP_HOST'] . '/');

// change to limit short url creation to a single IP
define('LIMIT_TO_IP', $_SERVER['REMOTE_ADDR']);

// change to TRUE to start tracking referrals
define('TRACK', FALSE);

// check if URL exists first
define('CHECK_URL', FALSE);

// change the shortened URL allowed characters
define('ALLOWED_CHARS', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

// do you want to cache?
define('CACHE', TRUE);

// if so, where will the cache files be stored? (include trailing slash)
define('CACHE_DIR', dirname(__FILE__) . '/cache/');

.htaccess

DirectoryIndex index.php

# remove the next 3 lines if you see a 500 server error
php_flag register_globals off
php_flag magic_quotes_gpc off
php_value display_errors 0

FileETag none
ServerSignature Off

Options All -Indexes

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^shorten/(.*)$ shorten.php?longurl=$1 [L]
RewriteRule ^([0-9a-zA-Z]{1,6})$ redirect.php?url=$1 [L]
</IfModule>

License and support

This script is provided as is, without warranty or guarantee, licensed under this creative commons license.

I hope you enjoy!

Update: Project added to GitHub! Start adding your own changes to this script! Visit on GitHub