diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f5a0e1b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* crlf=input \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..270f66e --- /dev/null +++ b/.htaccess @@ -0,0 +1,3 @@ +RewriteEngine On +RewriteBase / +RewriteRule ^(.*)? index.php?$1 [L,NC] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8309b41 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Simple PHP URL shortener + +## Installation + +1) Download the source code as located within this repository, and upload it to your web server. +2) Use `database.sql` to create the `redirect` table in a database of choice. +3) Edit `config.php` and enter your database credentials. + +## Features + +* Redirect to Twitter when given a numerical slug, e.g. `http://mths.be/8065633451249664` → `http://twitter.com/mathias/status/8065633451249664`. +* Redirect to your main website when no slug is entered, e.g. `http://mths.be/` → `http://mathiasbynens.be/`. +* Redirect to a specific page on your main website when an unknown slug (not in the database) is used, e.g. `http://mths.be/demo/jquery-size` → `http://mathiasbynens.be/demo/jquery-size`. +* Ignores weird trailing characters (`!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`, `*`, `+`, `,`, `-`, `.`, `/`, `@`, `:`, `;`, `<`, `=`, `>`, `[`, `\`, `]`, `^`, `_`, `{`, `|`, `}`, `~`) in slugs — useful when your short URL is run through a crappy link parser, e.g. `http://mths.be/aaa)` → same effect as visiting `http://mths.be/aaa`. +* Generates short, easy-to-type URLs using only `[a-z]` characters. +* DRY, minimal code. +* Correct, semantic use of the available HTTP status codes. + +## Favelets / Bookmarklets + +### Prompt + + javascript:(function(){var%20q=prompt('URL:');if(q){document.location='http://foo.bar/shorten-url.php?'+encodeURIComponent(q)}})(); + +### Shorten this URL + + javascript:(function(){document.location='http://foo.bar/shorten-url.php?'+encodeURIComponent(location.href)})(); + +_— [Mathias](http://mathiasbynens.be/)_ \ No newline at end of file diff --git a/config.php b/config.php new file mode 100644 index 0000000..f47ed9a --- /dev/null +++ b/config.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/database.sql b/database.sql new file mode 100644 index 0000000..bc02ffd --- /dev/null +++ b/database.sql @@ -0,0 +1,7 @@ +CREATE TABLE `redirect` ( + `slug` varchar(14) collate utf8_unicode_ci NOT NULL, + `url` varchar(620) collate utf8_unicode_ci NOT NULL, + `date` datetime NOT NULL, + `hits` bigint(20) NOT NULL default '0', + PRIMARY KEY (`slug`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Used for the URL shortener'; \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..a70147c --- /dev/null +++ b/index.php @@ -0,0 +1,31 @@ +real_escape_string(rtrim($_SERVER['REDIRECT_QUERY_STRING'], '!"#$%&\'()*+,-./@:;<=>[\\]^_`{|}~')); + if (is_numeric($slug) && strlen($slug) > 3) { + redirect('http://twitter.com/' . TWITTER_USERNAME . '/status' . $_SERVER['REQUEST_URI']); + } + $db = new mysqli(MYSQLI_HOST, MYSQLI_USER, MYSQLI_PASSWORD, MYSQLI_DATABASE); + $db->query('SET NAMES "utf8"'); + $result = $db->query('SELECT `url` FROM `redirect` WHERE `slug` = "' . $slug . '"'); + if ($result && $result->num_rows > 0) { + while ($item = $result->fetch_object()) { + if ($db->query('UPDATE `redirect` SET `hits` = `hits` + 1 WHERE `slug` = "' . $slug . '"')) { + redirect($item->url); + } + } + } else { + redirect(DEFAULT_URL . $_SERVER['REQUEST_URI']); + } +} else { + redirect(DEFAULT_URL . '/'); +} + +?> \ No newline at end of file diff --git a/shorten-url.php b/shorten-url.php new file mode 100644 index 0000000..ac78e69 --- /dev/null +++ b/shorten-url.php @@ -0,0 +1,52 @@ +query('SET NAMES "utf8"'); + +$url = $db->real_escape_string(urldecode(trim($_SERVER['QUERY_STRING']))); + +if (in_array($url, array('', 'about:blank', 'undefined', 'http://localhost/'))) { + die('Enter a URL'); +} + +function nextLetter(&$str) { + $str = ('z' === $str ? 'a' : ++$str); +} + +function getNextShortURL($s) { + $a = str_split($s); + $c = count($a); + if (preg_match('/^z*$/', $s)) { // string consists entirely of `z` + return str_repeat('a', $c + 1); + } + while ('z' === $a[--$c]) { + nextLetter($a[$c]); + } + nextLetter($a[$c]); + return implode($a); +} + +$result = $db->query('SELECT `slug` FROM `redirect` WHERE `url` = "' . $url . '" LIMIT 1'); +if ($result && $result->num_rows > 0) { // If there’s already a short URL for this URL + $item = $result->fetch_object(); + echo SHORT_URL . $item->slug; + die(); +} else { + $result = $db->query('SELECT `slug`, `url` FROM `redirect` ORDER BY `date` DESC LIMIT 1'); + if ($result && $result->num_rows > 0) { + while ($item = $result->fetch_object()) { + $slug = getNextShortURL($item->slug); + if ($url !== $item->url && $db->query('INSERT INTO `redirect` (`slug`, `url`, `date`, `hits`) VALUES ("' . $slug . '", "' . $url . '", NOW(), 0)')) { + header('HTTP/1.1 201 Created'); + echo SHORT_URL . $slug; + $db->query('OPTIMIZE TABLE `redirect`'); + } + } + } +} + +?> \ No newline at end of file