Files
selima-perl/lib/php/monica/rel2abs.inc.php
2026-03-10 21:31:43 +08:00

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;
}
?>