├── .github └── FUNDING.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.md ├── composer.json ├── config └── url-shortener.php ├── database └── migrations │ ├── 2021_08_04_101021_create_url_shorteners_table.php │ ├── 2021_08_04_142526_update_url_key_length.php │ └── 2021_08_12_165626_addunique_url_key.php ├── phpunit.xml ├── readme.md ├── src ├── LaravelUrlShortenerServiceProvider.php ├── Models │ └── UrlShortener.php └── routes │ └── web.php └── tests └── TestCase.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: magarrent 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | .env 3 | .phpunit.result.cache -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/magarrent/laravel-url-shortener). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ composer test 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Marc Garcia Torrent (Kodio Technologies) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magarrent/laravel-url-shortener", 3 | "description": "Simpler Url Shortener for Laravel", 4 | "type": "package", 5 | "license": "MIT", 6 | "keywords": [ 7 | "laravel" 8 | ], 9 | "authors": [ 10 | { 11 | "name": "Marc Garcia Torrent (Kodio Technologies)", 12 | "email": "magarrent@gmail.com" 13 | } 14 | ], 15 | "require": { 16 | "illuminate/support": "^7.0|^8.0|^9.0", 17 | "doctrine/dbal": "^3" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "Magarrent\\LaravelUrlShortener\\": "./src" 22 | } 23 | }, 24 | "autoload-dev": { 25 | "psr-4": { 26 | "Magarrent\\LaravelUrlShortener\\Tests\\": "tests" 27 | } 28 | }, 29 | "scripts": { 30 | "test": "vendor/bin/phpunit" 31 | }, 32 | "extra": { 33 | "laravel": { 34 | "providers": [ 35 | "Magarrent\\LaravelUrlShortener\\LaravelUrlShortenerServiceProvider" 36 | ] 37 | } 38 | }, 39 | "require-dev": { 40 | "orchestra/testbench": "^6.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /config/url-shortener.php: -------------------------------------------------------------------------------- 1 | 15, // http://test.test/X-random-key-length 5 | ]; 6 | -------------------------------------------------------------------------------- /database/migrations/2021_08_04_101021_create_url_shorteners_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('to_url'); 19 | $table->string('url_key', 6); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('url_shorteners'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/migrations/2021_08_04_142526_update_url_key_length.php: -------------------------------------------------------------------------------- 1 | string('url_key', 255)->change(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('url_shorteners', function (Blueprint $table) { 29 | $table->string('url_key', 6)->change(); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2021_08_12_165626_addunique_url_key.php: -------------------------------------------------------------------------------- 1 | unique('url_key'); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('url_shorteners', function (Blueprint $table) { 29 | $table->dropUnique('url_key'); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | tests 9 | 10 | 11 | 12 | 13 | ./app 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Laravel Url Shortener 3 | 4 | ![Laravel Url Shortener](https://user-images.githubusercontent.com/6561770/128169387-4c192224-79e6-46fc-a75b-ed18981e74e3.png) 5 | 6 | ![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square) 7 | ![Package Size](https://img.shields.io/github/languages/code-size/magarrent/laravel-url-shortener) 8 | 9 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/magarrent) 10 | 11 | ## Install 12 | `composer require magarrent/laravel-url-shortener` 13 | 14 | Run migrations: 15 | 16 | `php artisan migrate` 17 | 18 | ----- 19 | 20 | ## Configuration 21 | 22 | If you want to configurate some package parameters, run vendor publish: 23 | 24 | `php artisan vendor:publish --provider="Magarrent\LaravelUrlShortener\LaravelUrlShortenerServiceProvider"` 25 | 26 | Change the Key Url length in the `url-shortener.php` config file: 27 | 28 | ```php 29 | 6, // http://test.test/X-random-key-length 33 | ]; 34 | 35 | ``` 36 | 37 | ----- 38 | ## Usage 39 | Import the UrlShortener in your php file. 40 | 41 | use Magarrent\LaravelUrlShortener\Models\UrlShortener; 42 | 43 | Then you can use the Url shortener package to redirect **internal and external links.** 44 | 45 | UrlShortener::generateShortUrl("https://www.kodio.tech") 46 | 47 | UrlShortener::generateShortUrl("/my-next/local/page") 48 | 49 | Ex. Redirection: 50 | 51 | https://your.url/H8g9Jx => https://www.kodio.tech 52 | 53 | ----- 54 | You only have to send the Url To param to the UrlShortener model: 55 | 56 | public static function generateShortUrl(String $toUrl): String 57 | 58 | 59 | ## Roadmap 60 | 61 | - Ask me for more features! You can buy me a coffe too :) 62 | 63 | ## Changelog 64 | 65 | ### 1.0.4 66 | - Added support for **Laravel 9** 67 | - Fixed installation problem with migrations 68 | 69 | ### 1.0.2 70 | - Add `getOriginalUrlFromKey` function to model 71 | - Added configuration for Url key length 72 | 73 | ### 1.0 74 | - First version 75 | 76 | ## Contributing 77 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 78 | 79 | ## Credits 80 | 81 | - [Marc Garcia Torrent (Kodio Technologies)](https://github.com/Magarrent) 82 | - [All Contributors](https://github.com/Magarrent/laravel-url-shortener/contributors) 83 | 84 | ## Security 85 | If you discover any security-related issues, please email magarrent@gmail.com instead of using the issue tracker. 86 | 87 | ## License 88 | The MIT License (MIT). Please see [License File](/LICENSE.md) for more information. 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/LaravelUrlShortenerServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom(__DIR__ . '/../config/url-shortener.php', 'url-shortener'); 18 | } 19 | 20 | /** 21 | * Bootstrap services. 22 | * 23 | * @return void 24 | */ 25 | public function boot() 26 | { 27 | 28 | if(!Schema::hasTable('url_shorteners')) { 29 | if (!$this->app->runningInConsole()) { 30 | throw new \Exception("You must run php artisan migrate to use URL Shortener"); 31 | } 32 | } else { 33 | // Load custom routes 34 | $this->loadRoutesFrom(__DIR__ . '/routes/web.php'); 35 | } 36 | 37 | // Load migrations 38 | $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); 39 | 40 | // Load config file 41 | if ($this->app->runningInConsole()) { 42 | $this->publishes([ 43 | __DIR__ . '/../config/url-shortener.php' => config_path('url-shortener.php'), 44 | ], 'config'); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Models/UrlShortener.php: -------------------------------------------------------------------------------- 1 | $toUrl, 26 | 'url_key' => $urlKey 27 | ]); 28 | 29 | return app()->make('url')->to($urlKey); 30 | } 31 | 32 | /** 33 | * Generate a random unique key for url shortener 34 | * 35 | * @return String 36 | */ 37 | protected static function getUniqueKey(): String { 38 | $randomKey = Str::random(config('url-shortener.url_key_length')); 39 | while(self::where('url_key', $randomKey)->exists()) { 40 | $randomKey = Str::random(config('url-shortener.url_key_length')); 41 | } 42 | 43 | return $randomKey; 44 | } 45 | 46 | /** 47 | * Get original target Url from key 48 | * 49 | * @param String $urlKey 50 | * @return Mixed String|Boolean 51 | */ 52 | public static function getOriginalUrlFromKey(String $urlKey): Mixed { 53 | $url = self::where('url_key', $urlKey)->first(); 54 | 55 | if(!$url) return false; 56 | 57 | return $url->to_url; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/routes/web.php: -------------------------------------------------------------------------------- 1 | url_key, $url->to_url, 301); 9 | } 10 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 |