86 lines
3.0 KiB
PHP
86 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Channel;
|
|
use App\Models\PageVisit;
|
|
use App\Support\UserAgentParser;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class PageHitController extends Controller
|
|
{
|
|
private const GIF_1X1 = "GIF89a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;";
|
|
|
|
public function __invoke(Request $request): Response
|
|
{
|
|
$channelId = trim((string) $request->query('c', $request->input('c', '')));
|
|
$clientUid = trim((string) $request->query('u', $request->input('u', '')));
|
|
$newCode = Channel::normalizeNewChannelId($channelId);
|
|
if ($newCode !== null) {
|
|
$channelId = $newCode;
|
|
} else {
|
|
$channelId = strtolower($channelId);
|
|
if (! preg_match('/^[0-9a-f]{32}$/', $channelId)) {
|
|
return $this->pixel();
|
|
}
|
|
}
|
|
if (! preg_match('/^[0-9a-fA-F-]{8,64}$/', $clientUid) && ! preg_match('/^tmp_[0-9a-f]+$/i', $clientUid)) {
|
|
return $this->pixel();
|
|
}
|
|
|
|
$ip = PageVisit::normalizeIp((string) $request->ip());
|
|
$domain = PageVisit::normalizeDomain($request->getHost());
|
|
$uid = PageVisit::visitorUid($domain ?? $request->getHost(), $ip);
|
|
|
|
$debounceKey = 'page_hit:'.$channelId.':'.$uid;
|
|
if (! Cache::add($debounceKey, 1, now()->addSeconds(8))) {
|
|
return $this->pixel();
|
|
}
|
|
|
|
$ua = substr((string) $request->userAgent(), 0, 512);
|
|
$parsed = UserAgentParser::parse($ua);
|
|
$referer = $this->referer($request);
|
|
|
|
PageVisit::query()->create([
|
|
'channel_id' => $channelId,
|
|
'client_uid' => $uid,
|
|
'user_agent' => $ua !== '' ? $ua : null,
|
|
'os' => $parsed['os'],
|
|
'os_version' => $parsed['os_version'] !== '' ? $parsed['os_version'] : null,
|
|
'browser' => $parsed['browser'],
|
|
'browser_version' => $parsed['browser_version'] !== '' ? $parsed['browser_version'] : null,
|
|
'ip' => $ip !== '' ? $ip : null,
|
|
'domain' => $domain,
|
|
'referer' => $referer,
|
|
'created_at' => now(),
|
|
]);
|
|
|
|
return $this->pixel();
|
|
}
|
|
|
|
private function referer(Request $request): ?string
|
|
{
|
|
$referer = trim((string) $request->query('r', $request->input('r', '')));
|
|
if ($referer === '') {
|
|
$referer = trim((string) $request->headers->get('referer', ''));
|
|
}
|
|
if ($referer === '') {
|
|
return null;
|
|
}
|
|
|
|
return substr($referer, 0, 512);
|
|
}
|
|
|
|
private function pixel(): Response
|
|
{
|
|
return response(self::GIF_1X1, 200, [
|
|
'Content-Type' => 'image/gif',
|
|
'Content-Length' => (string) strlen(self::GIF_1X1),
|
|
'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
|
|
'Pragma' => 'no-cache',
|
|
]);
|
|
}
|
|
}
|