<?phpnamespace App\Chat;/** * The applet's "tempid": in 2002 a one-time key the web site wrote in a table (chat_tempid) with the member's * profile. Without a database the profile travels in the tempid itself, URL-encoded: * * n=Pseudo&a=25&s=1&v=Paris (nickname, age, sex 0 = woman / 1 = man / 2 = other, city) * ...&k=<key> (CARAMAIL_ADMIN_KEY: a moderator; CARAMAIL_SUPER_KEY: an administrator) * ...&r=<0|1|2> (the role asked: honoured only from the owner's addresses) * ...&p=<origin> (the "provenance" of the original, 0 by default) */final class TempId{ public const MAX_NICKNAME = 20; public const MAX_CITY = 30; /** @return array{nickname: string, age: int, sex: int, city: string, key: string, origin: int, role: ?int}|null */ public static function parse(string $tempid): ?array { if ($tempid === '' || strlen($tempid) > 512) { return null; } parse_str($tempid, $q); $nickname = self::clean((string)($q['n'] ?? ''), self::MAX_NICKNAME); if ($nickname === '') { return null; } return [ 'nickname' => $nickname, 'age' => max(0, min(120, (int)($q['a'] ?? 0))), 'sex' => max(0, min(2, (int)($q['s'] ?? 2))), 'city' => self::clean((string)($q['v'] ?? ''), self::MAX_CITY), 'key' => (string)($q['k'] ?? ''), 'origin' => max(0, min(99, (int)($q['p'] ?? 0))), 'role' => isset($q['r']) && in_array((string)$q['r'], ['0', '1', '2'], true) ? (int)$q['r'] : null, ]; } public static function make(string $nickname, int $age, int $sex, string $city, string $key = ''): string { $q = ['n' => $nickname, 'a' => $age, 's' => $sex, 'v' => $city]; if ($key !== '') { $q['k'] = $key; } return http_build_query($q); } /** No tab, line end or ':' (they cut frames and ids), trimmed, at most $max characters. */ private static function clean(string $value, int $max): string { $value = preg_replace('/[\x00-\x1f\x7f:]+/u', ' ', $value) ?? ''; return mb_substr(trim($value), 0, $max); }}