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.

 

QUICK NOTES

  • Tested on a WAMP8 server only – IIS and NGINX users, translate your own .htaccess.
  • Create a database and import 1-database.sql.
  • Change the database settings 2a-shorten.php to your own.
  • Register your own test URL in 2b-dummy.php.
  • If not deployed at root, edit .haccess. For example, http:/site.com/GO/WHATEVER-CODE:
    • Change to RewriteBase /GO/.
    • Change to RewriteRule /GO/ 3-index.php [L]
  • That’s all. Access http://site.com/WHATEVER-CODE and it should redirect.
If you spot a bug, feel free to comment below. I try to answer short 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.

 

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.

 

 

PHP MYSQL 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` (
  `short` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  `full` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 
ALTER TABLE `short_url`
  ADD PRIMARY KEY (`short`),
  ADD KEY `url_long` (`full`);

That’s right, only 2 fields.

  • short The “URL shortcode”, primary key. Take note, this is case sensitive.
  • full The full URL to redirect to.

 

 

STEP 2) SHORTEN URL PHP LIBRARY

2a-shorten.php
<?php
class Shorten {
  // (A) CONSTRUCTOR - CONNECT TO THE DATABASE
  private $pdo = null;
  private $stmt = null;
  public $error;
  function __construct () {
    try {
      $this->pdo = new PDO(
        "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHAR,
        DB_USER, DB_PASSWORD, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
      ]);
    } catch (Exception $ex) { exit($ex->getMessage()); }
  }

  // (B) DESTRUCTOR - CLOSE DATABSE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }
 
  // (C) HELPER - EXECUTE SQL QUERY
  function exec ($sql, $data=null) {
    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($data);
      return true;
    } catch (Exception $ex) {
      $this->error = $ex->getMessage();
      return false;
    }
  }
 
  // (D) HELPER - RANDOM STRING
  // CREDITS: https://stackoverflow.com/questions/4356289/php-random-string-generator
  function rand ($length=6) {
    $char = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~";
    $clen = strlen($char);
    $rand = "";
    for ($i=0; $i<$length; $i++) { $rand .= $char[rand(0, $clen-1)]; }
    return $rand;
  }
 
  // (E) GET BY SHORT URL CODE
  function getS ($short) {
    return $this->exec(
      "SELECT `full` FROM `short_url` WHERE `short`=?", [$short]
    ) ? $this->stmt->fetchcolumn() : false;
  }
 
  // (F) GET BY FULL URL
  function getF ($full) {
    return $this->exec(
      "SELECT `short` FROM `short_url` WHERE `full`=?", [$full]
    ) ? $this->stmt->fetchcolumn() : false;
  }
 
  // (G) DELETE ENTRY
  function del ($short) {
    return $this->exec("DELETE FROM `short_url` WHERE `url_id`=?", [$short]);
  }
 
  // (H) GENERATE A NEW SHORT URL CODE
  function create ($full) {
    // (H1) CHECK IF FULL URL ALREADY EXIST
    if ($this->getF($full) != "") {
      $this->error = "$full is already defined.";
      return false;
    }
 
    // (H2) GENERATE RANDOM SHORT CODE
    $short = null;
    while ($short === null) {
      $rand = $this->rand();
      if ($this->getS($rand) == "") { $short = $rand; }
    }
 
    // (H3) INSERT ENTRY
    return $this->exec(
      "INSERT INTO `short_url` (`short`, `full`) VALUES (?,?)",
      [$short, $full]
    ) ? $short : false ;
  }
}
 
// (I) DATABASE SETTINGS
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHAR", "utf8");
define("DB_USER", "root");
define("DB_PASSWORD", "");
define("URL_PATH_BASE", "/");
 
// (J) INIT
$_SURL = new Shorten();

Yikes, this library looks pretty massive at first. But keep calm and look carefully.

  • (A & B) The Constructor connects to the database when new Shorten() is created, the destructor closes the connection.
  • (C & D) Helper functions.
    • exec() Runs an SQL query.
    • rand() Generates a random string.
  • (E & F) – Get URL entries from the database.
    • getS() Give the short URL code, get the full URL.
    • getF() Give the full URL, get the short URL code.
  • (G & H)  Create and delete entries.
    • del() Delete the given short URL code.
    • create() Generate a shortcode for the given full URL.
  • (I & J) – Self-explanatory.

That’s all, pretty much just SQL queries. Remember to change the database settings to your own.

 

 

EXTRA) CREATE DUMMY SHORT URL CODE

2b-dummy.php
<?php
// (A) ADD ENTRIES
require "2a-shorten.php";
$short = $_SURL->create("https://code-boxx.com");
echo $short==false ? $_SURL->error : $short;

// (B) TO DELETE
// echo $_SURL->del(SHORT) ? "OK" : $_SURL->error ;

Now that the library is in place – Go ahead and create your first short URL.

 

STEP 3) REDIRECTION

HTACCESS FILE

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

This is “borrowed” from WordPress. What this does:

  • Redirect http://site.com/WHATEVER-CODE to 3-index.php.
  • But leave all existing files and folders alone.

Take note – the mod_rewrite module must be enabled in Apache for this to work.

P.S. IIS and NGINX users, you have to “translate” this on your own.

 

 

INDEX PAGE

3-index.php
<?php
// (A) GET SHORT URL CODE
$short = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$short = explode("/", trim($short, "/"));
$short = count($short)==1 ? $short[0] : null ;
$full = null;
 
// (B) GET FULL URL
if ($short!==null) {
  require "2a-shorten.php";
  $full = $_SURL->getS($short);
}
 
// (C) REDIRECT IF VALID
if ($full!==null) { header("Location: $full"); }
else { echo "INVALID REQUEST"; }

Finally, this should be straightforward:

  1. Get the “shortcode section” from the URL.
  2. Check the shortcode against the database.
  3. Redirect if valid.

 

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.

 

I DON’T WANT TO REDIRECT!

  • Store your file name in the database table full.
  • Update section C of 3-index.php – If valid, require $full instead of redirecting.
  • This pretty much becomes a “pretty URL” instead. See link below.

 

A POSSIBLE ISSUE

Here is a small possible problem that I foresee in create() of 2-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->getS($rand) == "").

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, even at 6 characters, there are billions of unique shortcodes. So yeah… Unless you are serving 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.