From f06762d1e8bb22565b8f15e5d72a27964977e3ae Mon Sep 17 00:00:00 2001 From: Anton Afanasyeu Date: Tue, 23 Jun 2026 18:53:34 +0200 Subject: [PATCH] url-shortener: QR encodes short URL with src=qr; forward query on redirect QrHandler uses shortUrlForQr; RedirectHandler merges query string onto origin. Co-authored-by: Cursor --- src/LinkRepository.php | 6 ++++++ src/QrHandler.php | 2 +- src/RedirectHandler.php | 8 +++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/LinkRepository.php b/src/LinkRepository.php index 9507507..3892485 100644 --- a/src/LinkRepository.php +++ b/src/LinkRepository.php @@ -10,6 +10,12 @@ final class LinkRepository { return self::publicBase() . '/' . $slug; } + /** URL encoded in QR PNGs — always tagged for analytics. */ + public static function shortUrlForQr(string $slug): string { + $url = self::shortUrl($slug); + return str_contains($url, '?') ? $url . '&src=qr' : $url . '?src=qr'; + } + /** @return array|null */ public static function findActiveByBearerOrigin(int $bearerId, string $originHash): ?array { $pdo = Database::pdo(); diff --git a/src/QrHandler.php b/src/QrHandler.php index cf59f46..62c057c 100644 --- a/src/QrHandler.php +++ b/src/QrHandler.php @@ -18,7 +18,7 @@ final class QrHandler { } $size = max(128, min(512, $size)); - $target = LinkRepository::shortUrl($slug); + $target = LinkRepository::shortUrlForQr($slug); $png = self::renderPng($target, $size); if ($png === null) { JsonResponse::error(503, 'INTERNAL', 'QR generation unavailable (install qrencode on BE)'); diff --git a/src/RedirectHandler.php b/src/RedirectHandler.php index 0ce9163..32ce54b 100644 --- a/src/RedirectHandler.php +++ b/src/RedirectHandler.php @@ -12,8 +12,14 @@ final class RedirectHandler { } LinkRepository::recordRedirect($slug); AuditLog::write('redirect', (int) $link['bearer_id'], $slug, ''); + $dest = (string) $link['origin']; + $query = (string) ($_SERVER['QUERY_STRING'] ?? ''); + if ($query !== '') { + $dest .= str_contains($dest, '?') ? '&' : '?'; + $dest .= $query; + } http_response_code(302); - header('Location: ' . (string) $link['origin']); + header('Location: ' . $dest); exit; }