Page 1 of 1

Shorten your URLs WITHOUT a database! Rate Topic: -----

#1 heyoman1  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 64
  • View blog
  • Posts: 735
  • Joined: 30-November 09

Posted 30 January 2011 - 12:20 AM

We have all been given a URL that has been shortened. You can tell this because you probably have been given a URL like (example) http://bit.ly/234nik. Then when you click on it, you are magically transferred to another URL. With so many of them buzzing around, like bit.ly, j.mp, minify.us, you probably wanted your own custom shortener. Well I'm here to tell you how to make one without a database! For example, my website ( http://appstorecrazy.com/ ) is my URL shortener (even though the long domain name defeats the purpose. ^_^)

Many people think that this is a near impossible feat. "You need a database to keep track of which URL is inputted and blah blah blah.." My way is way simpler, but comes with a drawback: Because there is no database interaction, you can't keep track of how many times a certain link has been clicked. But you can certainly implement these yourself!

Enough of me talking, let's get on with it!

First off, you will need either 1 of 2 things:
1) Have a web server hooked up on your local computer, preferably with L/M/WAMP or XAMPP
or

2) Currently have web hosting that supports PHP and mod_rewrite

I prefer to use the web hosting option as when you use the localhost, you may get a notice saying that certain varialbes are undefined until a URL is entered. Also that some localhost configurations don't have mod_rewrite enabled, and you would either have to:
1) enable mod_rewrite
2) manually put .html at the end.

We are going to create to create only 2 files for our shortener: index.php and .htaccess.

We will start off with the .htaccess. Normally, shortened URLs don't have a file extension on them. Well that is what we are going to make the .htaccess do: drop our extension and still make it work. First, make a text file, and call it ".htaccess", without the quotes. The name it just a file extension, and has no file name. Open it up, and let's start!

.htaccess
Options +FollowSymLinks
RewriteEngine on
#
## Internally rewrite extensionless file requests to .html files ##
#
# If the requested URI does not contain a period in the final path-part
RewriteCond %{REQUEST_URI} !(\.[^./]+)$
# and if it does not exist as a directory
RewriteCond %{REQUEST_FILENAME} !-d
# and if it does not exist as a file
RewriteCond %{REQUEST_FILENAME} !-f
# then add .html to get the actual filename
RewriteRule (.*) /$1.html [L]
#
#
## Externally redirect clients directly requesting .html page URIs to extensionless URIs
#
# If client request header contains html file extension
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^.]+\.)+html\ HTTP 
# externally redirect to extensionless URI
RewriteRule ^(.+)\.html$ http://www.x.com/$1 [R=301,L]


Make sure you replace x.com with your own server, be it either http://localhost/ or your own web site

This just says that if the .html extension isn't present when requesting the page, place .html at the end, and continue to the requested page. Else, if .html is present, drop the extension, and restart. This is all we need to get rid of the extension.
Spoiler


There are 5 steps are are going to to:
1) Get the url (or and the custom tag) we want shortened.
2) Get a randomized string.
3) Open up the current directory for viewing.
4) Check to see if our random string matches any file.
5) If it doesn't, make a file with that string that redirects to the given URL

1) Get the url (or and the custom tag) we want shortened.
<?php

$made = 0;
$url = $_GET['url'];
$custom = $_GET['custom'];


The first variable says if we made a URL already, so we won't have to display an error message. The second contains the given URL. The third is the custom tag.

2) Get a randomized string.
function getUniqueCode($length = "")
{
    $code = md5(uniqid(rand(), true)); 
    if ($length != "")
        return substr($code, 0, $length);
    else
        return $code;
}


This makes a randomized string as long as the length is given. Meaning if you say getUniqueCode(4), it will give you a string of 4 characters.

3) Open up the current directory for viewing.
if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
    }
}


We wouldn't want to create a file that redirects to nothing. So that's why we implemented the first if statement, saying that we can continue on if the $url variable contains something. Then we can safely open the current directory for viewing.

3.5) Make a variable containing the randomized string, or make it contain the custom tag.
if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
        if ($custom != "")
            $f = $custom;
        else
            $f = getUniqueCode(3);

        $d = $f . ".html";

        $site = "<!DOCTYPE html>\n\t<html>\n\t\t<head>\n\t\t\t<meta http-equiv=\"refresh\" content=\"0; URL=". $url ."\" />\n\t\t</head>\n\t\t<body>\n\t\t</body>\n\t</html>";
    }
}


Here we say that if we $custom contains something, assign it to $f. If there is no custom, get a random string of 3 characters. Then, make a new variable called $d for handling the actual file name. The $site variable is a long string that will make up the markup of our newly made file. All the \t's just help format the output file. It's my personal preference, so it's optional. This markup will redirect the user to the given URL.

4) Check to see if our random string matches any file.
if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
        if ($custom != "")
            $f = $custom;
        else
            $f = getUniqueCode(3);

        $d = $f . ".html";

        $site = "<!DOCTYPE html>\n\t<html>\n\t\t<head>\n\t\t\t<meta http-equiv=\"refresh\" content=\"0; URL=". $url ."\" />\n\t\t</head>\n\t\t<body>\n\t\t</body>\n\t</html>";
        
        while (false !== ($file = readdir($handle)))
        {
            if ($file != "." && $file != ".." && $file != "index.php" && $file != ".htaccess")
            {
                if ($d != $file)
                {
                }
            }
        }
    }
}


We check if we can continue to read from the directory, and if we can, make sure that we don't choose any important files. Then if that's true, we check to see if our $d variable is equal to any file.

5) If it doesn't, make a file with that string that redirects to the given URL
if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
        if ($custom != "")
            $f = $custom;
        else
            $f = getUniqueCode(3);

        $d = $f . ".html";

        $site = "<!DOCTYPE html>\n\t<html>\n\t\t<head>\n\t\t\t<meta http-equiv=\"refresh\" content=\"0; URL=". $url ."\" />\n\t\t</head>\n\t\t<body>\n\t\t</body>\n\t</html>";
        
        while (false !== ($file = readdir($handle)))
        {
            if ($file != "." && $file != ".." && $file != "index.php" && $file != ".htaccess")
            {
                if ($d != $file)
                {
                    $r = fopen($d, "w");
                    fwrite($r, $site);
                    fclose($r);
                    $made++;
                }
            }
        }

        closedir($handle);
    }
}

?>


We create a handle called $r that controls our file, and enable it to create a file ("w").
Then, write into our handle the $site variable that says that we want to redirect to the given URL. Then we close our file manipulator. Then we just increment our $made var to say that we have a file created. Notice how we close our directory with closedir();. This could prevent hackers, crackers, and who else knows, from going onto our directory while it's still open. We are officially done with creating the shortened URL! Time for our awesome graphics... err, basic html. :)
<!DOCTYPE html>
<html>
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<title>URL shortener</title>
</head>
<body>
<form method="get" action="<?php echo $_SERVER['PHP_SELF']; ?>">
Enter a URL (WITH THE http://): <br /><input type="text" name="url">
<br />                                                         
Want a custom tag?                  <br /><input type="text" name="custom">
<input type="submit">
</form> 
<?php 
if ($made > 0) {
    if (!empty($url)) 
        echo "Your new URL is: <br /><a href=\"http://x.com/" . $f . "\" target=\"_blank\">http://x.com/" . $f . "</a> ";
    else
        echo "No URL was given.";
}
?>
</body> 
</html>


Change x.com to either http://localhost/ or your own website name


When you enter in the URL (or and custom tag), the data will be sent to itself so it can create the file with the data you sent.

The first time, you enter your site, you wouldn't want it to say "No URL was given." You even haven't even entered a URL yet. That's why we made the $made var to keep track if we made a URL or not. Then we also check if $url was given. If it was, we give the user the new link to the URL that opens in a new page, just to see it work.

So that's it! This is the basis of a basic URL shortener, well for me. Just to note, if you are using http://localhost/, you can't share them out to others.

This is my first </dream.in.code> tutorial, and I hope you find this tutorial useful! :sweatdrop:

This post has been edited by heyoman1: 30 January 2011 - 12:50 AM


Is This A Good Question/Topic? 4
  • +

Replies To: Shorten your URLs WITHOUT a database!

#2 JacksonD  Icon User is offline

  • D.I.C Head

Reputation: 9
  • View blog
  • Posts: 215
  • Joined: 18-October 11

Posted 26 October 2011 - 05:16 AM

When I do it, it just refreshes my page.
http://thecss.webege.com/your-url/

My code: (index.php)
<!DOCTYPE html>
<html>
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<title>Get Smaller</title>
</head>
<body>
<form method="get" action="<?php echo $_SERVER['PHP_SELF']; ?>">
Enter a URL (WITH THE http://): <br /><input type="text" name="url">
<br />                                                         
Want a custom tag?                  <br /><input type="text" name="custom">
<input type="submit">
</form> 
<?php 
if ($made > 0) {
    if (!empty($url)) 
        echo "Your new URL is: <br /><a href=\"http://thecss.webege.com/" . $f . "\" target=\"_blank\">http://thecss.webege.com/" . $f . "</a> ";
    else
        echo "No URL was given.";
}
?>
</body> 
</html>


<?php

$made = 0;
$url = $_GET['url'];
$custom = $_GET['custom'];

function getUniqueCode($length = "")
{
    $code = md5(uniqid(rand(), true)); 
    if ($length != "")
        return substr($code, 0, $length);
    else
        return $code;
}

if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
    }
}

if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
        if ($custom != "")
            $f = $custom;
        else
            $f = getUniqueCode(3);

        $d = $f . ".html";

        $site = "<!DOCTYPE html>\n\t<html>\n\t\t<head>\n\t\t\t<meta http-equiv=\"refresh\" content=\"0; URL=". $url ."\" />\n\t\t</head>\n\t\t<body>\n\t\t</body>\n\t</html>";
    }
}

if (!empty($url))
{
    if ($handle =  opendir(".")) 
    {
        if ($custom != "")
            $f = $custom;
        else
            $f = getUniqueCode(3);

        $d = $f . ".html";

        $site = "<!DOCTYPE html>\n\t<html>\n\t\t<head>\n\t\t\t<meta http-equiv=\"refresh\" content=\"0; URL=". $url ."\" />\n\t\t</head>\n\t\t<body>\n\t\t</body>\n\t</html>";
        
        while (false !== ($file = readdir($handle)))
        {
            if ($file != "." && $file != ".." && $file != "index.php" && $file != ".htaccess")
            {
                if ($d != $file)
                {
                }
            }
        }
    }
}


Was This Post Helpful? 0
  • +
  • -

#3 Atli  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 3717
  • View blog
  • Posts: 5,981
  • Joined: 08-June 10

Posted 01 November 2011 - 09:53 PM

@JacksonD
Steps 3 - 5 build on each other. You can't just copy-paste them into a file one after the other. If you are just copy-pasting, the snippet in step 5 is what you are looking for. The PHP should also come before the HTML.


@heyoman1
There is one major flaw in your PHP code: The while loop you are using to check to see if the file has to be written will create the new file for every file listed that doesn't match the new file's name, even if the new file did actually exist.

The logic of your loop reads like this, in plain English:
for each of the file in the directory {
	if the current file is not one of the pre-excluded {
		if the current file is not the file we are looking for {
			create the file.
		}
	}
}

Do you see what I mean? The "create the file" part will execute for every file in the list that doesn't match the file you are searching for, whether or not it is in the list somewhere. This also means this will drain more and more resources the more files there are, which will eventually bring your server down to a crawl or even crash it.

The solution is to either use the loop to search first, having it flip a boolean flag when the file is found and use that once the loop is done to write the file; or simply use the file_exists() function to do the work for you.

You can also use file_put_contents() to write the file, rather than the fopen-fwrite-fclose series. Which reduces the whole thing down to something along the lines of:
if (!file_exists($d)) {
	$made = (bool) file_put_contents($d, $site);
}



I would also point out that the way you are accessing your GET variables at the top of the PHP page will generate warnings on servers with error reporting enabled. It's not an issue on production servers, but still. It's considered bad practice to attempt to access user input fields without making sure they exist first. (See the isset function for that.)


I like the idea though. A very simple way to do this when PHP is the only tool available to you. Although personally I would turn the .HTML files into .PHP just so I could set a HTTP 301 code. Or possibly just use a single PHP file that reads the URIs from .TXT files and generates the HTTP code and the HTML from it.
Was This Post Helpful? 1
  • +
  • -

#4 heyoman1  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 64
  • View blog
  • Posts: 735
  • Joined: 30-November 09

Posted 05 November 2011 - 10:16 PM

@Atli
I see where you are going with this. But in the guts of the while loop, I have an if() that sees if the file exists already. If it does, the while loop just continues with the next file. Also, I didn't know about the file_x() methods until a while after this. I just knew the fopen/write/close() functions through my past experience in C.

Funny story about this while loop. I forgot, but if I remember correctly, without that inner if() in the while(), I was creating files at 2x, where x = number of files. So if I have 8 shortened files, this script would create 256 files! xD

And with this, I feel this is a good time to update. I closed off appstorecrazy.com, and this shortener is now hosted under http://switch.tk/. I added a login system to you can see your shortened URLs (if you are logged in). If you are using Google Chrome, I made an extension for it. You will get an alert when visiting switch.tk through Chrome asking if you want to download it. I plan on redoing the whole thing, as I feel the guts are horribly made (spaghetti code, sorta). But yea, enjoy! :)

Also, if you read the spoiler, you can change the $site var to:
$site = "<?php header(".$url."); ?>";


So that it would run a bit faster.

This post has been edited by heyoman1: 11 January 2012 - 12:33 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1