+ * @brief Remove indentation from a text
+ *
+ * @param string $text String to be transformed.
+ * @param string $chr Optional. Indentation tag. Default tab (\t).
+ * @param int $count Optional. Default null.
+ *
+ * @return string Transformed string.
+ */
+ public static function deindent($text, $chr = "[\t ]", $count = NULL)
+ {
+ $lines = explode("\n", $text);
+
+ if (is_null($count)) {
+ $m = [];
+ $k = 0;
+ while ($k < count($lines) && strlen($lines[$k]) == 0) {
+ $k++;
+ }
+ preg_match("|^" . $chr . "*|", $lines[$k], $m);
+ $count = strlen($m[0]);
+ }
+
+ for ($k = 0; $k < count($lines); $k++) {
+ $lines[$k] = preg_replace("|^" . $chr . "{" . $count . "}|", "", $lines[$k]);
+ }
+
+ return implode("\n", $lines);
+ }
+
+ /**
+ * @brief Get byte size returned in a Data Measurement (KB, MB, GB)
+ *
+ * @param int $bytes The number of bytes to be measured
+ * @param int $precision Optional. Default 2.
+ *
+ * @return string Size with measured units.
+ */
+ public static function formatBytes($bytes, $precision = 2)
+ {
+ $units = ['B', 'KB', 'MB', 'GB', 'TB'];
+ $bytes = max($bytes, 0);
+ $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
+ $pow = min($pow, count($units) - 1);
+ $bytes /= pow(1024, $pow);
+
+ return round($bytes, $precision) . ' ' . $units[$pow];
+ }
+
+ /**
+ * @brief Protect percent characters in sprintf calls
+ *
+ * @param string $s String to transform.
+ *
+ * @return string Transformed string.
+ */
+ public static function protectSprintf($s)
+ {
+ return str_replace('%', '%%', $s);
+ }
+
+ /**
+ * @brief Base64 Encode URL and translate +/ to -_ Optionally strip padding.
+ *
+ * @param string $s URL to encode
+ * @param boolean $strip_padding Optional. Default false
+ *
+ * @return string Encoded URL
+ */
+ public static function base64UrlEncode($s, $strip_padding = false)
+ {
+ $s = strtr(base64_encode($s), '+/', '-_');
+
+ if ($strip_padding) {
+ $s = str_replace('=', '', $s);
+ }
+
+ return $s;
+ }
+
+ /**
+ * @brief Decode Base64 Encoded URL and translate -_ to +/
+ * @param string $s URL to decode
+ *
+ * @return string Decoded URL
+ * @throws \Exception
+ */
+ public static function base64UrlDecode($s)
+ {
+ if (is_array($s)) {
+ Logger::log('base64url_decode: illegal input: ' . print_r(debug_backtrace(), true));
+ return $s;
+ }
+
+ /*
+ * // Placeholder for new rev of salmon which strips base64 padding.
+ * // PHP base64_decode handles the un-padded input without requiring this step
+ * // Uncomment if you find you need it.
+ *
+ * $l = strlen($s);
+ * if (!strpos($s,'=')) {
+ * $m = $l % 4;
+ * if ($m == 2)
+ * $s .= '==';
+ * if ($m == 3)
+ * $s .= '=';
+ * }
+ *
+ */
+
+ return base64_decode(strtr($s, '-_', '+/'));
+ }
+
+ /**
+ * @brief Normalize url
+ *
+ * @param string $url URL to be normalized.
+ *
+ * @return string Normalized URL.
+ */
+ public static function normaliseLink($url)
+ {
+ $ret = str_replace(['https:', '//www.'], ['http:', '//'], $url);
+ return rtrim($ret, '/');
+ }
+
+ /**
+ * @brief Normalize OpenID identity
+ *
+ * @param string $s OpenID Identity
+ *
+ * @return string normalized OpenId Identity
+ */
+ public static function normaliseOpenID($s)
+ {
+ return trim(str_replace(['http://', 'https://'], ['', ''], $s), '/');
+ }
+
+ /**
+ * @brief Compare two URLs to see if they are the same, but ignore
+ * slight but hopefully insignificant differences such as if one
+ * is https and the other isn't, or if one is www.something and
+ * the other isn't - and also ignore case differences.
+ *
+ * @param string $a first url
+ * @param string $b second url
+ * @return boolean True if the URLs match, otherwise False
+ *
+ */
+ public static function compareLink($a, $b)
+ {
+ return (strcasecmp(self::normaliseLink($a), self::normaliseLink($b)) === 0);
+ }
+
+
+ /**
+ * Ensures the provided URI has its query string punctuation in order.
+ *
+ * @param string $uri
+ * @return string