public static function normalize($url)
    {
        $u = parse_url(preg_replace('#^file:/+([a-z]+:)#i', '$1', $url));

        if ($u === false) {
            return $url;
        }

        if (empty($u['scheme'])) {
            $u = null;
            return false;
        }

        $scheme = strtolower($u['scheme']);

        if (strlen($scheme) > 1) {
            $normalized = $scheme . '://';
        } else {
            $normalized = strtoupper($scheme) . ':';
        }

        if (isset($u['user'])) {
            $normalized .= $u['user'];
            $normalized .= isset($u['pass']) ? (':' . $u['pass']) : '';
            $normalized .= '@';
        }

        if (isset($u['host'])) {
            if (in_array($scheme, static::$defaultSchemes)) {
                $host = urldecode($u['host']);
                $normalized .= mb_strtolower($host, mb_detect_encoding($host));
            } else {
                $normalized .= $u['host'];
            }
        }

        if (isset($u['port']) && !in_array($scheme . ':' . $u['port'], static::$defaultPorts)) {
            $normalized .= ':' . $u['port'];
        }

        if (empty($u['path']) || $u['path'] === '/') {
            $normalized .= '/';
        } else {
            $normalized .= '/' . ltrim(self::canonpath($u['path']), '/');
        }

        if (isset($u['query'])) {
            $normalized .= self::canonquery($u['query'], '?');
        }

        if (isset($u['fragment'])) {
            $normalized .= '#' . $u['fragment'];
        }

        $u = null;
        return $normalized;
    }