├── .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 | ?>
--------------------------------------------------------------------------------