310 lines
10 KiB
PHP
310 lines
10 KiB
PHP
<?php
|
|
// File name: rel2abs.inc.php
|
|
// Description: PHP subroutine to convert a relative URL to an absolute URL
|
|
// Date: 2002-06-10
|
|
// Author: imacat <imacat@pristine.com.tw>
|
|
// Copyright: Copyright (C) 2002-2007 Pristine Communications
|
|
|
|
// Refer to RFC 1808
|
|
|
|
// Set the include path
|
|
if (!defined("INCPATH_SET")) {
|
|
require_once dirname(__FILE__) . "/incpath.inc.php";
|
|
}
|
|
// Referenced subroutines
|
|
require_once "monica/parseurl.inc.php";
|
|
require_once "monica/requri.inc.php";
|
|
|
|
// Settings
|
|
define("REL2ABS_SKIP_FRAGMENT", true);
|
|
define("REL2ABS_NO_HOST", true);
|
|
define("REL2ABS_RDIFF_KEEP", true);
|
|
define("REL2ABS_RDIFF_STRIP", false);
|
|
|
|
// rel2abs: Conver a relative URL to an absolute URL
|
|
// Refer to RFC 1808
|
|
function rel2abs($rel, $base = null, $skip_fragment = false, $no_host = false, $rdiff = true)
|
|
{
|
|
// Keep the original. We may need to bounce intact later.
|
|
$rel_o = $rel;
|
|
// Make the base absolute first
|
|
if (!is_null($base)) {
|
|
$base = rel2abs($base);
|
|
// Default base to the current URL
|
|
} else {
|
|
$base = REQUEST_FULLURI;
|
|
}
|
|
// Skip the fragment
|
|
if (substr($rel, 0, 1) == "#" && $skip_fragment) {
|
|
return $rel;
|
|
}
|
|
// Return if it is completely empty (RFC 1808, 4, step 2, a)
|
|
if ($rel == "") {
|
|
return $base;
|
|
}
|
|
// Parse the URL first
|
|
$rel_a = parse_url_rfc1808($rel);
|
|
// Fail to parse - bounce intact
|
|
if (is_null($rel_a)) {
|
|
return $rel_o;
|
|
}
|
|
if ( !array_key_exists("net_loc", $rel_a)
|
|
&& array_key_exists("path", $rel_a)
|
|
&& substr($rel_a["path"], 0, 1) == "/"
|
|
&& $rdiff) {
|
|
$rel_a["path"] = ROOT_DIFF . $rel_a["path"];
|
|
}
|
|
$base_a = parse_url_rfc1808($base);
|
|
// Fail to parse - bounce intact
|
|
if (is_null($base_a)) {
|
|
return $rel_o;
|
|
}
|
|
if (!array_key_exists("path", $base_a)) {
|
|
$base_a["path"] = "/";
|
|
}
|
|
if (!array_key_exists("scheme", $base_a)) {
|
|
$base_a["scheme"] = "http";
|
|
}
|
|
// Return if it starts with a scheme (RFC 1808, 4, step 2, b)
|
|
if (array_key_exists("scheme", $rel_a)) {
|
|
return $rel;
|
|
}
|
|
// Inherit the scheme of the base URL (RFC 1808, 4, step 2, c)
|
|
$rel_a["scheme"] = $base_a["scheme"];
|
|
$skip_to_7 = false;
|
|
// The net_loc is not empty (RFC 1808, 4, step 3)
|
|
if (array_key_exists("net_loc", $rel_a)) {
|
|
$skip_to_7 = true;
|
|
// Inherit the net_loc of the base URL (if any)
|
|
} else {
|
|
if (array_key_exists("net_loc", $base_a)) {
|
|
$rel_a["net_loc"] = $base_a["net_loc"];
|
|
}
|
|
// The path is not relative (RFC 1808, 4, step 4)
|
|
if ( array_key_exists("path", $rel_a)
|
|
&& substr($rel_a["path"], 0, 1) == "/") {
|
|
$skip_to_7 = true;
|
|
} else {
|
|
// The path is empty (RFC 1808, 4, step 5)
|
|
if (!array_key_exists("path", $rel_a)) {
|
|
$rel_a["path"] = $base_a["path"];
|
|
// The params is not empty (RFC 1808, 4, step 5, a)
|
|
if (array_key_exists("params", $rel_a)) {
|
|
$skip_to_7 = true;
|
|
} else {
|
|
if (array_key_exists("params", $base_a)) {
|
|
$rel_a["params"] = $base_a["params"];
|
|
}
|
|
// The query is not empty (RFC 1808, 4, step 5, b)
|
|
if (array_key_exists("query", $rel_a)) {
|
|
$skip_to_7 = true;
|
|
} else {
|
|
if (array_key_exists("query", $base_a)) {
|
|
$rel_a["query"] = $base_a["query"];
|
|
}
|
|
$skip_to_7 = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Resolve the path (RFC 1808, 4, step 6)
|
|
if (!$skip_to_7) {
|
|
$rel_a["path"] = preg_replace("/[^\/]+$/", "", $base_a["path"])
|
|
. $rel_a["path"];
|
|
$rel_a["path"] = stdpath($rel_a["path"]);
|
|
}
|
|
|
|
// Compose the URL (RFC 1808, 4, step 7)
|
|
$abs = "";
|
|
if (!$no_host) {
|
|
$abs .= $rel_a["scheme"] . ":";
|
|
if (array_key_exists("net_loc", $rel_a)) {
|
|
$abs .= "//" . $rel_a["net_loc"];
|
|
}
|
|
}
|
|
$abs .= $rel_a["path"];
|
|
if (array_key_exists("params", $rel_a)) {
|
|
$abs .= ";" . $rel_a["params"];
|
|
}
|
|
if (array_key_exists("query", $rel_a)) {
|
|
$abs .= "?" . $rel_a["query"];
|
|
}
|
|
if (array_key_exists("fragment", $rel_a)) {
|
|
$abs .= "#" . $rel_a["fragment"];
|
|
}
|
|
|
|
return $abs;
|
|
}
|
|
|
|
// abs2rel: Conver an absolute URL to a relative URL
|
|
function abs2rel($abs, $base = null)
|
|
{
|
|
// Keep the original. We may need to bounce intact later.
|
|
$abs_o = $abs;
|
|
// Make the base absolute first
|
|
if (!is_null($base)) {
|
|
$base = rel2abs($base);
|
|
// Default base to the current URL
|
|
} else {
|
|
$base = REQUEST_FULLURI;
|
|
}
|
|
$abs = rel2abs($abs, $base);
|
|
// Parse the URL first
|
|
$abs_a = parse_url_rfc1808($abs);
|
|
// Fail to parse - bounce intact
|
|
if (is_null($abs_a)) {
|
|
return $abs_o;
|
|
}
|
|
if (!array_key_exists("path", $abs_a)) {
|
|
$abs_a["path"] = "/";
|
|
}
|
|
$base_a = parse_url_rfc1808($base);
|
|
// Fail to parse - bounce intact
|
|
if (is_null($base_a)) {
|
|
return $abs_o;
|
|
}
|
|
// Return if not the same scheme
|
|
if ($abs_a["scheme"] != $base_a["scheme"]) {
|
|
return $abs;
|
|
}
|
|
unset($abs_a["scheme"]);
|
|
// Return if not the same network location (net_loc)
|
|
if ( !((!array_key_exists("net_loc", $abs_a)
|
|
&& !array_key_exists("net_loc", $base_a))
|
|
|| (array_key_exists("net_loc", $abs_a)
|
|
&& array_key_exists("net_loc", $base_a)
|
|
&& $abs_a["net_loc"] == $base_a["net_loc"]))) {
|
|
return $abs;
|
|
}
|
|
unset($abs_a["net_loc"]);
|
|
if (!array_key_exists("path", $abs_a)) {
|
|
$abs_a["path"] = "/";
|
|
}
|
|
// Different path -- find the path difference
|
|
if ($abs_a["path"] != $base_a["path"]) {
|
|
// Remove the last segment from the base URL
|
|
$base_path = preg_replace("/[^\/]+$/", "", $base_a["path"]);
|
|
$abs_path = $abs_a["path"];
|
|
// Remove the leading absolute slash
|
|
$base_path = preg_replace("/^\//", "", $base_path);
|
|
$abs_path = preg_replace("/^\//", "", $abs_path);
|
|
// Check each path segment from the left
|
|
while (preg_match("/^([^\/]+\/)(.*)$/", $base_path, $m)) {
|
|
// Not sharing the same path segment
|
|
if (substr($abs_path, 0, strlen($m[1])) != $m[1]) {
|
|
break;
|
|
}
|
|
$base_path = $m[2];
|
|
$abs_path = substr($abs_path, strlen($m[1]));
|
|
// Nothing left, but false is not what we want
|
|
if ($abs_path === false) {
|
|
$abs_path = "";
|
|
break;
|
|
}
|
|
}
|
|
// Turn each remaining segment to ".." and prepend it to the path
|
|
$abs_a["path"] = preg_replace("/[^\/]+/", "..", $base_path) . $abs_path;
|
|
// Remove the trailing slash of the ancestor directories
|
|
if ( $abs_a["path"] == "../"
|
|
|| preg_match("/\/\.\.\/$/", $abs_a["path"])) {
|
|
$abs_a["path"] = substr($abs_a["path"], 0, -1);
|
|
}
|
|
// Nothing left means the current directory
|
|
if ($abs_a["path"] == "") {
|
|
$abs_a["path"] = ".";
|
|
}
|
|
|
|
// Same path
|
|
} else {
|
|
// Different params
|
|
if ( !((!array_key_exists("params", $abs_a)
|
|
&& !array_key_exists("params", $base_a))
|
|
|| (array_key_exists("params", $abs_a)
|
|
&& array_key_exists("params", $base_a)
|
|
&& $abs_a["params"] == $base_a["params"]))) {
|
|
// No further checks
|
|
// Keep the last segment of the path
|
|
$abs_a["path"] = preg_replace("/^\/(?:[^\/]+\/)*/", "", $abs_a["path"]);
|
|
if ($abs_a["path"] == "") {
|
|
$abs_a["path"] = ".";
|
|
}
|
|
|
|
// Same params
|
|
} else {
|
|
// Different query
|
|
if ( !((!array_key_exists("query", $abs_a)
|
|
&& !array_key_exists("query", $base_a))
|
|
|| (array_key_exists("query", $abs_a)
|
|
&& array_key_exists("query", $base_a)
|
|
&& $abs_a["query"] == $base_a["query"]))) {
|
|
// No further checks
|
|
// Keep the last segment of the path
|
|
$abs_a["path"] = preg_replace("/^\/(?:[^\/]+\/)*/", "", $abs_a["path"]);
|
|
if ($abs_a["path"] == "") {
|
|
$abs_a["path"] = ".";
|
|
}
|
|
|
|
// Same query
|
|
} else {
|
|
// Everything is the same (fragment not counted)
|
|
// Keep only the fragment if there is a fragment
|
|
if (array_key_exists("fragment", $abs_a)) {
|
|
unset($abs_a["path"]);
|
|
unset($abs_a["params"]);
|
|
unset($abs_a["query"]);
|
|
|
|
// No fragment
|
|
} else {
|
|
// Keep the last segment of the path
|
|
$abs_a["path"] = preg_replace("/^\/(?:[^\/]+\/)*/", "", $abs_a["path"]);
|
|
if ($abs_a["path"] == "") {
|
|
$abs_a["path"] = ".";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compose the URL
|
|
$rel = "";
|
|
if (array_key_exists("path", $abs_a)) {
|
|
$rel .= $abs_a["path"];
|
|
}
|
|
if (array_key_exists("params", $abs_a)) {
|
|
$rel .= ";" . $abs_a["params"];
|
|
}
|
|
if (array_key_exists("query", $abs_a)) {
|
|
$rel .= "?" . $abs_a["query"];
|
|
}
|
|
if (array_key_exists("fragment", $abs_a)) {
|
|
$rel .= "#" . $abs_a["fragment"];
|
|
}
|
|
|
|
return $rel;
|
|
}
|
|
|
|
// stdpath: Standardize a path name
|
|
// Refer to RFC 1808, 4, step 6
|
|
function stdpath($path)
|
|
{
|
|
// Remove all the "./" (RFC 1808, 4, step 6, a)
|
|
$path = preg_replace("/(?<=\/)\.\//", "", $path);
|
|
$path = preg_replace("/^\.\//", "", $path);
|
|
// Remove the trailing "." (RFC 1808, 4, step 6, b)
|
|
$path = preg_replace("/(?<=\/)\.$/", "", $path);
|
|
// Remove all the "<segment>/../" (RFC 1808, 4, step 6, c)
|
|
while ( preg_match("/^(.*?)([^\/]+)\/\.\.\/(.*)$/", $path, $m)
|
|
&& $m[2] != "..") {
|
|
$path = $m[1] . $m[3];
|
|
}
|
|
// Remove the trailing "<segment>/.." (RFC 1808, 4, step 6, d)
|
|
while ( preg_match("/^(.*?)([^\/]+)\/\.\.$/", $path, $m)
|
|
&& $m[2] != "..") {
|
|
$path = $m[1];
|
|
}
|
|
return $path;
|
|
}
|
|
|
|
?>
|