$userId, 'mem' => $membershipNumber, 'exp' => time() + $expiresInSeconds, 'rnd' => self::generateRandomHex(8), ]; $json = json_encode($payload, JSON_UNESCAPED_SLASHES); $base64Payload = rtrim(strtr(base64_encode($json), '+/', '-_'), '='); $signature = self::generateHmacSignature($base64Payload, $secretKey); return $base64Payload . '.' . $signature; } public static function verifyDynamicQrToken(string $token, string $secretKey): ?array { $parts = explode('.', $token); if (count($parts) !== 2) { return null; } [$base64Payload, $signature] = $parts; if (!self::verifyHmacSignature($base64Payload, $signature, $secretKey)) { return null; } $json = base64_decode(strtr($base64Payload, '-_', '+/')); if (!$json) { return null; } $payload = json_decode($json, true); if (!is_array($payload) || !isset($payload['exp']) || $payload['exp'] < time()) { return null; // Expired or invalid format } return $payload; } }