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!
TABLE OF CONTENTS
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
EXAMPLE CODE DOWNLOAD
Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
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
CREATE TABLE `short_url` (
`short` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`full` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `short_url`
ADD PRIMARY KEY (`short`),
ADD UNIQUE KEY `full` (`full`);
That’s right, only 2 fields.
short
Primary key, the “URL shortcode”. Take note, this is case-sensitive.full
The full URL to redirect to. Unique to prevent duplicate URLs.
STEP 2) SHORTEN URL PHP LIBRARY
<?php
class Shorten {
// (A) CONSTRUCTOR - CONNECT TO THE DATABASE
private $pdo = null;
private $stmt = null;
public $error;
function __construct () {
$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
]);
}
// (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) : void {
$this->stmt = $this->pdo->prepare($sql);
$this->stmt->execute($data);
}
// (D) HELPER - RANDOM STRING
// CREDITS: https://stackoverflow.com/questions/4356289/php-random-string-generator
function random ($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 getShort ($short) {
$this->exec("SELECT `full` FROM `short_url` WHERE `short`=?", [$short]);
return $this->stmt->fetchColumn();
}
// (F) GET BY FULL URL
function getFull ($full) {
$this->exec("SELECT `short` FROM `short_url` WHERE `full`=?", [$full]);
return $this->stmt->fetchColumn();
}
// (G) DELETE ENTRY
function del ($short) {
$this->exec("DELETE FROM `short_url` WHERE `url_id`=?", [$short]);
return true;
}
// (H) GENERATE A NEW SHORT URL CODE
function create ($full) {
// (H1) CHECK IF FULL URL ALREADY EXIST
if ($this->getFull($full) != "") {
$this->error = "$full is already defined.";
return false;
}
// (H2) GENERATE RANDOM SHORT CODE
$short = null;
while ($short === null) {
$random = $this->random();
if ($this->getShort($random) == "") { $short = $random; }
}
// (H3) INSERT ENTRY
$this->exec(
"INSERT INTO `short_url` (`short`, `full`) VALUES (?,?)",
[$short, $full]
);
return $short;
}
}
// (I) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHAR", "utf8mb4");
define("DB_USER", "root");
define("DB_PASSWORD", "");
// (J) INIT
$_SURL = new Shorten();
Yikes, this library looks pretty massive at first. But keep calm and look carefully.
- (A, B, J) 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.random()
Generates a random string.
- (E & F) Get URL entries from the database.
getShort()
Give the short URL code, get the full URL.getFull()
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) Remember to change the database settings to your own.
That’s all, pretty much just SQL queries. Remember to change the database settings to your own.
STEP 3) REDIRECTION
3A) CREATE A DUMMY SHORT URL CODE
<?php
// (A) ADD ENTRIES
require "2-lib-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.
3B) HTACCESS FILE
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^3c-index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /3c-index.php [L]
This is “borrowed” from WordPress. What this does:
- Turn the rewrite engine on.
- Redirect
http://site.com/SHORTCODE
to3c-index.php
. - Don’t redirect existing files and folders alone.
- Don’t redirect HTTP auth requests.
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.
3C) INDEX PAGE
<?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 "2-lib-shorten.php";
$full = $_SURL->getShort($short);
}
// (C) REDIRECT IF VALID
if ($full!==false) { header("Location: $full"); }
else { echo "INVALID REQUEST"; }
Finally, this should be straightforward:
- Get the “shortcode section” from the URL.
- Check the shortcode against the database.
- Redirect if valid.
EXTRAS
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!
If you want to load a page using this short URL system:
- Instead of the URL, store the file name in the database
full
column. - Update section C of
3c-index.php
– If valid,require $full
instead of redirecting. - This pretty much turns it into a “pretty URL” system.
A POSSIBLE ISSUE
Here is a small possible problem that I foresee in create()
of 2-lib-shorten.php
.
- The shortcode is generated using a random string generator
$random = $this->random()
. - It is then checked against the database to make sure there are no duplicate shortcodes
if ($this->getShort($random) == "")
.
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
- Pretty URL With PHP HTACCESS – Code Boxx
- 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!