The Logic Behind Link Shortener

     

Link shortening is a method of transforming a longer link to a shorter one. Let’s say you are linking to an article at http://www.somedomain.com/content/articles/index.php?article_id=567 on your blog post, but would like the link to appear shorter. There are several different approaches for this – one can, for example, use Bitly, probably the world’s most popular link shortening service. Alternatively, if you are interested about how things work, you can create your own link shortener!

Having a self-hosted link shortening engine has a few differences over using a third-party service. The most obvious is how the shortened link will look. Using Bitly, the shortened link would look like http://bit.ly/2uNPPDM. However, using your own engine, the link would be something like http://yourdomain.com/go/1. It is debatable which one is better and whether it actually matters, but the latter one can give a tiny boost for your branding. Also, you can customize your own link shortener endlessly – like adding a click counter to keep track of the outbound links.

The Logic

In this article, we are creating a simple link shortener with Apache web server, PHP and MySQL. We will be modifying .htaccess (the Apache configuration file) adding a new file go.php and creating a database table for mapping the links. After that, we will have the shortened links, such as http://akseliniemela.com/go/1 that will point to CodeAcademy forum post at https://www.codecademy.com/forum_questions/51db458b9c4e9d073a000613.

The flow of data will look like this:

http://akseliniemela.com/go/1  »  read .htaccess  »  find instructions to read go.php?id=1  »  find instructions to read database  »  send to https://www.codecademy.com/forum_questions/51db458b9c4e9d073a000613

In theory and practice, you could omit the go.php and database parts. In that case, you would need to hard-code all the outgoing links to .htaccess file. This is not a problem if you only have a handful of links, but if you have many it’s better to read them from a proper database. Hence, we choose to use the PHP and database implementation.

Step 1: Create table

The outbound links are included in the database, and that’s where the web server will read them. We will create a table called links to our MySQL database. The links table will have two columns:

id, with INT type and auto_increment and primary key on.
link, with TEXT type.

After that, we will insert a few rows with long links to the table. We’ll use the following URLs in the link column:

* https://www.codecademy.com/forum_questions/51db458b9c4e9d073a000613
* https://stackoverflow.com/questions/12385891/how-to-deal-with-long-links-in-html-emails
* https://github.com/Parallel-in-Time/parallel-in-time.github.io/issues/61

The links table will look like this in phpMyAdmin:

You can download the phpMyAdmin dump and import it to your database. Once the links table has been created and filled with some data, it’s time to move to .htaccess.

Step 2: Modify .htaccess

.htaccess is the configuration file the web server reads before showing the website. If instructions are included in the file, the server executes them first. We want to tell the server to rewrite akseliniemela.com/go/x/ internally to akseliniemela.com/go.php?id=x. In another words, akseliniemela.com/go/x/ will stay on the address bar of your web server, while the information is actually read from akseliniemela.com/go.php?id=x. We include the following to the domain’s .htaccess:


<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^go/([^/.]+)/?$ go.php?id=$1 [L]
</IfModule>

First, we make sure mod_rewrite is activated on Apache. Then we fire up the rewrite engine, and after that we map that address (akseliniemela.com)/go/[everything but / and .] internally rewrites to (akseliniemela.com)/go.php?id=[everything but / and .]. For example, now we can go to /go/1 and it will be read from /go.php?id=1. Exactly the functionality we want from this link shortener!

Step 3: Create go.php

go.php is the file that reads the database and links table, fetches the right outbound link according to the id=x parameter brought by .htaccess, and then redirects the user to that outbound link if found. The file will look like this:

<?php 

    require_once("db.php"); 

    $stmt = $conn->prepare('SELECT link FROM links WHERE id = :id');
    $stmt->execute(array('id' => $_GET['id']));
	
	$row = $stmt->fetch();
	
	if ($row) {

		header("HTTP/1.1 301 Moved Permanently");
		header("Location: $row[0]");
		
	}
	
?>

First, we include db.php that makes the connection to MySQL and selects the right database, using the $conn variable. After that, we prepare a statement to select link field that corresponds the id brought by .htaccess (/go/x) and consecutively by go.php (go.php?id=x). The ?id=x portion of URL is referenced to by the $_GET[‘id’] on the 6th row. In fact, the whole 5 and 6 rows form a prepared statement which eliminates the risk of SQL injection.

After that we fetch the row with the link field. If it’s found, we continue with the redirect. The redirect is brought by modifying browser headers – hence the lines 12-13. We first tell the browser that the /go/x is permanently moved (HTTP 301) to the outbound link which is a good habit. After that, we tell the browser the location to go to – the first element from the row variable, which contains the right outbound link from the table.

Now, the link shortener is ready! The result is that http://akseliniemela.com/go/1 leads to https://www.codecademy.com/forum_questions/51db458b9c4e9d073a000613, http://akseliniemela.com/go/2 leads to https://stackoverflow.com/questions/12385891/how-to-deal-with-long-links-in-html-emails and http://akseliniemela.com/go/3 leads to https://github.com/Parallel-in-Time/parallel-in-time.github.io/issues/61.

If this article helped you or you have something to say or ask, please leave a comment below!

Share Your Thoughts

Have something to say about this post? Then say it by filling the form below!

(required):

: