{"id":18941012,"url":"https://github.com/cleaniquecoders/shrinkr","last_synced_at":"2025-07-12T06:33:11.264Z","repository":{"id":258602288,"uuid":"874505821","full_name":"cleaniquecoders/shrinkr","owner":"cleaniquecoders","description":"Shrinkr is a Laravel package for shortening URLs, with custom slugs, analytics, branded domains, and seamless API integration.","archived":false,"fork":false,"pushed_at":"2025-05-01T10:15:08.000Z","size":90,"stargazers_count":12,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-29T09:18:10.782Z","etag":null,"topics":["laravel","php","shortener"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cleaniquecoders.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"Cleanique Coders"}},"created_at":"2024-10-18T00:31:29.000Z","updated_at":"2025-06-22T10:36:27.000Z","dependencies_parsed_at":"2024-12-31T22:42:04.854Z","dependency_job_id":"f3b2d3d3-8327-49ca-a47b-d838bce09f1d","html_url":"https://github.com/cleaniquecoders/shrinkr","commit_stats":null,"previous_names":["cleaniquecoders/shrinkr"],"tags_count":4,"template":false,"template_full_name":"spatie/package-skeleton-laravel","purl":"pkg:github/cleaniquecoders/shrinkr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleaniquecoders%2Fshrinkr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleaniquecoders%2Fshrinkr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleaniquecoders%2Fshrinkr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleaniquecoders%2Fshrinkr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cleaniquecoders","download_url":"https://codeload.github.com/cleaniquecoders/shrinkr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleaniquecoders%2Fshrinkr/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264951608,"owners_count":23687973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["laravel","php","shortener"],"created_at":"2024-11-08T12:25:17.492Z","updated_at":"2025-07-12T06:33:10.920Z","avatar_url":"https://github.com/cleaniquecoders.png","language":"PHP","funding_links":["https://github.com/sponsors/Cleanique Coders"],"categories":[],"sub_categories":[],"readme":"[![Latest Version on Packagist](https://img.shields.io/packagist/v/cleaniquecoders/shrinkr.svg?style=flat-square)](https://packagist.org/packages/cleaniquecoders/shrinkr)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/cleaniquecoders/shrinkr/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/cleaniquecoders/shrinkr/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/cleaniquecoders/shrinkr/fix-php-code-style-issues.yml?branch=main\u0026label=code%20style\u0026style=flat-square)](https://github.com/cleaniquecoders/shrinkr/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/cleaniquecoders/shrinkr.svg?style=flat-square)](https://packagist.org/packages/cleaniquecoders/shrinkr)\n\n---\n\n# Shrinkr\n\nShrinkr is a Laravel package for shortening URLs, offering custom slugs, analytics, branded domains, and API integration.\n\nShrinkr makes it easy to convert long URLs into short, shareable links. With features like **custom slugs**, **click analytics**, **branded domains**, and seamless **API support**, Shrinkr empowers users to manage URLs effectively.\n\n---\n\n## Features\n\n- [x] **Shorten URLs** with or without custom slugs.\n- [x] **Analytics tracking**: Track clicks, referrers, IP addresses, and devices.\n- [x] **Branded domains**: Use custom domains for shortened URLs.\n- [x] **Configurable logging**: Store logs in files or databases.\n- [ ] **API support**: Programmatically shorten and resolve URLs.\n- [x] ~~**Rate Limiting**: To prevent abuse (e.g., spamming requests to shorten URLs or resolve them).~~ **Middleware**: Added middleware configuration. Default is `throttle:60,1`.\n- [ ] ~~**Protected URLs**: Add password protection or other access restrictions to certain URLs, ensuring only authorized users can access the content.~~ After further research, it's not relevant if the original URL is unprotected. Hence, this feature will be skip.\n- [ ] ~~**QR Codes**: Provide users with QR codes for easy sharing of URLs, especially on mobile devices.~~ Use package such as [Simple QrCode](https://github.com/SimpleSoftwareIO/simple-qrcode) to generate the QR Code for the shortened URL.\n- [x] **Link Health Monitoring**: Ensure that the original URLs are still reachable and valid \u0026 automatically disable or notify users if a link becomes broken or inactive.\n- [x] **Event \u0026 Listeners**: Improve system decoupling by using events to trigger actions asynchronously (e.g., logging clicks, sending notifications).\n- [x] **Expiry**: Allow expiry to be set - in minutes.\n\n---\n\n## Installation\n\nInstall the package via Composer:\n\n```bash\ncomposer require cleaniquecoders/shrinkr\n```\n\nPublish the migration files and migrate:\n\n```bash\nphp artisan vendor:publish --tag=\"shrinkr-migrations\"\nphp artisan migrate\n```\n\nPublish the config file:\n\n```bash\nphp artisan vendor:publish --tag=\"shrinkr-config\"\n```\n\nThe published configuration file (`config/shrinkr.php`) will allow you to customize settings.\n\n---\n\n## Configuration\n\nYou can configure **logging options** by modifying the `config/shrinkr.php` file.\n\n```php\nreturn [\n    'logger' =\u003e \\CleaniqueCoders\\Shrinkr\\Actions\\Logger\\LogToFile::class, // Default logger\n];\n```\n\nTo log to a **database**, change the logger to:\n\n```php\n'logger' =\u003e \\CleaniqueCoders\\Shrinkr\\Actions\\Logger\\LogToDatabase::class,\n```\n\n---\n\n## **Usage**\n\nHere’s a basic usage example using the Shrinkr facade, actions, and events.\n\n---\n\n### **1. Shorten a URL**\n\nYou can shorten a URL with or without a **custom slug** and **expiry duration**.\n\n```php\nuse CleaniqueCoders\\Shrinkr\\Facades\\Shrinkr;\n\n// Shorten a URL with default random slug\n$shortUrl = Shrinkr::shorten('https://example.com/long-url', auth()-\u003eid());\necho $shortUrl; // Outputs: https://yourdomain.com/abc123\n\n// Shorten a URL with a custom slug and expiry duration (e.g., 60 minutes)\n$shortUrlWithCustomSlug = Shrinkr::shorten('https://example.com/long-url', auth()-\u003eid(), [\n    'custom_slug' =\u003e 'my-slug',\n    'expiry_duration' =\u003e 60, // Expires in 60 minutes\n]);\necho $shortUrlWithCustomSlug; // Outputs: https://yourdomain.com/my-slug\n```\n\n---\n\n### **2. Retrieve the Original URL**\n\nUse the `resolve()` method to retrieve the **original URL** from a shortened one.\n\n```php\n$originalUrl = Shrinkr::resolve('abc123');\necho $originalUrl; // Outputs: https://example.com/long-url\n```\n\nWhen the URL is accessed, the **`UrlAccessed` event** will be dispatched automatically to track the visit.\n\n---\n\n### **3. Update an Existing Short URL**\n\nYou can update an existing short URL with a new **custom slug** or **expiry duration**.\n\n```php\nuse CleaniqueCoders\\Shrinkr\\Models\\Url;\nuse CleaniqueCoders\\Shrinkr\\Facades\\Shrinkr;\n\n$url = Url::find(1);\n\n// Update the short URL with a new slug and expiry duration\n$updatedUrl = Shrinkr::update($url, [\n    'custom_slug' =\u003e 'updated-slug',\n    'expiry_duration' =\u003e 120, // 2 hours from now\n]);\necho $updatedUrl-\u003eshortened_url; // Outputs: https://yourdomain.com/updated-slug\n```\n\n---\n\n### **4. Event Handling**\n\n#### **UrlAccessed Event**\n\nThe **`UrlAccessed` event** is dispatched whenever a shortened URL is accessed. You can listen for this event to **log analytics or trigger notifications**.\n\n**Example: Log URL Access in a Listener**\n\n```php\nnamespace CleaniqueCoders\\Shrinkr\\Listeners;\n\nuse CleaniqueCoders\\Shrinkr\\Events\\UrlAccessed;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass LogUrlAccess\n{\n    public function handle(UrlAccessed $event)\n    {\n        $url = $event-\u003eurl;\n\n        Log::info('URL accessed', [\n            'url_id' =\u003e $url-\u003eid,\n            'shortened_url' =\u003e $url-\u003eshortened_url,\n            'accessed_at' =\u003e now(),\n        ]);\n    }\n}\n```\n\n#### **UrlExpired Event**\n\nThe **`UrlExpired` event** is dispatched when a URL has expired, either through a scheduled check or upon access. You can listen to this event to **notify the user or perform other actions**.\n\n**Example: Notify on URL Expiry in a Listener**\n\n```php\nnamespace CleaniqueCoders\\Shrinkr\\Listeners;\n\nuse CleaniqueCoders\\Shrinkr\\Events\\UrlExpired;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass NotifyUrlExpired\n{\n    public function handle(UrlExpired $event)\n    {\n        $url = $event-\u003eurl;\n\n        Log::warning('URL expired', [\n            'url_id' =\u003e $url-\u003eid,\n            'shortened_url' =\u003e $url-\u003eshortened_url,\n            'expired_at' =\u003e now(),\n        ]);\n\n        // Optionally, notify the user about the expired URL.\n    }\n}\n```\n\n---\n\n### **5. Automatically Expire URLs**\n\nIf you’ve set an **expiry duration**, the URL will be marked as expired once that time has passed. You can also run the **expiry command** manually or schedule it.\n\n**Run the Expiry Command Manually:**\n\n```bash\nphp artisan shrinkr:check-expiry\n```\n\n**Schedule the Expiry Command:**\n\nIn your **`app/Console/Kernel.php`**:\n\n```php\n$schedule-\u003ecommand('shrinkr:check-expiry')-\u003ehourly();\n```\n\n---\n\n### **6. Monitor URL Health**\n\nThe **Link Health Monitoring** feature allows you to **check if URLs are reachable** and mark them as **active or expired**.\n\n#### **Check Health Action**\n\nUse the `CheckUrlHealthAction` to **manually check the health** of a specific URL.\n\n```php\nuse CleaniqueCoders\\Shrinkr\\Actions\\CheckUrlHealthAction;\nuse CleaniqueCoders\\Shrinkr\\Models\\Url;\n\n$url = Url::find(1); // Retrieve URL instance\n\n$action = new CheckUrlHealthAction();\n$isHealthy = $action-\u003eexecute($url);\n\nif ($isHealthy) {\n    echo \"URL is active.\";\n} else {\n    echo \"URL is expired.\";\n}\n```\n\n#### **Check Health Command**\n\nUse the Artisan command to **check the health of all URLs** in bulk.\n\n```bash\nphp artisan shrinkr:check-health\n```\n\nThis command will:\n\n1. **Check the status** of all URLs.\n2. **Mark expired URLs** and dispatch the `UrlExpired` event.\n3. **Provide real-time output** on the status of each URL.\n\nExample output:\n\n```\nURL abc123 is now marked as active.\nURL xyz456 is now marked as expired.\nURL health check completed.\n```\n\n#### **Schedule the Health Check Command**\n\nYou can **automatically run the health check** at regular intervals using Laravel’s scheduler.\n\nIn your **`app/Console/Kernel.php`**:\n\n```php\nprotected function schedule(Schedule $schedule)\n{\n    $schedule-\u003ecommand('shrinkr:check-health')-\u003ehourly();\n}\n```\n\nThis will ensure that all URLs are **continuously monitored** and marked as expired when necessary.\n\n---\n\n### **7. Redirect Tracking**\n\nThe redirect feature tracks detailed information such as:\n\n- **IP address** of the visitor\n- **Browser and OS** (via User-Agent parsing)\n- **Referrer** (where the link was clicked)\n- **Headers and query parameters**\n- Optionally **store logs in a database** or log file\n\nExample database log entry:\n\n| url_id | ip         | browser | platform | referrer     | created_at          |\n|----------|------------|---------|----------|--------------|---------------------|\n| 1   | 192.168.1.1 | Chrome  | Windows  | google.com   | 2024-10-18 12:34:56 |\n\n---\n\n### **8. Routing**\n\nYou can configure custom domain for the URL by configuring:\n\n```php\n'domain' =\u003e 'bite.ly',\n```\n\nYou may also change the middleware or add new one by configuring:\n\n```php\n'middleware' =\u003e ['auth', 'verified', 'throttle:600,1']\n```\n\n## Testing\n\nRun the tests using:\n\n```bash\ncomposer test\n```\n\n---\n\n## Changelog\n\nRefer to the [CHANGELOG](CHANGELOG.md) for the latest updates and changes.\n\n---\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING](CONTRIBUTING.md) for guidelines.\n\n---\n\n## Security Vulnerabilities\n\nReport security vulnerabilities by reviewing [our security policy](../../security/policy).\n\n---\n\n## Credits\n\n- [Nasrul Hazim Bin Mohamad](https://github.com/nasrulhazim)\n- [All Contributors](../../contributors)\n\n---\n\n## License\n\nShrinkr is open-sourced software licensed under the [MIT license](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcleaniquecoders%2Fshrinkr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcleaniquecoders%2Fshrinkr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcleaniquecoders%2Fshrinkr/lists"}