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
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
- Create a database and import
database.sql
. - Change the database settings in section I of
shorten.php
to your own. - If not deployed in the root folder (E.G.
http://site.com/SHORT/
):- Change
.htaccess
, setRewriteBase /SHORT/
andRewriteRule . /SHORT/index.php
. - Change
URL_PATH_BASE
inshorten.php
to/SHORT/
as well.
- Change
- Run
test.php
to create a dummy test entry. - 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
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
<?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
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
<?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
- Create Short URL using PHP URL Shortener – CodexWorld
- Creating a URL Shortener Application in PHP & MySQL – NomadPHP
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!