Very Simple URL Shortener With PHP MySQL – Free Code Download

Welcome to a tutorial on how to create a simple URL shortener with PHP and MySQL. Want to share some promotion links and don’t want to use the “common” URL shorteners online? Here’s how you can create your own in just a few steps – Read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Notes URL Shortener Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

QUICK NOTES

If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

QUICKSTART

  1. Create a database and import database.sql.
  2. Change the database settings in section I of shorten.php to your own.
  3. If not deployed in the root folder (E.G. http://site.com/SHORT/):
    • Change .htaccess, set RewriteBase /SHORT/ and RewriteRule . /SHORT/index.php.
    • Change URL_PATH_BASE in shorten.php to /SHORT/ as well.
  4. Run test.php to create a dummy test entry.
  5. That’s it. Access http://site.com/CODE and it should redirect.

 

 

URL SHORTENER

All right, let us now get into some details of the URL shortener with PHP and MySQL.

 

STEP 1) THE DATABASE

database.sql
CREATE TABLE `short_url` (
  `url_id` bigint(20) NOT NULL,
  `url_long` text NOT NULL,
  `url_code` varchar(16) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 
ALTER TABLE `short_url`
  ADD PRIMARY KEY (`url_id`),
  ADD UNIQUE KEY `url_code` (`url_code`),
  ADD UNIQUE KEY `url_long` (`url_long`) USING HASH;
 
ALTER TABLE `short_url`
  MODIFY `url_id` bigint(20) NOT NULL AUTO_INCREMENT;

First, we start with creating a short_url database table to store all the URLs. Very simple with only 3 fields:

Field Description
url_id The primary key, just a running number.
url_long The full URL.
url_code The “shortcode URL”, that is – http://your-site.com/SHORTCODE.

 

 

STEP 2) SHORTEN URL PHP LIBRARY

shorten.php
<?php
class Shorten {
  // (A) PROPERTIES
  private $pdo = null;
  private $stmt = null;
  public $error;

  // (B) CONSTRUCTOR - CONNECT TO THE DATABASE
  function __construct () {
    try {
      $this->pdo = new PDO(
        "mysql:host=". DB_HOST .";dbname=". DB_NAME .";charset=". DB_CHARSET,
        DB_USER, DB_PASSWORD, [
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
          PDO::ATTR_EMULATE_PREPARES => false
        ]
      );
    } catch (Exception $ex) { exit($ex->getMessage()); }
  }

  // (C) DESTRUCTOR - CLOSE DATABSE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }

  // (D) GET BY LONG URL
  function getLong ($url) {
    $this->stmt = $this->pdo->prepare("SELECT * FROM `short_url` WHERE `url_long`=?");
    $this->stmt->execute([$url]);
    $url = $this->stmt->fetch();
    return is_array($url) ? $url : false ;
  }

  // (E) GET BY SHORT CODE
  function getShort ($code) {
    $this->stmt = $this->pdo->prepare("SELECT * FROM `short_url` WHERE `url_code`=?");
    $this->stmt->execute([$code]);
    $url = $this->stmt->fetch();
    return is_array($url) ? $url : false ;
  }

  // (F) GENERATE RANDOM STRING
  // CREDITS: https://stackoverflow.com/questions/4356289/php-random-string-generator
  function rand ($length = 6) {
    $char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $clength = strlen($char);
    $rand = '';
    for ($i = 0; $i < $length; $i++) { $rand .= $char[rand(0, $clength - 1)]; }
    return $rand;
  }
 
  // (G) GENERATE A NEW SHORT CODE FOR GIVEN URL
  function create ($url, $safe=true) {
    // (G1) "SAFE MODE" - DO NOT OVERRIDE LONG URL
    if ($safe) { if ($this->getLong($url) !== false) {
        $this->error = "$url is already defined.";
        return false;
      }
    }
    
    // (G2) GENERATE + CHECK RANDOM SHORT CODE
    $code = null;
    while ($code === null) {
      $rand = $this->rand();
      if ($this->getShort($rand) === false) { $code = $rand; }
    }

    // (G3) REPLACE ENTRY
    try {
      $this->stmt = $this->pdo->prepare("REPLACE INTO `short_url` (`url_long`, `url_code`) VALUES (?, ?)");
      $this->stmt->execute([$url, $code]);
      return $code;
    } catch (Exception $ex) {
      $this->error = $ex->getMessage();
      return false;
    }
  }

  // (H) DELETE ENTRY
  function del ($id) {
    try {
      $this->stmt = $this->pdo->prepare("DELETE FROM `short_url` WHERE `url_id`=?");
      $this->stmt->execute([$id]);
      return true;
    } catch (Exception $ex) {
      $this->error = $ex->getMessage();
      return false;
    }
  }
}

// (I) DATABASE SETTINGS
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_CHARSET', 'utf8');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
define('URL_PATH_BASE', '/');

// (J) INIT
$_SHOURL = new Shorten();

Yes, this library looks pretty massive at first. But keep calm and look carefully, all it does is pretty much SQL queries.

  • A, B, C – The Constructor connects to the database when new Shorten() is created, the destructor closes the connection.
  • D, E – Get entries from the database.
  • F, G, H – Create and delete entries.
  • I, J – Settings and starting the “engine”.

 

 

STEP 3) REDIRECTION

HTACCESS FILE

.htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

With the foundations in place, all that’s left is to create the “shortcode redirection” itself. How we do that, is to redirect http://site.com/WHATEVER-CODE to index.php. Take note – the mod_rewrite module must be enabled in Apache for this to work. IIS and NGINX users… You have to “translate” this on your own.

INDEX PAGE

index.php
<?php
// (A) LOAD SHORTEN URL LIBRARY
require "shorten.php";

// (B) STRIP PATH DOWN TO AN ARRAY
// E.G. HTTP://SITE.COM/HELLO/WORLD/ > $_PATH = ["HELLO", "WORLD"]
$_PATH = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if (substr($_PATH, 0, strlen(URL_PATH_BASE)) == URL_PATH_BASE) {
  $_PATH = substr($_PATH, strlen(URL_PATH_BASE));
}
$_PATH = rtrim($_PATH, '/');
$_PATH = explode("/", $_PATH);

// (C) "ERROR CHECKING" + REDIRECTION
$basecount = substr_count(URL_PATH_BASE, "/");
// (C1) INVALID PATH
if (count($_PATH) != $basecount) { exit("INVALID URL"); }
else {
  // (C2) EMPTY PATH
  $shortcode = $_PATH[$basecount-1];
  if ($shortcode=="") { exit("INVALID URL"); }
  
  // (C3) GET FULL URL
  $url = $_SHOURL->getShort($shortcode);
  if ($url===false) { exit("INVALID URL"); }

  // (C4) REDIRECT
  header("Location: ".$url['url_long']);
  exit();
}

Finally, in index.php

  • We strip the request URI into an array. For example, http://site.com/AB123C into $_PATH = ["AB123C"].
  • Take that shortcode, check against the database.
  • Redirect to the long URL if found, throw an “invalid URL” error if not.

That’s all for the entire URL shortener.

 

 

USEFUL BITS & LINKS

That’s all for the main tutorial, and here is a small section on some extras and links that may be useful to you.

 

A POSSIBLE ISSUE

Here is a small possible problem that I foresee in section G2 of shorten.php.

  • The shortcode is generated using a random string generator $rand = $this->rand().
  • It is then checked against the database to make sure there are no duplicate shortcodes if ($this->getShort($rand) === false).

Yes, this works. But when the number of shortcodes grows over time, the chances of hitting duplicates get higher. This segment will end up looping more to generate a unique shortcode.

But the good news is, at 6 alphanumeric characters, there are 626 = 56,800,235,584‬ possible unique shortcodes. So yeah… Unless you are storing the entire world, this is not going to be a big issue.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *