Create URL Shortener For Twitter Using PHP

 

Hello, today I am going to go through how to build a custom URL shortener. Why have your own? Because then you are advertising yourself not another service like tinyurl.

A URL shortener is a nice way to send incredibly long links. It also helps when writing Tweets on Twitter (something I do a lot).

I decided that this system will have the following:

  1. Option to need a login or not
  2. API Key login
  3. Generate a new API key
  4. Click count
  5. Add/remove links when logged in
  6. Most recent IP tracking (always useful)
  7. Not to include bots on your clicks
  8. A nice admin backend
  9. Maybe: A JS button to login, and past the current URL into the textbox
  10. Maybe: Not looked how it fully works yet but be able to get a short URL with the Tweetie app for iPhone from Atebits. (I have nothing to do with them, just like their products.

Before we start you may want to have a go with the system we will be building here:

Download
live demo

Username: alexbor
Password: password

How it will work

I am going to do this in a two-part tutorial. By the end of the first tutorial we would have accomplished:

  1. Adding URLs
  2. Tracking (but not a nice view) of URLs
  3. Redirections (of both adding a Ò+Ó to the end of a URL and normal redirecting)
  4. AJAX system for adding a new URL
  5. Adding IP address
  6. Not to include bots
  7. Log in/out
  8. Redirecting visitors

Just so you can see, the final system that we will build today will have the following files:

The databases

Lets get started and create the databases that we will need. Run the following SQL code:

CREATE TABLE `url` (
  `id` int(30) NOT NULL AUTO_INCREMENT,
  `short` varchar(30) NOT NULL,
  `long` varchar(300) NOT NULL,
  `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `clicks` int(255) NOT NULL DEFAULT '0',
  `lastIP` varchar(30) NOT NULL,
  `lastClicked` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `active` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `short` (`short`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

CREATE TABLE `users` (
  `id` int(30) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) NOT NULL,
  `password` varchar(32) NOT NULL,
  `email` varchar(100) NOT NULL,
  `lastIP` varchar(20) NOT NULL,
  `apiKey` varchar(200) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`,`email`,`apiKey`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

If that worked successfully then you will have two tables, one will be for links and the other for users.

Now lets build the basic HTML of the website. On the home directory create a file index.php and put this in it:

	<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Make it short</title>
			<!-- Start of CSS -->
		<link rel="stylesheet" type="text/css" href="files/css/main.css" />
			<!-- Start of JS -->
	 	<script type="text/javascript" src="files/js/jquery.js"></script>
	 	<script type="text/javascript" src="files/js/add.js"></script>

	</head>
	<body>
	<div id="header">
		<div class="process"><div class="processingC"></div></div>
	</div>
	<div id="strip">
		<div id="stipWrap">
					<!-- This is the basic form for sending the url -->
					<form id="linkForm" class="" action="files/process/add.php" method="post">
						<input value="Make me short..." type="text" class="smallInput" id="theLink" name="theLink"/>
						<input type="submit" id="submit" value="Shorten" />
					</form>		

					<!-- This will show up once the URL has been shortened and allow you to post it to Facebook/Twitter/ or with Tweetie quickly -->
					<ul class="postTo">
						<li class="tweetie"><a href="">Post With Tweetie</a></li>
						<li class="twitter"><a href="">Post To Twitter</a></li>
						<li class="facebook"><a href="">Share On Facebook</a></li>
					</ul>
			</div>
	</div>
	<div id="end"></div>
	</body>
	</html>

Nothing to special there, just a layout with a form for adding/submitting URLs, also a few links that will have URLs once it has worked.

This file looks for some javascript and css files. We will create them now. Make a new folder called “files” the inside that create the following folders: css, functions, images, js, process, stats.

The main thing to notice from that is the folder “functions”, this will contain all functions and the config file. Also the process folder, this will contain process such as login, logout, where forms post to, etc.

The CSS file

Inside the CSS folder, add a new css file called “main.css”. The we will add the following CSS:

@charset "UTF-8";
/* CSS Document */
/* UTULITIES */
.clear{clear: both;}
.push{height: 30px;}
/* END */
/* ORDER PAGE CORRECTLY, REMOVING SOME BROWSER DEFULTS */
*{margin: 0; padding: 0;}
html{overflow-y: scroll;position: relative;}
body{width: 100%; height: 100%; background: url(../images/theBG.png) repeat; background-color: #00ADED;}
/* END */

/* header  */
#header{width: 1000px;height: 153px;margin: 0 auto;}
/*  END  */
#stipWrap{width: 1000px; margin: 0 auto;}
#strip{background:url("../images/strip.png") repeat-x scroll 0 0 transparent;height:270px;min-width:1000px;position:inherit;}
#linkForm{height:30px;margin: 0 auto;padding-top:100px;width:500px;}

/*  SOME MORE DEFULTS  */
.label{color:white;font-size:30px;} /*  Will be used when we have done the login bit  */
.smallInput{font-family: Helvetica, Verdana, Arial, sans-serif;background:none repeat scroll 0 0 #E9F0F8;border:1px solid #00ADED;color:#1E1C56;font-size:20px;padding:5px;}
#theLink{width:400px;}
#theLink:hover{background: #ffffff;}
#theLink:focus{color: #000000;}

/* These show the progress, and information from jQuery's AJAX   */
.process{background:#CC1B00;color:white;font-size:23px;font-weight:bold;height:0;margin-left:250px;position:absolute;text-align:center;width:500px;overflow: hidden;}
.processingC{padding: 5px;}

/*  The post to links  */
ul{font-family:helvetica;list-style:none outside none;margin-left:230px;margin-top:10px;display: none;}
ul li{display:inline-block;text-align:center;width:145px;}
ul li a{color:#2473A0;text-decoration:none;}
ul li a:hover{color:#E4E9E9;}
#message{color:#CBCBCB;font-family:Helvetica,Verdana,Arial,sans-serif;font-size:25px;font-weight:bold;margin:0 auto;padding-top:154px;text-align:center;width:1000px;word-spacing:3px;letter-spacing: 2px;text-shadow:0 0 8px #00ADED;}

.problem{color:#CBCBCB;font-family:Helvetica,Verdana,Arial,sans-serif;font-size:25px;font-weight:bold;text-align:center;width:1000px;padding-top: 5px;word-spacing:3px;letter-spacing: 2px;text-shadow:0 0 8px #00ADED;}

/*  LOGIN FORM  */
.inform{color:white;padding:25px 0;text-align:center;}
.loginForm{text-align: center;}
.logOut{color:#B1B3B3;font-size:18px;font-style:italic;padding-top:5px;position:absolute;text-decoration:none;}
.logOut:hover{color:white;}

There is nothing really to explain in the CSS or HTML file, this is mainly a tutorial explaining how to build the URL system.
Next add the images into the images folder that are included in the download and load the page. You should have this:

Javascript

Create the following JS files in the appropriate directory. First create file “add.js” and the second file “jquery.js” is optional, you can also load it from google with
<script type=”text/javascript” src=”http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js”></script>.

Just make sure that you are loading version 4.x + as we will be using .submit() and, as far as I know, that was added in the new version.

In the add.js file, we will add the following.

// when ready
$(function() {
	// we will be using this later (maybe more the once) so create this function that will
	// reset the "process" box to its defaults
	function resetThings(){
		$(".process").css({"background": "red"});
	}

	// now make some variables, these will be used later

	var urlBox = $('#theLink').val(),	// the textarea default value
		submitB = $('#submit'); 		// and the submit button
	$('#theLink').focus(function(){
		if( $(this).val() == urlBox ){
			$(this).val("http://");	 	// what to put in the text box by default
		}
	});

// when we click submit on this form
$('#linkForm').submit(function(){
	// reset the process box
	resetThings();
	// remove the submit button
	submitB.fadeOut();
	// tell the user we are doing something
	$('.processingC').html('Shrinking your URL...');
	$('.process').animate({"height": "50px"}, 500);

	$.ajax({
		type: 'post', // the method will be post
		dataType: 'json', // the data type to post
		url: 'files/process/add.php', // the URL of where to post the information
		data: 'theLink=' + $('#theLink').val(), //the data to post, we just want what is in the box at this time
		// on success the response will added to the "e" so we can call it by writing e.message. You don't need to use "e"
		// you can use what you want, but make sure that if you change it you change all of the other e's to the new thing
		// The response that will will send to this will be
		// 1. If it was successful
		// 2. A message
		// 3. If we have it, the short url. We will create this response in a minuet 

		success: function(e){
			if(e.error == true){ // if no error
				$('.processingC').html(e.message); // display the message in the box at the top saying what has happened
				submitB.fadeIn(); // as there was an error, bring back the submit button
				$('.process').animate({"height": "50px"}, 3500).animate({"height": "0px"}, 1000); 	// remove the process box
																									// after giving time to see the message
			}else{ // if there was not an error, it worked!
				$('.processingC').html(e.message); // display message
				$('.process').css({"background": "green"}).animate({"height": "50px"}, 3500).animate({"height": "0px"}, 1000); // make it a nice green
				$('#theLink').val(e.shortURL); // put the URL in the box
				$('.postTo').fadeIn(); // bring up the links
				// change the size of the textbox, not needed but a nice touch
				$("#theLink").animate({"width": "450px"})

				// set the buttons
				$('.postTo .tweetie a').attr({"href": "javascript:window.location='tweetie:'+'" + e.shortURL + "' "});
				$('.postTo .twitter a').attr({"href": "http://twitter.com/?status=" + e.shortURL + " "});
				$('.postTo .facebook a').attr({"href": "http://facebook.com/sharer.php?u=" + e.shortURL + " "});
			}
		}
	}); // end of ajax
		// if we had a time out, alert saying this.
		$(this).ajaxError(function(){
			alert("THERE WAS AN AJAX ERROR, SORRY ABOUT THAT");
		});
		// IMPORTANT! So it won't go to the page, return false!
		return false;
}); // end of submit
});

Lets start on the PHP

Create a file called “config.php” inside the functions folder. This will contain the database username, password, etc. Along with a way of setting if the login is needed and the base url. The base url will be the location of where you have placed the first index.php file. On my demo page it is http://demo.alexbor.com/url REMEMBER not to include the end “/”, nothing that bad will happen, it’s just best that you don’t. Put in all the information like this:

<?php
	$dbhost = 'localhost'; 	// the host (will probably be localhost)
	$dbuser = 'USERNAME'; 	// the username
	$dbpass = 'PASSWORD'; 	// the password
	$db		= 'DATABASE'; 	// the database
							// connect to the database, if fails - die.
	$conn 	= mysql_connect($dbhost, $dbuser, $dbpass) or die("Could not connect to the database");
							// select the database
	mysql_select_db($db) or die("I couldn't find the database");
							// define the base url... E.g. http://alexbor.com
	define("BASE_URL", "http://alexbor.com" );
							// In the end we will check if a login is required to shorten a url
	define("LOGIN_REQ", false );
?>

Load this page, and if you get nothing its all good! Now the functions page, create a file “functions.php” in this functions folder. I have said what everything (that we will need at this point) does so will not go into an explanation at the bottom.

<?php
// get the config file that has all the database info
require_once("config.php");
session_start(); // we will use sessions so its best to start it here as we will be including it on all pages
// A quick way to respond to the JSON request that we will set up later.
// This will allow us to easily post if it worked, a message, and (if we have it) a short URL
function json_to_jquery($type, $message, $url){
	$replying['error'] = "$type"; // if it worked or not
	$replying['message'] = "$message"; // the message
	$replying['shortURL'] = "$url"; // the URL
	echo(json_encode($replying)); // json encode so that the JS file will know what everything means
}

function gen_short_url(){
		// find the heighest ID
	$query 	= 'SELECT MAX( id ) FROM `url` LIMIT 1 ';
			// run the query/get info
	$res	= mysql_query($query);
	$accoc 	= mysql_fetch_assoc($res);
			// grab the heighest ID and add one
	$id		= $accoc['MAX( id )'];
	$id++;
			// convert to short url code
			// the base conver will convert (when set up like we have) will convert from 1-9 then a-z
			// it is a great way to produce what we want
	$shortURL = base_convert($id, 10, 36);
	return $shortURL;

};

// this will add the values, we will give it the short/and long URL
function add_url_to_database($shortURL, $longURL){
	// create the query, and insert it into the "url" table
	$insert_query = "INSERT INTO `url` (`id` ,`short` ,`long` )
						VALUES (
						NULL ,
						'{$shortURL}',
						'{$longURL}'
						)";
	// if it did something
	if(mysql_query($insert_query)){
		// set the error to false
		$urlInfo['error'] = false;
		// set the short url
		$urlInfo['shortURL'] = $shortURL;
		// set the long url
		$urlInfo['longURL'] = $longURL;
		return $urlInfo;
	}
}

?>

Leave this and we will come back to it later. Next, create the add page that the jQuery posts to. In the process directory (as we will be processing the information) create a file “add.php”. We will add the following:

<?php
require_once("../functions/functions.php");  // get the functions file
$error = false; // set this as defalt
$longURL = mysql_real_escape_string( strip_tags($_POST['theLink']) ); // remove bad things and put it into a variable

// check if valid URL
if(!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $longURL)){
	$message = "Not a valid URL!"; // This will be what will be displayed to the user if there was a problem
	$error = true; // set an error
} else{ // it was valid
		$longURL = urlencode($longURL); // encode the url
}

// if there was no error, add it to the database
if(!$error){
	// next we will create a short url "temp" and pass that into the next function (we will create this in a second)
	$shortURL = gen_short_url();
	$urlInfo = add_url_to_database($shortURL, $longURL); // add the short/long url
}else{ 

// as there was an error, so we will say so. The short URL string is added but left blank as a value as the function requiers it
	json_to_jquery($error, $message, "");
	die();
}
// if errors
if($urlInfo['error'] || $error){
	json_to_jquery($error, "There was a problem", "");
	die();
}else{ 	// this worked so build the short url
		// the base that was set in the config file, then a foward slash, and the shortURL that was returned
	$url = BASE_URL . "/" . $urlInfo['shortURL'];
	json_to_jquery("0", "Success!", $url);  // Send this to the user via our function
}
?>

And that is it for the adding of links!
If you try it out now it should allow you to insert links into the database.

We will next deal with redirecting the users. For this we will create a “.htaccess” file on the home directory. Add the following:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L]

This will re-write the URL so if you go you it will save you from needing http://alexbor.com/index.php?url=4 and instead just http://alexbor.com/4. This is all good, but we need to get the index.php file read to deal with this. Open up that file again and we will add the following to the very top of the file, above anything already in the file.


<?php

require_once("files/functions/functions.php"); // as normal, get the functions
$url           = mysql_real_escape_string( strip_tags($_GET['url'])); // get the varible "url" from the url. This will be the short url.
//echo $url; // uncomment this if you would like to see it get the value.
// if it has a string length
if(strlen($url) >= 1){
	// set a variable saying we are doing a redirect to true.
	$redirect = true;
}else{
	// if not we will load the page as normal, so set it to false.
	$redirect = false;
}
if(!$redirect) : // if we are not re-directing the page do this
// as the rest of the file here. Then at the very bottom add
?>
<html>
 ....
</html>

<?php endif; if($redirect) :  // check we are redirecting
	// get the full URL (we will set this up in a minute
	// it will take the short url that we got
	$redirect =	get_url_from_small($url);

//	print_r($redirect); // uncomment to see what we are returning

	if($redirect['error']){ // if there is a problem, say so
		echo "That URL is either no longer valid or has been deactivated";
	}else{ // if not
		$url = urldecode($redirect['long']); // decode the long url
		header( "Location:  " . $url . " " ); // redirect the user
	}
endif; //end of the redirect if.
?>

In that area above, we have used a plethora of function that are yet to exist, so we will now create them.

function gen_short_url(){
		// find the heighest ID
	$query 	= 'SELECT MAX( id ) FROM `url` LIMIT 1 ';
			// run the query/get info
	$res	= mysql_query($query);
	$accoc 	= mysql_fetch_assoc($res);
			// grab the heighest ID and add one
	$id		= $accoc['MAX( id )'] + 1;
	$id++;
			// convert to short url code
	$shortURL = base_convert($id, 10, 36);
		// if that failed, set an error
	return $shortURL;

};
// get full url
function get_url_from_small($smallURL){ // set up the function

	if(small_url_exists($smallURL)){ // this will return true or false

		$longQ = mysql_query("SELECT * FROM `url` WHERE `short`='{$smallURL}' LIMIT 1"); // find the url
		// don't need to check amount of rows, we know it exists!
		$accoc 	= mysql_fetch_assoc($longQ); // grab the row values
		if($accoc['active'] == 0){ // if it is no longer active
			$accoc['error'] = true; // set error
			return $accoc; // return this
			die(); // die
		}
		$accoc['error'] = false; // if not, set error to false

		if(get_stats_page($smallURL)){ // check if it has a + at the end of it
			$short = $accoc['short']; // if it does we get the short url from that array
			$accoc['long'] = BASE_URL . "/files/stats/" . $short; // and overwrite the long url to this
			return $accoc; // now return this array
		}else{
				user_clicked_link($accoc['id'], $accoc['clicks']); // add one to the clicked number, we are passing the amount of clicks to save from doing a another SQL query, and we are passing the ID so we know what we are doing.
				return $accoc; // return
		}

	}else{ // it does not exist
		$accoc['error'] = true; // set an error
		return $accoc;
	}

}

function add_url_to_database($shortURL, $longURL){
	$insert_query = "INSERT INTO `url` (`id` ,`short` ,`long` ,`addedByID`)
						VALUES (NULL ,
						'{$shortURL}',
						'{$longURL}',
						'0' )";
	if(mysql_query($insert_query)){
		$urlInfo['error'] = false;
		$urlInfo['shortURL'] = $shortURL;
		$urlInfo['longURL'] = $longURL;
		return $urlInfo;
	}
}

// check that a value exists
function small_url_exists($smallURL){													// this will take the small url
	$existsQ = mysql_query("SELECT * FROM `url` WHERE `short`='{$smallURL}' LIMIT 1");	// run a search to find it
	$exsitsRows = mysql_num_rows($existsQ);												// check amount of rows
	if($exsitsRows == 0 ){ 																// if there are 0 it was not found
		return false;
	}else{
		return true;
	}
}

function get_stats_page($shortURL){ // here we check to see if a short url had a + at the end
$shortURL = urlencode($shortURL); // encode as URL's with +'s get changed into spaces previously.
	if(preg_match('/([+])$/i', $shortURL)){ // check that it contains a + once at the end
		return true;	// it does
	}else{
		return false;	//it does not
	}
}

function user_clicked_link($id, $clicks){ // this will add a click number
	// if user is not a bot
	if( !botCheck() ){
		$clicks = $clicks +1; // add one to the amount of clicks
		$ipAdd 	= $_SERVER['REMOTE_ADDR']; // get the IP address
		$tUnixTime = time(); // get the time
		$timeStamp = gmdate("Y-m-d H:i:s", $tUnixTime); // put it into a valid (gmt) time stamp
		$updateQ = "UPDATE `url` SET
					`clicks` = '{$clicks}',
					`lastIP` = '{$ipAdd}',
					`lastClicked` = '{$timeStamp}'
					WHERE `id` ='$id' LIMIT 1";
		mysql_query($updateQ);// update to the new values
	}
}

// check for bots
function botCheck(){
	// an array containing all the names of the most popular bots
	$botlist = array("Teoma", "alexa", "froogle", "Gigabot", "inktomi",
	"looksmart", "URL_Spider_SQL", "Firefly", "NationalDirectory",
	"Ask Jeeves", "TECNOSEEK", "InfoSeek", "WebFindBot", "girafabot",
	"crawler", "www.galaxy.com", "Googlebot", "Scooter", "Slurp",
	"msnbot", "appie", "FAST", "WebBug", "Spade", "ZyBorg", "rabaz",
	"Baiduspider", "Feedfetcher-Google", "TechnoratiSnoop", "Rankivabot",
	"Mediapartners-Google", "Sogou web spider", "WebAlta Crawler","TweetmemeBot",
	"Butterfly","Twitturls","Me.dium","Twiceler");
	// foreach of the names, see if the user is one of them
	foreach($botlist as $bot){
						/// get them
		if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
		return true;	// Is a bot
	}
		return false;	// Not a bot
}

I have commented throughout explaining in detail what each function does, so have a read through that. This is now good to go! Try it out and see what happens. You can now shorten URL’s and also go to them.

Logging in/out

Next, we will do the login bit. For this we will need, a username, md5 hashed password, an API key and email. We will deal with adding users at a later time but for now, add them in manually. To see what an md5 password and API key looks like, create a new php file and use what follows:

<?php
	echo "Your password is";
	echo md5("password") . "<br />";
	// create a API key that will be individual and hard to crack.

	$toHash = time(); // the current time
	$toHash .= rand(0, 999999); // a random number
	$tohash .= $_SERVER['REMOTE_ADDR']; // the IP address of the user

	$toHash2 = rand(0, 999999);
	$toHash2 .= "alex@alexbor.com"; // your email
	$hash1 = md5($toHash); // md5 the first hash
	$hash2 = md5($toHash2);  // md5 the second hash
	echo "Your API key is: " . $hash1 . $hash2 . "<br/>"
?>

Select both of those values and inset them into the database along with you desired username/email with the following SQL query. Note: Make sure the username and password are over 6 characters or over and the username has no white space.

INSERT INTO `urls`.`users` (`id` ,`username` ,`password` ,`email` ,`apiKey`)
VALUES (NULL , 'USERNAME', 'PASSWORD', 'EMAIL', 'API KEY');

That should be the only time we add a user manually, we will build a way to add them ourselves from a nice view.

We now have a users, so we will create a way to login with the username and password above.

In the index page we will add the following in the very top under where we are requiring our functions file.

$loggedIn = $_SESSION['loggedIn'];
$username = $_SESSION['username'];

Next find the div with an ID of “strip”, and replace it with this:

<div id="strip">
	<div id="stipWrap">
		<!-- If we require a login AND the user is not logged in we will load the login form -->
		<?php if( (LOGIN_REQ) && ($loggedIn != true) ){ ?>
				<h1 class="inform">Please login with the form below:</h1>
				<form class="loginForm" action="files/process/login.php" method="POST">
					<label for="username" class="label">Username:</label><br />
					<input type="text" id="username" class="smallInput" name="username"><br />

					<label for="password" class="label">Password:</label><br />
					<input type="password" id="password" class="smallInput" name="password"><br /><br />
					<input type="submit" value="Login me in!" />
				</form>
		<!-- else, if we don't require a login, load the submit form -->
		<?php }else{ ?>
				<?php
					// if you are logged in, display a logout URL.
				if($loggedIn){echo "<a href='" . BASE_URL . "/files/process/logout.php' class='logOut'>Logout " . $username . "?</a>"; }
				?>
				<form id="linkForm" class="" action="files/process/add.php" method="post">
					<input value="Make me short..." type="text" class="smallInput" id="theLink" name="theLink"/>
					<input type="submit" id="submit" value="Shorten" />
				</form>		

				<ul class="postTo">
					<li class="tweetie"><a href="">Post With Tweetie</a></li>
					<li class="twitter"><a href="">Post To Twitter</a></li>
					<li class="facebook"><a href="">Share On Facebook</a></li>
				</ul>
		<?php }; ?>
	</div>
</div>

That will check if the defined value of “LOGIN_REQ” is true or false, it’s false and the user is not logged in, load the login form. If not then we have aloud public access to this url shortener. If you try it out when changing the value of LOGIN_REQ in the config page you will see it change. We will build the login system.

Logging in

In the process folder, add two new files “login.php” and “logout.php”. Then open the login file.

<?php
require_once("../functions/functions.php");
$username = mysql_real_escape_string( strip_tags($_POST['username']) ); // get the posted username
$password = mysql_real_escape_string( strip_tags($_POST['password']) );	// get the posted password
if(strlen($username) < 5 ){ 	// if the username is above 5 char
	$error = true;			// if its not set an error
	$errorMessages['username'] = "Please write a username"; // what the error is
}
if(strlen($password) < 5){ // same with password
	$error = true;
	$errorMessages['password'] = "Please write a password";
}

if(preg_match("/ /", $username)){ // check that the username has no white space.
	$error = true;
	$errorMessages['spaces'] = "Username cannot contain white space";
}

if($error){ // if there is an errir
	foreach( $errorMessages as $errorMessage ){ // for every error message
		echo "Problem: " . $errorMessage . "<br />"; // echo it out
	}
}

if(!$error){ // if no error
	$password = md5($password); // hash the pass, we do this know as it generates a 32 char varible. Even if it was left
								// empty
	if(check_username_and_password($username, $password)){ // if we find the user (will create this function)
		// found user
		// set sessions
		$_SESSION['loggedIn'] = true;
		$_SESSION['username'] = $username; // set a session
		header("Location:  " . BASE_URL . "/");  // redirect back the the index page
	}else{
		//didn't find user
		echo "Sorry, no user with that username/password combo was found!";
	}
}?>

And now the logout page. Inside the logout file we create earlier write:

<?php
require_once("../functions/functions.php");
setcookie( session_name(), '', time() - 100); // if there is a session cookie make it expire it from the user's pc
session_destroy();	// destroy the session on our server
header("Location:  " . BASE_URL . "/"); // redirect back to index page
?>

Almost done, we now just need to add the final function to check if the user was found. Open the functions file at the bottom add:

// DOING THE LOGINS
function check_username_and_password($username, $password){
	$ucheck = mysql_query("SELECT * FROM `users` WHERE `username`='{$username}' AND `password` ='{$password}' LIMIT 1");
	$ucheckRows = mysql_num_rows($ucheck);
	if($ucheckRows == 0 ){
		return false;
	}else{
		return true;
	}
}

Finished

That should now be the end of it for. From the plan I set above:

  1. Adding URLs done
  2. Tracking (but not a nice view) of URLs done
  3. Redirections (of both adding a Ò+Ó to the end of a URL and normal redirecting) done
  4. AJAX system for adding a new URL done
  5. Adding IP address done
  6. Not to include bots done
  7. Log in/out done
  8. Redirecting visitors done

You can download completed files from here and have a read through them. You may not be able to see the .htaccess file though, so you will have to remake it on the server to get this to work.

Related posts:

  1. Twitter URL Shortener: Part 2
  2. Cross Browser Placeholder Text For Input Fields


Written by brenelz

Hello everyone, I'm Brenley Dueck or better known as Brenelz. I currently run my own business called Brenelz Web Solutions which focuses primary on winnipeg website design. The web technologies I most specialize in are CSS, jQuery, AJAX, PHP, and the MySQL database. Please make sure to follow me on twitter.

 

21 Responses to “Create URL Shortener For Twitter Using PHP”

  1. Steve Says:

    March 10th, 2010 at 9:50 am

    Wow! Great stuff here! Learned about some new php functions.

  2. Paperboy Says:

    March 11th, 2010 at 6:21 pm

    Thanks, this nice tut will come in handy! I have a pretty short domain name I’ve thought about using for this! :)

  3. Nick Parsons Says:

    March 11th, 2010 at 6:22 pm

    Whoa – that was an amazing tutorial! I like the fact that you picked something so unique and yet useful.

    As a sidenote, jQuery.submit() did exist before v.4, but it’s still a great idea to use the latest version :) Excellent job – I’ll definitely be coming back here!

  4. brenelz Says:

    March 11th, 2010 at 11:54 pm

    So glad that you like it…. more good tutorials to come!

  5. ridwan Says:

    March 12th, 2010 at 1:55 am

    hi, i’m interesting to try this tutorial.
    but when i add url to make it short.
    it doesn’t give me any short url.
    neither store to url table nor to give me the link of short urls. (it just back to the current url/not generate the short url)

    thx b4

  6. Alex Says:

    March 12th, 2010 at 3:12 am

    @Nick Parsons – Oh thanks, I tried it and it didn’t work… Must have just been doing it wrong.
    Thanks for the comments people!

  7. Johan Says:

    March 12th, 2010 at 4:12 am

    Excellent tutorial! Found your blog when searching tweets for uploadify to see what people thought! :)

  8. Alex Says:

    March 12th, 2010 at 10:35 am

    @ridwan – Can you give me some information such as what browser you are using? What OS etc so I can get this bug fixed.

  9. Design Says:

    March 13th, 2010 at 7:29 am

    Must take pleasure in your time you put into this blog :)

  10. Notable Tech Posts – 2010.03.14 | The Life of Lew Ayotte Says:

    March 14th, 2010 at 10:38 am

    [...] Create URL shortener for Twitter using PHP [...]

  11. 2010-03-12 유용한 링크 | We are connected Says:

    March 15th, 2010 at 2:55 am

    [...] Create URL Shortener For Twitter Using PHP [...]

  12. Linkhub – Woche 10-2010 « pehbehbeh Says:

    March 15th, 2010 at 3:13 am

    [...] eigenen URL-Shortener [...]

  13. Atul Kash Says:

    March 16th, 2010 at 4:26 pm

    Excellent work! This is much needed, I’ll be doing a web app for twitter very soon and this is going to be very helpful.(Will credit you) Thanks

  14. fix for ridwan/alex Says:

    March 29th, 2010 at 11:08 am

    I only downloaded this for debugging the fact that ridwan isn’t able to create a short url.

    Please, check your database for any field called ‘addedById’ in the table ‘url’ (if you’ve downloaded the whole package, or followed this tutorial exactly as it is written). Now, go to your functions.php file (located in /files/functions) and search for the function ‘add_url_to_database’. Remove ‘addedById’ from the query, as well as the value ’0′ (include the comma which is in front of that value).

    This will fix your issue.

    Regards,

    One of the many webdevelopers in the world.

  15. Alex Says:

    March 29th, 2010 at 12:14 pm

    Thanks for that fix! I added the “addedById” at the start then decided against it (I later changed this as you can see in part 2 if you download/view the tutorial). Think I forgot to change that in the tutorial and demo at the start…
    Anyway, thanks for telling me what it was! :)

  16. nestdev Says:

    April 30th, 2010 at 8:33 pm

    Hi brenelz !, thank’s for great tutorial. share and promote your article and tutorial in http://nestdev.com. check out, your tutorial was there. :)

  17. koduru Says:

    July 29th, 2010 at 12:34 pm

    I created this shortner on my doamin sweet.cc, but how do I use my custom url shortner site associated with retweet button so the short url’s are generated as sweet.cc/1 instaed of bit.ly

  18. Steven Says:

    August 20th, 2010 at 5:46 pm

    Hello

    Thanks for the tutorial, but I am having trouble getting it to work. It shortens the urls and adds them to the database, but doesn’t allow me to access a short url. I get the following error:
    “Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at /nfs/raven/u1/c/craders/public_html/s/index.php:2) in /nfs/raven/u1/c/craders/public_html/s/files/functions/functions.php on line 3
    ….”
    Can you please help?

    Here is my functions.php file : http://dl.dropbox.com/u/3638821/functions.php

  19. Emily Says:

    October 26th, 2010 at 5:03 am

    Hi,

    I currently have a problem with the ambersand in my url and though twitter sends the correct url to its status line it doesnt enter it in at the status box and I thought maybe url shortneing would help but it hasn’t?

    i used urlencode() to send it but recently on twitter its just not excepting this no more all that does is now send the correct info to twiter’s status= part of the url but breaks at the ambersand again in the status box?

    thanks,

  20. mojoe Says:

    December 19th, 2011 at 4:18 am

    For the love of god, please use addSlashes on the variables on your SQL queries to prevent injections!

    Also, you may want to scan the links submitted to make sure someone isn’t posting a javascript: url to do some xss attack.

  21. Alex Says:

    January 4th, 2012 at 2:43 pm

    Yes, really should have. As I 1st was meaning for this to be just for use by a registered user who was running it I didn’t overly add much security.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
connect with me!