optimized visitor model, migration, middleware, seeder

pull/44/head
A1Gard 2 months ago
parent 8bef2c82b4
commit 3166710510

@ -2,6 +2,8 @@
namespace App\Helpers; namespace App\Helpers;
use App\Models\Visitor;
/** /**
* @package Helpers * @package Helpers
* @author A1Gard <a1gard@4xmen.ir> * @author A1Gard <a1gard@4xmen.ir>
@ -25,45 +27,7 @@ class TVisitor {
if (!isset($_SERVER['HTTP_USER_AGENT'])) if (!isset($_SERVER['HTTP_USER_AGENT']))
return 0; return 0;
$os_list = array( $os_list = array_values(Visitor::$osList);
'(Linux)',
'(Windows NT 11.0)', // Added Windows 11
'(Windows NT 10.0)',
'(Windows NT 6.3)',
'(Windows NT 6.2)',
'(Windows NT 6.1)',
'(Windows NT 6.0)',
'(Windows NT 5.2)',
'(Windows NT 5.1)',
'(Windows NT 5.0)',
'(Windows NT 4.0)',
'(Win 9x 4.90)',
'(Windows 98)',
'(Windows 95)',
'(Windows CE)',
'Windows (iPhone|iPad)',
'(iPhone)|(iPad)',
'(Mac OS X)',
'(MacPPC)|(Mac_PowerPC)|(Macintosh)',
'(Ubuntu)',
'(Linux Mint)',
'(Debian)',
'(Fedora)',
'(Red Hat)',
'(SuSE)',
'(Android)',
'(webOS)|(hpwOS)',
'(BlackBerry)',
'(Symbian)',
'(FreeBSD)',
'(OpenBSD)',
'(NetBSD)',
'(SunOS)',
'(OpenSolaris)',
'(Chrome OS)',
'(CrOS)',
'(bot)'
);
foreach ($os_list as $index => $match) { foreach ($os_list as $index => $match) {
if (preg_match("/$match/i", $_SERVER['HTTP_USER_AGENT'])) { if (preg_match("/$match/i", $_SERVER['HTTP_USER_AGENT'])) {
@ -82,43 +46,7 @@ class TVisitor {
if (!isset($_SERVER['HTTP_USER_AGENT'])) if (!isset($_SERVER['HTTP_USER_AGENT']))
return 'Unknown'; return 'Unknown';
$os_list = array( $os_list = Visitor::$osList;
'Linux' => '(Linux)',
'Windows 11' => '(Windows NT 11.0)', // Added Windows 11
'Windows 10' => '(Windows NT 10.0)',
'Windows 8.1' => '(Windows NT 6.3)',
'Windows 8' => '(Windows NT 6.2)',
'Windows 7' => '(Windows NT 6.1)',
'Windows Vista' => '(Windows NT 6.0)',
'Windows Server 2003/XP x64' => '(Windows NT 5.2)',
'Windows XP' => '(Windows NT 5.1)',
'Windows 2000' => '(Windows NT 5.0)',
'Windows ME' => '(Win 9x 4.90)',
'Windows 98' => '(Windows 98)',
'Windows 95' => '(Windows 95)',
'Windows CE' => '(Windows CE)',
'Windows (iPhone/iPad)' => 'Windows (iPhone|iPad)',
'iPhone/iPad' => '(iPhone)|(iPad)',
'Mac OS X' => '(Mac OS X)',
'Mac OS' => '(MacPPC)|(Mac_PowerPC)|(Macintosh)',
'Ubuntu' => '(Ubuntu)',
'Linux Mint' => '(Linux Mint)',
'Debian' => '(Debian)',
'Fedora' => '(Fedora)',
'Red Hat' => '(Red Hat)',
'SuSE' => '(SuSE)',
'Android' => '(Android)',
'webOS' => '(webOS)|(hpwOS)',
'BlackBerry' => '(BlackBerry)',
'Symbian' => '(Symbian)',
'FreeBSD' => '(FreeBSD)',
'OpenBSD' => '(OpenBSD)',
'NetBSD' => '(NetBSD)',
'SunOS' => '(SunOS)',
'OpenSolaris' => '(OpenSolaris)',
'Chrome OS' => '(Chrome OS)|(CrOS)',
'bot' => '(bot)'
);
foreach ($os_list as $os => $pattern) { foreach ($os_list as $os => $pattern) {
if (preg_match("/$pattern/i", $_SERVER['HTTP_USER_AGENT'])) { if (preg_match("/$pattern/i", $_SERVER['HTTP_USER_AGENT'])) {
@ -145,7 +73,7 @@ class TVisitor {
'mobile', 'android', 'iphone', 'ipod', 'ipad', 'windows phone', 'blackberry', 'kindle', 'silk', 'mobile', 'android', 'iphone', 'ipod', 'ipad', 'windows phone', 'blackberry', 'kindle', 'silk',
'opera mini', 'opera mobi', 'webos', 'symbian', 'nokia', 'samsung', 'lg', 'htc', 'mot', 'tablet', 'opera mini', 'opera mobi', 'webos', 'symbian', 'nokia', 'samsung', 'lg', 'htc', 'mot', 'tablet',
'rim tablet', 'meego', 'netfront', 'bolt', 'fennec', 'series60', 'maemo', 'midp', 'cldc', 'up.browser', 'rim tablet', 'meego', 'netfront', 'bolt', 'fennec', 'series60', 'maemo', 'midp', 'cldc', 'up.browser',
'up.link', 'mmp', 'symbian', 'smartphone', 'wap' 'up.link', 'mmp', 'symbian', 'smartphone', 'wap',
]; ];
// Check if user agent contains any mobile keywords // Check if user agent contains any mobile keywords
@ -192,24 +120,7 @@ class TVisitor {
if (!isset($_SERVER['HTTP_USER_AGENT'])) if (!isset($_SERVER['HTTP_USER_AGENT']))
return 'Unknown'; return 'Unknown';
$browser_list = array( $browser_list = Visitor::$browserList;
'Firefox' => '(Firefox)',
'Edge' => '(Edg|Edge)',
'Chrome' => '(Chrome)(?!.*Edge)',
'Safari' => '(Safari)(?!.*Chrome)',
'Opera' => '(OPR|Opera)',
'Brave' => '(Brave)',
'Internet Explorer' => '(MSIE|Trident)',
'DeepNet Explorer' => '(Deepnet)',
'Flock' => '(Flock)',
'Maxthon' => '(Maxthon)',
'Avant Browser' => '(Avant)',
'AOL' => '(AOL)',
'Vivaldi' => '(Vivaldi)',
'UC Browser' => '(UCBrowser)',
'Yandex Browser' => '(YaBrowser)',
'Samsung Internet' => '(SamsungBrowser)',
);
foreach ($browser_list as $browser => $pattern) { foreach ($browser_list as $browser => $pattern) {
if (preg_match("/$pattern/i", $_SERVER['HTTP_USER_AGENT'])) { if (preg_match("/$pattern/i", $_SERVER['HTTP_USER_AGENT'])) {
@ -228,24 +139,7 @@ class TVisitor {
if (!isset($_SERVER['HTTP_USER_AGENT'])) if (!isset($_SERVER['HTTP_USER_AGENT']))
return 0; return 0;
$browser_list = array( $browser_list = array_values(Visitor::$browserList);
'(Firefox)',
'(Edg|Edge)',
'(Chrome)(?!.*Edge)',
'(Safari)(?!.*Chrome)',
'(OPR|Opera)',
'(Brave)',
'(MSIE|Trident)',
'(Deepnet)',
'(Flock)',
'(Maxthon)',
'(Avant)',
'(AOL)',
'(Vivaldi)',
'(UCBrowser)',
'(YaBrowser)',
'(SamsungBrowser)',
);
foreach ($browser_list as $index => $pattern) { foreach ($browser_list as $index => $pattern) {
if (preg_match("/$pattern/i", $_SERVER['HTTP_USER_AGENT'])) { if (preg_match("/$pattern/i", $_SERVER['HTTP_USER_AGENT'])) {
@ -328,18 +222,7 @@ class TVisitor {
return null; return null;
} }
$engines = [ $engines = Visitor::$engines;
'google' => ['q', 'query'],
'bing' => ['q'],
'yahoo' => ['p'],
'yandex' => ['text'],
'baidu' => ['wd', 'word'],
'duckduckgo' => ['q'],
'ask' => ['q'],
'aol' => ['q'],
'naver' => ['query'],
'ecosia' => ['q'],
];
$parsed_url = parse_url($referer); $parsed_url = parse_url($referer);
$host = isset($parsed_url['host']) ? strtolower($parsed_url['host']) : ''; $host = isset($parsed_url['host']) ? strtolower($parsed_url['host']) : '';

@ -4,12 +4,11 @@ namespace App\Http\Middleware;
use App\Helpers\TVisitor; use App\Helpers\TVisitor;
use App\Models\Visitor; use App\Models\Visitor;
use Carbon\Carbon;
use Closure; use Closure;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
class VisitorDetector class VisitorCounter
{ {
/** /**
* Handle an incoming request. * Handle an incoming request.
@ -18,20 +17,26 @@ class VisitorDetector
*/ */
public function handle(Request $request, Closure $next): Response public function handle(Request $request, Closure $next): Response
{ {
$visitor = Visitor::where('updated_at','>',date("Y-m-d H:i:s" ,time() - (60*60))) $visitor = Visitor::where('updated_at','>',date("Y-m-d H:i:s" ,time() - (60*60)))
->where('ip', $request->ip())->first(); ->where('ip', $request->ip())->first();
if ($visitor === null) { if ($visitor === null) {
$visitor = new Visitor(); $visitor = new Visitor();
$visitor->ip = $request->ip(); $visitor->ip = $request->ip();
$visitor->browser = TVisitor::DetectBrowserI(); $visitor->browser = TVisitor::DetectBrowser();
$visitor->os = TVisitor::DetectOSI(); $visitor->os = TVisitor::DetectOS();
$visitor->version = TVisitor::BrowserVersion(); $visitor->version = TVisitor::BrowserVersion();
$visitor->keywords = TVisitor::GetKeyword(); $ref = TVisitor::GetKeyword();
if ($ref !== null) {
$visitor->keywords = $ref['keyword'];
$visitor->engine = $ref['engine'];
}
$visitor->is_mobile = TVisitor::IsMobile(); $visitor->is_mobile = TVisitor::IsMobile();
$visitor->page = $request->route()->getName();
$visitor->save(); $visitor->save();
}else{ }else{
$visitor->increment('visit'); $visitor->increment('visit');
$visitor->page = $request->route()->getName();
$visitor->save();
} }
return $next($request); return $next($request);
} }

@ -8,4 +8,75 @@ use Illuminate\Database\Eloquent\Model;
class Visitor extends Model class Visitor extends Model
{ {
use HasFactory; use HasFactory;
public static $engines = [
'google' => ['q', 'query'],
'bing' => ['q'],
'yahoo' => ['p'],
'yandex' => ['text'],
'baidu' => ['wd', 'word'],
'duckduckgo' => ['q'],
'ask' => ['q'],
'aol' => ['q'],
'naver' => ['query'],
'ecosia' => ['q'],
];
public static $browserList = ['Firefox' => '(Firefox)',
'FirFox' => '(FireFox)',
'Chrome' => '(Chrome)(?!.*Edge)',
'Edge' => '(Edg|Edge)',
'Opera' => '(OPR|Opera)',
'Brave' => '(Brave)',
'Safari' => '(Safari)(?!.*Chrome)',
'Internet Explorer' => '(MSIE|Trident)',
'DeepNet Explorer' => '(Deepnet)',
'Flock' => '(Flock)',
'Maxthon' => '(Maxthon)',
'Avant Browser' => '(Avant)',
'AOL' => '(AOL)',
'Vivaldi' => '(Vivaldi)',
'UC Browser' => '(UCBrowser)',
'Yandex Browser' => '(YaBrowser)',
'Samsung Internet' => '(SamsungBrowser)',
];
public static $osList = [
'Linux' => '(Linux)',
'Windows 11' => '(Windows NT 11.0)', // Added Windows 11
'Windows 10' => '(Windows NT 10.0)',
'Mac OS X' => '(Mac OS X)',
'Android' => '(Android)',
'iOS' => '(iPhone)|(iPad)',
'Windows 8.1' => '(Windows NT 6.3)',
'Windows 8' => '(Windows NT 6.2)',
'Windows 7' => '(Windows NT 6.1)',
'Windows Vista' => '(Windows NT 6.0)',
'Windows Server 2003/XP x64' => '(Windows NT 5.2)',
'Windows XP' => '(Windows NT 5.1)',
'Windows 2000' => '(Windows NT 5.0)',
'Windows ME' => '(Win 9x 4.90)',
'Windows 98' => '(Windows 98)',
'Windows 95' => '(Windows 95)',
'Windows CE' => '(Windows CE)',
'Windows (iPhone/iPad)' => 'Windows (iPhone|iPad)',
'Mac OS' => '(MacPPC)|(Mac_PowerPC)|(Macintosh)',
'Ubuntu' => '(Ubuntu)',
'Linux Mint' => '(Linux Mint)',
'Debian' => '(Debian)',
'Fedora' => '(Fedora)',
'Red Hat' => '(Red Hat)',
'SuSE' => '(SuSE)',
'webOS' => '(webOS)|(hpwOS)',
'BlackBerry' => '(BlackBerry)',
'Symbian' => '(Symbian)',
'FreeBSD' => '(FreeBSD)',
'OpenBSD' => '(OpenBSD)',
'NetBSD' => '(NetBSD)',
'SunOS' => '(SunOS)',
'OpenSolaris' => '(OpenSolaris)',
'Chrome OS' => '(Chrome OS)|(CrOS)',
'bot' => '(bot)'
];
} }

@ -2,6 +2,8 @@
namespace Database\Factories; namespace Database\Factories;
use App\Helpers\TVisitor;
use App\Models\Visitor;
use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\Factory;
/** /**
@ -17,18 +19,32 @@ class VisitorFactory extends Factory
public function definition(): array public function definition(): array
{ {
$displays = ['1920x1080','1366x768','1920x1080','1366x768','1280x1024',null, null]; $displays = ['1920x1080', '1366x768', '1920x1080', '1366x768', '1280x1024', null, null];
$date = $this->faker->dateTimeBetween('-31 days', 'now'); $displays_mobile = ['360x780', '430x932', '390x844', '375x667', '412x915', null, null];
if (rand(0, 2) == 1) {
$date = $this->faker->dateTimeBetween('-30 days', 'now');
} else {
$date = $this->faker->dateTimeBetween('-120 days', 'now');
}
if (rand(1, 10) == 7) {
$keyword = $this->faker->word();
$engine = array_keys(Visitor::$engines)[rand(0, count(Visitor::$engines) - 1)];
}
$os = array_keys(Visitor::$osList)[rand(0, 6)];
return [ return [
// //
'ip' => $this->faker->ipv4(), 'ip' => $this->faker->ipv4(),
'visit' => rand(1,rand(2,12)), 'visit' => rand(1, rand(2, 12)),
'browser' => rand(0,5), 'browser' => array_keys(Visitor::$browserList)[rand(0, 6)],
'os' => rand(0,14), 'os' => $os,
'version' => rand(100,132), 'version' => rand(100, 132),
'display' => $displays[count($displays)-1], 'display' => $os === 'iOS' || $os === 'Android' ? $displays_mobile[rand(0, count($displays_mobile) - 1)] : $displays[rand(0, count($displays) - 1)],
'updated_at' => $date, 'updated_at' => $date,
'created_at' => $date, 'created_at' => $date,
'keywords' => $keyword ?? null,
'engine' => $engine ?? rand(0, 5) == 0 ? 'google' : null,
'is_mobile' => $os === 'iOS' || $os === 'Android',
]; ];
} }
} }

@ -15,12 +15,14 @@ return new class extends Migration
$table->id(); $table->id();
$table->ipAddress('ip'); $table->ipAddress('ip');
$table->unsignedInteger('visit')->default(1); $table->unsignedInteger('visit')->default(1);
$table->unsignedInteger('browser')->nullable(); $table->enum('browser',array_keys(\App\Models\Visitor::$browserList))->nullable();
$table->unsignedInteger('os')->nullable(); $table->enum('os',array_keys(\App\Models\Visitor::$osList))->nullable();
$table->enum('engine',array_keys(\App\Models\Visitor::$engines))->nullable();
$table->string('version')->nullable(); $table->string('version')->nullable();
$table->string('display')->nullable(); $table->string('display')->nullable();
$table->string('keywords')->nullable(); $table->string('keywords')->nullable();
$table->boolean('is_mobile')->default(false); $table->boolean('is_mobile')->default(false);
$table->string('page')->nullable();
$table->timestamps(); $table->timestamps();
}); });
} }

@ -14,6 +14,6 @@ class VisitorSeeder extends Seeder
public function run(): void public function run(): void
{ {
// //
Visitor::factory()->count(110)->create(); Visitor::factory()->count(1250)->create();
} }
} }

@ -5,7 +5,7 @@ use Illuminate\Support\Facades\Route;
Route::get('/', function () { Route::get('/', function () {
return view('welcome'); return view('welcome');
})->name('welcome')->middleware(\App\Http\Middleware\VisitorDetector::class); })->name('welcome')->middleware(\App\Http\Middleware\VisitorCounter::class);
Auth::routes(['register' => false]); Auth::routes(['register' => false]);
@ -340,9 +340,7 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group(
Route::get('test',function (){ Route::get('test',function (){
// return \Resources\Views\Segments\PreloaderCircle::onAdd(); // return \Resources\Views\Segments\PreloaderCircle::onAdd();
$p = \App\Models\Product::where('id',31)->first(); return \App\Helpers\TVisitor::GetKeyword();
return $p->fullMeta();
}); });

Loading…
Cancel
Save