├── .gitattributes ├── .gitignore ├── .htaccess ├── LICENSE-MIT.txt ├── README.md ├── config.php ├── database.sql ├── index.php ├── nginx.conf └── shorten.php /.gitattributes: -------------------------------------------------------------------------------- 1 | # Automatically normalize line endings for all text-based files 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteBase / 3 | RewriteRule ^shorten(.*)$ shorten.php?$1 [L,QSA] 4 | RewriteCond %{REQUEST_FILENAME} !-f 5 | RewriteCond %{REQUEST_FILENAME} !-d 6 | RewriteRule ^(.*)$ index.php?slug=$1 [L,QSA] -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Copyright Mathias Bynens 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple PHP URL shortener 2 | 3 | Requires PHP ≥ 5.4.0 or higher. 4 | 5 | ## Installation 6 | 7 | 1. Download the source code as located within this repository, and upload it to your web server. 8 | 2. Use `database.sql` to create the `redirect` table in a database of choice. (Do *not* delete the `INSERT` statement on [line 10](https://github.com/mathiasbynens/php-url-shortener/blob/f64ee342246fa5bf0340641372680a2d398afc79/database.sql#L10) as it is needed to initialize the database.) 9 | 3. Edit `config.php` and enter your database credentials. 10 | 4. For additional *security through obscurity™*, consider renaming `shorten.php` to a secret file name of your choosing and tweaking the `.htaccess` file ([line 3](https://github.com/mathiasbynens/php-url-shortener/blob/f64ee342246fa5bf0340641372680a2d398afc79/.htaccess#L3)) accordingly. 11 | 12 | ## Features 13 | 14 | * Redirect to Twitter when given a numerical slug, e.g. `http://mths.be/8065633451249664` → `http://twitter.com/mathias/status/8065633451249664`. 15 | * Redirect to your Twitter account when `@` is used as a slug, e.g. `http://mths.be/@` → `http://twitter.com/mathias`. 16 | * Redirect to your Google Plus account when `+` is used as a slug, e.g. `http://mths.be/+` → `https://plus.google.com/u/0/116553353277057965424/posts`. 17 | * Redirect to your main website when no slug is entered, e.g. `http://mths.be/` → `http://mathiasbynens.be/`. 18 | * 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`. 19 | * 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`. 20 | * Generates short, easy-to-type URLs using only `[a-z]` characters. 21 | * Doesn’t create multiple short URLs when you try to shorten the same URL. In this case, the script will simply return the existing short URL for that long URL. 22 | * DRY, minimal code. 23 | * Correct, semantic use of the available HTTP status codes. 24 | * Can be used with Twitter for iPhone. Just go to _Settings_ › _Services_ › _URL Shortening_ › _Custom…_ and enter `http://yourshortener.ext/shorten?url=%@`. 25 | 26 | ## Favelets / Bookmarklets 27 | 28 | ### Prompt 29 | 30 | ``` js 31 | javascript:(function(){const%20q=prompt('URL:');if(q){location='https://yourshortener.ext/shorten?url='+encodeURIComponent(q)}}()); 32 | ``` 33 | 34 | ### Shorten this URL 35 | 36 | ``` js 37 | javascript:(function(){location='https://yourshortener.ext/shorten?url='+encodeURIComponent(location.href)}()); 38 | ```` 39 | 40 | ## License 41 | 42 | This script is available under the MIT license. 43 | 44 | ## Author 45 | 46 | * [Mathias Bynens](http://mathiasbynens.be/) 47 | 48 | ## Contributors 49 | 50 | * [Peter Beverloo](http://peter.sh/) 51 | * [Tomislav Biscan](https://github.com/B-Scan) 52 | 53 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /database.sql: -------------------------------------------------------------------------------- 1 | # Why you should use `utf8mb4` instead of `utf8`: http://mathiasbynens.be/notes/mysql-utf8mb4 2 | CREATE TABLE `redirect` ( 3 | `slug` varchar(14) collate utf8mb4_unicode_ci NOT NULL, 4 | `url` varchar(620) collate utf8mb4_unicode_ci NOT NULL, 5 | `date` datetime NOT NULL, 6 | `hits` bigint(20) NOT NULL default '0', 7 | PRIMARY KEY (`slug`) 8 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Used for the URL shortener'; 9 | 10 | INSERT INTO `redirect` VALUES ('a', 'https://github.com/mathiasbynens/php-url-shortener', NOW(), 1); -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 8) { 20 | $url = 'https://twitter.com/' . TWITTER_USERNAME . '/status/' . $slug; 21 | } else { 22 | 23 | $db = new MySQLi(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE); 24 | $db->set_charset('utf8mb4'); 25 | 26 | $escapedSlug = $db->real_escape_string($slug); 27 | $redirectResult = $db->query('SELECT url FROM redirect WHERE slug = "' . $escapedSlug . '"'); 28 | 29 | if ($redirectResult && $redirectResult->num_rows > 0) { 30 | $db->query('UPDATE redirect SET hits = hits + 1 WHERE slug = "' . $escapedSlug . '"'); 31 | $url = $redirectResult->fetch_object()->url; 32 | } else { 33 | $url = DEFAULT_URL . $_SERVER['REQUEST_URI']; 34 | } 35 | 36 | $db->close(); 37 | 38 | } 39 | } 40 | } 41 | 42 | header('Location: ' . $url, null, 301); 43 | 44 | $attributeValue = htmlspecialchars($url); 45 | ?> 46 | Continue 47 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | # Match this with your setup 4 | listen 80; 5 | server_name _; 6 | 7 | root /var/www/html; 8 | index index.php; 9 | 10 | # START rewrite rules 11 | location /shorten { 12 | try_files $uri $uri/ /shorten.php?$args; 13 | } 14 | 15 | location / { 16 | rewrite ^/(.*)$ /index.php?slug=$1 last; 17 | try_files $uri $uri/ /index.php; 18 | } 19 | # END rewrite rules 20 | 21 | # Match this with your setup 22 | location ~ \.php$ { 23 | include snippets/fastcgi-php.conf; 24 | fastcgi_pass unix:/run/php/php7.0-fpm.sock; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /shorten.php: -------------------------------------------------------------------------------- 1 | set_charset('utf8mb4'); 37 | 38 | $url = $db->real_escape_string($url); 39 | 40 | $result = $db->query('SELECT slug FROM redirect WHERE url = "' . $url . '" LIMIT 1'); 41 | if ($result && $result->num_rows > 0) { // If there’s already a short URL for this URL 42 | die(SHORT_URL . $result->fetch_object()->slug); 43 | } else { 44 | $result = $db->query('SELECT slug, url FROM redirect ORDER BY date DESC, slug DESC LIMIT 1'); 45 | if ($result && $result->num_rows > 0) { 46 | $slug = getNextShortURL($result->fetch_object()->slug); 47 | if ($db->query('INSERT INTO redirect (slug, url, date, hits) VALUES ("' . $slug . '", "' . $url . '", NOW(), 0)')) { 48 | header('HTTP/1.1 201 Created'); 49 | echo SHORT_URL . $slug; 50 | $db->query('OPTIMIZE TABLE `redirect`'); 51 | } 52 | } 53 | } 54 | 55 | ?> --------------------------------------------------------------------------------