diff --git a/inc/functions/net.php b/inc/functions/net.php index 4319a3f3..1384f651 100644 --- a/inc/functions/net.php +++ b/inc/functions/net.php @@ -15,3 +15,63 @@ function is_connection_https(): bool { function is_connection_secure(): bool { return is_connection_https() || (!empty($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] === '127.0.0.1'); } + +/** + * Encodes a string into a base64 variant without characters illegal in urls. + */ +function base64_url_encode(string $input): string { + return strtr(base64_encode($input), '+/=', '-_.'); +} + +/** + * Decodes a string from a base64 variant without characters illegal in urls. + */ +function base64_url_decode(string $input): string { + return base64_decode(strtr($input, '-_.', '+/=')); +} + +/** + * Encodes a typed cursor. + * + * @param string $type The type for the cursor. Only the first character is considered. + * @param array $map A map of key-value pairs to encode. + * @return string An encoded string that can be sent through urls. Empty if either parameter is empty. + */ +function encode_cursor(string $type, array $map): string { + if (empty($type) || empty($map)) { + return ''; + } + + $acc = $type[0]; + foreach ($map as $key => $value) { + $acc .= "|$key#$value"; + } + return base64_url_encode($acc); +} + +/** + * Decodes a typed cursor. + * + * @param string $cursor A string emitted by `encode_cursor`. + * @return array An array with the type of the cursor and an array of key-value pairs. The type is null and the map + * empty if either there are no key-value pairs or the encoding is incorrect. + */ +function decode_cursor(string $cursor): array { + $map = []; + $type = ''; + $acc = base64_url_decode($cursor); + if ($acc === false || empty($acc)) { + return [ null, [] ]; + } + + $type = $acc[0]; + foreach (explode('|', substr($acc, 2)) as $pair) { + $pair = explode('#', $pair); + if (count($pair) >= 2) { + $key = $pair[0]; + $value = $pair[1]; + $map[$key] = $value; + } + } + return [ $type, $map ]; +}