Alright so recently I has been working on putting together a URL Shortener so I may use a custom link URL for tracking the links which I post to twitter. A service like or I did some searching and over at the PHPAcademy they had a tutorial on doing just that. With Alex’s permission from PHPAcademy I am going to share my take on his tutorial. The groundwork for the PHP remains unchanged I did some factoring of the JavaScript and front-end. Also I just added one more data row to the MySQL database which will be tracking all of the shortened links and my addition which tracks how many non-uniques it’s our link is getting.

The base tutorial for the PHP may be found on PHP Academy here:

My live link of the code that will be covered may be seen in working order here:

All of my changes an modifications to the code are also public ally available on GitHub:

(Note the only bit of code that is not include is my server info when’s food time to add that is when you create your database)

The changes were nothing too groundbreaking but just implementing some better JS practices and expanding functionality and usability.

Stepping through the changes:

PHP Changes

The only real change was adding a bit of code to track hits on the links. So registering that a hit occured. Then passing that to our mySql database.

function redirect($code){
	$code = mysql_real_escape_string($code);
		$url_query = mysql_query("SELECT * FROM `urls` WHERE `code`='$code'");
		$url = mysql_result($url_query,0,'url');
		$hits = mysql_result($url_query,0,'hits');
		mysql_query("UPDATE urls SET hits= ' ".$hits." ' WHERE code = '".$code."'");	
		header('Location: ' .$url);


File Structure

I always work in a segmented manner. This is how application developers approach building applications with a Model-View-Controller (MVC) approach.  Separating markup, styling and functionality are professional best practices.  I have three directories css, js and images for these. There is some php on index.php which can’t be avoided but Alex from PHPAcademy does a good job segmenting out functions.

New Functionality

URL Validation

I am validating the input further by checking for an http or https protocol and adding http as the default if no protocol exists.

if(!(new RegExp('^(http|https)://')).test(url)){
    url = 'http://' + url;

URL Highlighting/Selection

Selection of the shortened URL has some improved logic to select the text of the shortened URL and also to show/display a tooltip which shows the shortcut for copying the code (dynamic based on the operating system).

url.blur( function(){
url.focus( function(){
    if (url.val().match(/{
}).mouseup(function(e){ e.preventDefault(); });

Get Operating System for Tooltip

The code for the message has remained relatively untouched. Added is the updating of the tip text which is returned from our getOs() function.

tip.html(opSys); //updates text with value returned from getOs()

function getOs(){
    var os =  navigator.platform;
    return (os.match(/Mac/)) ? '⌘ + C to copy' : 'Ctrl + C to copy';

Code Practices

Store DOM Elements

Here is where I really refined things from the tutorial. The javascript stores DOM elements into variables for performance. In our document.ready() function which starts our processes when everything on the page is ready.

var url = $('#url');
tip = $('#tip p');
opSys = getOs();

Room for Improvement

The opSys and tip variables are defined outside of our document.ready() function so they may be accessible to both the document.ready() and the getUrl() and getOs().  This is a small project so that is not completely terrible however, the scope is global so these could be overwritten by other global variables.

var opSys, tip;

Also I have dipped into the DOM three times using the same selector $(‘#url’). If I were to improve this I would define it in one place. A global var like opSys and tip would work. Better yet it could be define in the document.ready() function and passed to the getUrl function as a parameter. I left these mistakes in here to point them out and also as a reminder that there is almost always room for improvement and that there are most certainly multiple ways of approaching problems.  If I do decide to amend these that will be reflected and seen in my commits on github and this post will be updated as well!