"" * "." -> "." * ".." -> ".." * "/" -> "/" * "foo" -> "foo" * "/foo" -> "/foo" * "foo/" -> "foo/" * "foo/bar" -> "foo/bar" * "foo//bar" -> "foo/bar" * "foo/./bar" -> "foo/bar" * "foo/../bar" -> "bar" * "//" -> "/" * "/." -> "/" * "/.." -> "/" * "./" -> "./" * "../" -> "../" * "foo/.." -> "" * "foo/../.." -> ".." * "./foo" -> "foo" */ function canonize_uri_path($path) { $segments = explode('/', $path); # Note: path "/" explodes to array('',''). $segments_count = count($segments); $canon_segments = array(); for ($n = 0; $n < $segments_count; ++$n) { $segment = $segments[$n]; if ($segment === '') { if ($n === 0 || $n === $segments_count - 1) { # We are here iff path starts or ends with '/', and we want # to keep empty segments only on path extremities. $canon_segments[] = $segment; } } elseif ($segment === '.') { if ($n === 0) { # We keep only the first dot segment. $canon_segments[] = $segment; } elseif ($n === $segments_count - 1) { # So that 'foo/.' -> 'foo/' and not 'foo'. $canon_segments[] = ''; } } elseif ($segment === '..') { $c = count($canon_segments); if ($c === 0 || $canon_segments[$c - 1] === '..') { # Dot-dot segments are kept only at the start of canonized path. $canon_segments[] = $segment; } elseif ($canon_segments[$c - 1] !== '') { # Dot-dot pop previous segment, except first empty segment, # i.e. "/.." path is canonized to "/" path. array_pop($canon_segments); } } else { $canon_segments[] = $segment; } } return implode('/', $canon_segments); # Note: array('','') implodes to "/". } # Return $path up to the last slash. Return './' if no slash. function base_uri_path($path) { $last_slash_pos = strrpos($path, '/'); if ($last_slash_pos === FALSE) { return './'; } return substr($path, 0, $last_slash_pos + 1); } function combine_uri_pathes($path1, $path2) { $combined_path = $path2{0} === '/' ? $path2 : base_uri_path($path1).$path2; return canonize_uri_path($combined_path); } function combine_uris($uri1, $uri2) { if ($uri2['scheme'] !== NULL) { $combined_uri = $uri2; } else { $combined_uri = $uri1; $combined_uri['path'] = combine_uri_pathes($uri1['path'], $uri2['path']); $combined_uri['query'] = $uri2['query']; $combined_uri['fragment'] = $uri2['fragment']; # Reparse all to check URI validity. $combined_uri = parse_w2ml_uri(unparse_uri($combined_uri)); } return $combined_uri; } function is_hierarchical_uri_scheme($scheme) { return $scheme === 'file' || $scheme === 'ftp' || $scheme === 'http' || $scheme === 'https' || $scheme === 'site'; } function unparse_uri_host($uri) { $res = ''; $scheme = $uri['scheme']; if ($scheme !== NULL) { $res = $scheme . ':'; } if (is_hierarchical_uri_scheme($scheme)) { $res .= '//'; } if ($uri['user'] !== NULL) { $res .= $uri['user']; if ($uri['pass'] !== NULL) { $res .= ':' . $uri['pass']; } $res .= '@'; } if ($uri['host'] !== NULL) { $res .= $uri['host']; if ($uri['port'] !== NULL) { $res .= ':' . $uri['port']; } } return $res; } function unparse_uri($uri) { $res = unparse_uri_host($uri); if ($uri['path'] !== NULL) { $res .= $uri['path']; } if ($uri['query'] !== NULL) { $res .= '?' . $uri['query']; } if ($uri['fragment'] !== NULL) { $res .= '#' . $uri['fragment']; } return $res; } ?>