ip().'|'.config('app.key')); $isUnique = $this->isUnique($link, $ipHash); $parsed = LinkUserAgentParser::parse((string) $request->userAgent()); LinkClick::create([ 'short_link_id' => $link->id, 'ip_hash' => $ipHash, 'user_agent' => $this->truncate($request->userAgent(), 512), 'referer' => $this->truncate($request->header('referer'), 512), 'device_type' => $parsed['device_type'], 'browser' => $parsed['browser'], 'os' => $parsed['os'], 'country' => LinkGeoResolver::countryCode($request), 'is_unique' => $isUnique, 'clicked_at' => now(), ]); $this->counters->add($link, $isUnique); } catch (Throwable $e) { Log::warning('link click recording failed', [ 'short_link_id' => $link->id, 'error' => $e->getMessage(), ]); } } /** * First click from this IP within the window? * * Relies on the (short_link_id, ip_hash, clicked_at) index. Without it this is a * scan over every click the link has ever received, which degrades as the link * gets popular — the opposite of what a viral link needs. */ private function isUnique(ShortLink $link, string $ipHash): bool { $windowHours = (int) config('link.click_unique_window_hours', 24); return ! LinkClick::query() ->where('short_link_id', $link->id) ->where('ip_hash', $ipHash) ->where('clicked_at', '>=', now()->subHours($windowHours)) ->exists(); } private function truncate(?string $value, int $max): ?string { if ($value === null) { return null; } return mb_strlen($value) > $max ? mb_substr($value, 0, $max) : $value; } }