diff --git a/app/ClickUrl.php b/app/ClickUrl.php index b7f0a41c..e6e6219a 100644 --- a/app/ClickUrl.php +++ b/app/ClickUrl.php @@ -29,7 +29,7 @@ class ClickUrl extends Model * @var array */ protected $fillable = [ - 'short_url', 'click', 'real_click', 'country', 'country_full', 'referer', 'ip_address', 'ip_hashed', 'ip_anonymized', + 'short_url', 'click', 'real_click', 'country', 'country_full', 'user_agent', 'browser', 'browser_version', 'os', 'referer', 'ip_address', 'ip_hashed', 'ip_anonymized', ]; /** diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 86d38291..8314be2b 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -34,6 +34,8 @@ protected function schedule(Schedule $schedule) { // $schedule->command('inspire') // ->hourly(); + $schedule->command('browscap:update') + ->weekly(); } /** diff --git a/app/Http/Controllers/ClickUrlController.php b/app/Http/Controllers/ClickUrlController.php index ade842c2..15b54410 100644 --- a/app/Http/Controllers/ClickUrlController.php +++ b/app/Http/Controllers/ClickUrlController.php @@ -17,6 +17,10 @@ use GeoIp2\Database\Reader; use Illuminate\Http\Request; use Illuminate\Support\Facades\Redirect; +use BrowscapPHP\Browscap; +use BrowscapPHP\Exception; +use Doctrine\Common\Cache\FilesystemCache; +use Roave\DoctrineSimpleCache\SimpleCacheAdapter; /** * Controller handling the actual page of the corresponding URL, that redirects the user. @@ -77,17 +81,24 @@ public function click($url) $real_click = 0; } + $userAgent = request()->server('HTTP_USER_AGENT'); + $browser = $this->getBrowser($userAgent); + $data = [ 'short_url' => $url, 'click' => $click, 'real_click' => $real_click, 'country' => $countries['countryCode'], 'country_full' => $countries['countryName'], + 'user_agent' => $userAgent, + 'browser' => $browser['browser'], + 'browser_version' => $browser['browserVersion'], + 'os' => $browser['os'], 'referer' => $referer ?? null, 'ip_address' => $ip, 'ip_hashed' => $hashed, 'ip_anonymized' => $anonymized, - ]; + ]; ClickUrl::store($data); @@ -113,4 +124,27 @@ public function getCountries($ip) return compact('countryCode', 'countryName'); } } + + protected function getBrowser($userAgent) + { + $fileCache = new FilesystemCache(config('browscap.cache')); + $cache = new SimpleCacheAdapter($fileCache); + $browscap = new Browscap($cache, logger()->driver()); + + try { + $result = $browscap->getBrowser($userAgent); + } catch (Exception $e) { + return [ + 'browser' => null, + 'browserVersion' => null, + 'os' => null + ]; + } + + return [ + 'browser' => $result->browser, + 'browserVersion' => $result->version, + 'os' => $result->platform + ]; + } } diff --git a/composer.json b/composer.json index ec9a00c9..9c3f3f88 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "laravel/passport": "^7.2", "laravel/tinker": "^1.0", "phpunit/phpunit": "8", + "propa/laravel-browscap": "^2.0", "simplesoftwareio/simple-qrcode": "^2.0", "spatie/laravel-honeypot": "^1.3", "yajra/laravel-datatables-oracle": "~9.0" diff --git a/composer.lock b/composer.lock index 5a5166ed..70008117 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d2de0669e50d55810c103b18195b135c", + "content-hash": "2304f7577cb024645ef13ab8d34a89af", "packages": [ { "name": "anlutro/l4-settings", @@ -111,6 +111,82 @@ "homepage": "https://github.com/Bacon/BaconQrCode", "time": "2017-10-17T09:59:25+00:00" }, + { + "name": "browscap/browscap-php", + "version": "4.2.1", + "source": { + "type": "git", + "url": "https://github.com/browscap/browscap-php.git", + "reference": "f37794ae64b9ee53cef725b8c368aa5ca114f374" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/browscap/browscap-php/zipball/f37794ae64b9ee53cef725b8c368aa5ca114f374", + "reference": "f37794ae64b9ee53cef725b8c368aa5ca114f374", + "shasum": "" + }, + "require": { + "daverandom/exceptional-json": "^1.0.4", + "ext-json": "*", + "guzzlehttp/guzzle": "^6.2", + "monolog/monolog": "^1.23 || ^2.0", + "php": ">=7.1.0,<7.4.0", + "psr/simple-cache": "^1.0", + "roave/doctrine-simplecache": "^1.1 || ^2.0", + "symfony/console": "^3.3 || ^4.0", + "symfony/filesystem": "^3.3 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.13", + "mikey179/vfsstream": "^1.6", + "pepakriz/phpstan-exception-rules": "^0.3 || ^0.4", + "phpstan/phpstan": "^0.10", + "phpstan/phpstan-beberlei-assert": "^0.10", + "phpstan/phpstan-deprecation-rules": "^0.10", + "phpstan/phpstan-phpunit": "^0.10", + "phpstan/phpstan-strict-rules": "^0.10", + "phpunit/phpunit": "^6.5 || ^7.0" + }, + "suggest": { + "ext-curl": "to use curl requests to get the ini file" + }, + "bin": [ + "bin/browscap-php" + ], + "type": "library", + "autoload": { + "psr-4": { + "BrowscapPHP\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Stoppani", + "email": "jonathan.stoppani@gmail.com" + }, + { + "name": "James Titcumb", + "email": "james@asgrim.com" + }, + { + "name": "Thomas Mueller", + "email": "mimmi20@live.de" + } + ], + "description": "Standalone replacement for php's native get_browser() function", + "homepage": "https://github.com/browscap/browscap-php", + "keywords": [ + "browser", + "capabilities", + "get_browser", + "user agent" + ], + "time": "2019-10-18T08:06:44+00:00" + }, { "name": "composer/ca-bundle", "version": "1.2.4", @@ -167,6 +243,44 @@ ], "time": "2019-08-30T08:44:50+00:00" }, + { + "name": "daverandom/exceptional-json", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/ExceptionalJSON.git", + "reference": "fed957142b4687b079495c80975666dd1a67d61d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/ExceptionalJSON/zipball/fed957142b4687b079495c80975666dd1a67d61d", + "reference": "fed957142b4687b079495c80975666dd1a67d61d", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ExceptionalJSON\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright" + } + ], + "description": "JSON encoding and decoding that throws exceptions on failure", + "time": "2018-06-11T11:25:57+00:00" + }, { "name": "defuse/php-encryption", "version": "v2.2.1", @@ -263,6 +377,89 @@ "description": "implementation of xdg base directory specification for php", "time": "2014-10-24T07:27:01+00:00" }, + { + "name": "doctrine/cache", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "c15dcd24b756f9e52ea7c3ae8227354f3628f11a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/c15dcd24b756f9e52ea7c3ae8227354f3628f11a", + "reference": "c15dcd24b756f9e52ea7c3ae8227354f3628f11a", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "doctrine/coding-standard": "^6.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "keywords": [ + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "riak", + "xcache" + ], + "time": "2019-11-11T10:31:52+00:00" + }, { "name": "doctrine/inflector", "version": "1.3.1", @@ -3035,6 +3232,7 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2019-09-17T06:23:10+00:00" }, { @@ -3119,6 +3317,61 @@ ], "time": "2019-02-01T05:41:59+00:00" }, + { + "name": "propa/laravel-browscap", + "version": "v2.0.6", + "source": { + "type": "git", + "url": "https://github.com/kulbakin/laravel-browscap.git", + "reference": "5a87df5de690ef65ee4f2b352dc557e3091563d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kulbakin/laravel-browscap/zipball/5a87df5de690ef65ee4f2b352dc557e3091563d5", + "reference": "5a87df5de690ef65ee4f2b352dc557e3091563d5", + "shasum": "" + }, + "require": { + "browscap/browscap-php": "^4.0", + "illuminate/support": "^5.0|^6.0|^7.0", + "php": "^7.1.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Propa\\BrowscapPHP\\BrowscapServiceProvider" + ], + "aliases": { + "Browscap": "Propa\\BrowscapPHP\\Facades\\Browscap" + } + } + }, + "autoload": { + "psr-4": { + "Propa\\BrowscapPHP\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pavel Kulbakin", + "email": "p.kulbakin@gmail.com" + } + ], + "description": "Browscap-PHP integration for Laravel 5/6", + "keywords": [ + "Browscap", + "browscap-php", + "browser", + "laravel", + "user-agent" + ], + "time": "2020-04-03T12:53:14+00:00" + }, { "name": "psr/container", "version": "1.0.0", @@ -3561,6 +3814,58 @@ ], "time": "2018-07-19T23:38:55+00:00" }, + { + "name": "roave/doctrine-simplecache", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/Roave/DoctrineSimpleCache.git", + "reference": "165599198031cf2a14b52bc7de6eca970e9dfdf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/DoctrineSimpleCache/zipball/165599198031cf2a14b52bc7de6eca970e9dfdf5", + "reference": "165599198031cf2a14b52bc7de6eca970e9dfdf5", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.7", + "php": "^7.2,<7.5", + "psr/simple-cache": "^1.0" + }, + "provide": { + "psr/simple-cache-implementation": "1.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "cache/tag-interop": "dev-master", + "infection/infection": "^0.14.2", + "phpunit/phpunit": "^8.4", + "symfony/console": "^4.3", + "symfony/phpunit-bridge": "^4.4@dev" + }, + "type": "library", + "autoload": { + "psr-4": { + "Roave\\DoctrineSimpleCache\\": "src/" + }, + "files": [ + "namespace-bc-aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "James Titcumb", + "email": "james@asgrim.com" + } + ], + "description": "Doctrine Cache adapter for PSR-16 Simple Cache", + "time": "2019-10-23T17:43:38+00:00" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -4625,6 +4930,56 @@ ], "time": "2019-09-17T09:54:03+00:00" }, + { + "name": "symfony/filesystem", + "version": "v4.3.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2019-08-20T14:07:54+00:00" + }, { "name": "symfony/finder", "version": "v4.3.8", @@ -6520,89 +6875,6 @@ ], "time": "2019-11-06T16:40:04+00:00" }, - { - "name": "doctrine/cache", - "version": "1.9.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "c15dcd24b756f9e52ea7c3ae8227354f3628f11a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/c15dcd24b756f9e52ea7c3ae8227354f3628f11a", - "reference": "c15dcd24b756f9e52ea7c3ae8227354f3628f11a", - "shasum": "" - }, - "require": { - "php": "~7.1" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "alcaeus/mongo-php-adapter": "^1.1", - "doctrine/coding-standard": "^6.0", - "mongodb/mongodb": "^1.1", - "phpunit/phpunit": "^7.0", - "predis/predis": "~1.0" - }, - "suggest": { - "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "riak", - "xcache" - ], - "time": "2019-11-11T10:31:52+00:00" - }, { "name": "doctrine/dbal", "version": "v2.10.0", @@ -7608,56 +7880,6 @@ "phra" ], "time": "2015-10-13T18:44:15+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v4.3.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", - "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Filesystem Component", - "homepage": "https://symfony.com", - "time": "2019-08-20T14:07:54+00:00" } ], "aliases": [], diff --git a/config/app.php b/config/app.php index db874e89..96fb4fa6 100644 --- a/config/app.php +++ b/config/app.php @@ -185,7 +185,7 @@ App\Providers\RouteServiceProvider::class, Barryvdh\Debugbar\ServiceProvider::class, Jenssegers\Agent\AgentServiceProvider::class, - + Propa\BrowscapPHP\BrowscapServiceProvider::class, ], /* @@ -237,6 +237,7 @@ 'Debugbar' => Barryvdh\Debugbar\Facade::class, 'Setting' => 'anlutro\LaravelSettings\Facade', 'Agent' => Jenssegers\Agent\Facades\Agent::class, + 'Browscap' => Propa\BrowscapPHP\Facades\Browscap::class, ], ]; diff --git a/database/migrations/2020_08_16_094943_add_browser_os_to_clicks_table.php b/database/migrations/2020_08_16_094943_add_browser_os_to_clicks_table.php new file mode 100644 index 00000000..e06230f8 --- /dev/null +++ b/database/migrations/2020_08_16_094943_add_browser_os_to_clicks_table.php @@ -0,0 +1,35 @@ +string('user_agent')->after('country_full'); + $table->string('browser', 30)->after('user_agent')->nullable(); + $table->string('browser_version', 10)->after('browser')->nullable(); + $table->string('os', 30)->after('browser_version')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('clicks', function (Blueprint $table) { + $table->dropColumn(['user_agent', 'browser', 'browser_version', 'os']); + }); + } +}