2

基本上,给定一个基本 URL,如

file:///path/to/some/file.html

还有一个相对 URL,例如

another_file.php?id=5

我想出去

file:///path/to/some/another_file.php?id=5

我找到了这个脚本(与这个脚本相同),但它似乎不适用于该file://方案。在使用我的代码之前,我正在做一些本地测试,所以我想同时处理file://http://.

有人知道可以执行此操作的脚本/函数吗?

在 C# 中,我会使用Uri(Uri base, string rel)


以上只是一个例子。它应该适用于您可以放入的任何<a href="xxx">URL 。


这是迄今为止我得到的最好的,但它无法处理..,可能还有其他一些事情:

function rel2abs($base, $rel) {
    if (parse_url($rel, PHP_URL_SCHEME) != '') return $rel;
    if ($rel[0]=='#' || $rel[0]=='?') return $base.$rel;
    $parse = parse_url($base);
    $path = preg_replace('#/[^/]*$#', '', $parse['path']);
    if ($rel[0] == '/') $path = '';
    $abs = (isset($path['host'])?$path['host']:'')."$path/$rel";
    $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
    for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
    return $parse['scheme'].'://'.$abs;
}
4

6 回答 6

2

您可以使用parse_url()将 URL 分成几部分,然后在正斜杠字符上拆分“路径”部分。这应该允许您重新组装它们并更换最后一部分。

像这样的东西(伪代码,未经测试,甚至不确定它是否是有效的 PHP 语法):

$url_parts = parse_url($url_text);
$path_parts = explode('/', $url_parts[path]);

$new_url = $url_parts[scheme] + ":";

if ($url_parts[scheme] == "file") {
    $new_url .= '///';
} else {
    $new_url .= '//';
}

$new_url .= $url_parts[hostname] . '/';
for (int i = 0; i < count($path_parts) - 1; i++) {
    $new_url .= $path_parts[i] . "/";
} 

$new_url .= $REPLACEMENT_FILENAME

如果需要,您可以在末尾附加查询字符串和/或锚片段(以 # 开头) - 请参阅 parse_url() 手册页以获取其数组中 URL 部分的列表。

于 2012-06-26T20:43:56.203 回答
2

我已经修改了 Puggan Se 的答案来处理 HTML 页面中看到的某些相对 URL。

function url2absolute($baseurl, $relativeurl) {

    // if the relative URL is scheme relative then treat it differently
    if(substr($relativeurl, 0, 2) === "//") {
        if(parse_url($baseurl, PHP_URL_SCHEME) != null) {
            return parse_url($baseurl, PHP_URL_SCHEME) . ":" . $relativeurl;
        } else { // assume HTTP
            return "http:" . $relativeurl;
        }
    }

    // if the relative URL points to the root then treat it more simply
    if(substr($relativeurl, 0, 1) === "/") {
        $parts = parse_url($baseurl);
        $return = $parts['scheme'] . ":";
        $return .= ($parts['scheme'] === "file") ? "///" : "//";
        // username:password@host:port ... could go here too!
        $return .= $parts['host'] . $relativeurl;
        return $return;
    }

    // If the relative URL is actually an absolute URL then just use that
    if(parse_url($relativeurl, PHP_URL_SCHEME) !== null) {
        return $relativeurl;
    }

    $parts = parse_url($baseurl);

    // Chop off the query string in a base URL if it is there
    if(isset($parts['query'])) {
        $baseurl = strstr($baseurl,'?',true);
    }

    // The rest is adapted from Puggan Se

    $return = ""; // string to return at the end
    $minpartsinfinal = 3; // for everything except file:///
    if($parts['scheme'] === "file") {
        $minpartsinfinal = 4;
    }

    // logic for username:password@host:port ... query string etc. could go here too ... somewhere?      

    $basepath = explode('/', $baseurl); // will this handle correctly when query strings have '/'
    $relpath = explode('/', $relativeurl);

    array_pop($basepath);

    $returnpath = array_merge($basepath, $relpath);
    $returnpath = array_reverse($returnpath);

    $parents = 0;
    foreach($returnpath as $part_nr => $part_value) {
        /* if we find '..', remove this and the next element */
        if($part_value == '..') {
            $parents++;
            unset($returnpath[$part_nr]);
        } /* if we find '.' remove this element */
        else if($part_value == '.') {
            unset($returnpath[$part_nr]);
        } /* if this is a normal element, and we have unhandled '..', then remove this */
        else if($parents > 0) {
            unset($returnpath[$part_nr]);
            $parents--;
        }
    }
    $returnpath = array_reverse($returnpath);
    if(count($returnpath) < $minpartsinfinal) {
        return FALSE;
    }
        return implode('/', $returnpath);
}

例子:

print url2absolute("file:///path/to/some/file.html", "another_file.php?id=5") . "<br>"; // original example
print url2absolute("file:///path/to/some/file.html", "../../../../../another_file.php?id=5") . "<br>"; // should be an error!
print url2absolute("http://path/to/some/file.html?source=this/one", "another_file.php?id=5") . "<br>"; // with query string on base URL
print url2absolute("http://path/to/some/file.html", "//other-path/another_file.php?id=5") . "<br>"; // scheme relative
于 2015-08-17T16:36:02.037 回答
1

我认为最简单的解决方案是使用dirname()函数。

$url = 'file:///path/to/some/file.html';
$rel = 'another_file.php?id=5';

$final = dirname($url).'/'.$rel;
于 2012-06-26T21:10:33.847 回答
1
<?php
/* strings from your exemple */
$base_url = "file:///path/to/some/file.html";
$relative_url = "another_file.php?id=5";

/* split up urls folder parts into an array */
$base_url_parts = explode('/', $base_url);
$relative_parts = explode('/', $relative);

/* remove last element (in this case "file.html") */
array_pop($base_url_parts);

/* merge absolute_url from base and relative */
$absolute_url_parts = array_merge($base_url_parts, $relative_parts);

/* reverser the list before the search of '..' */
$absolute_url_parts = array_reverse($absolute_url_parts);

/* count of current number of unhandled '..' */
$parent_folder_count = 0;

/* loop throught all elements looking for '..' */
foreach($absolute_url_parts as $part_nr => $part_value)
{
    /* if we find '..', remove this and the next element */
    if($part_value = '..')
    {
        $parent_folder_count++;
        unset($absolute_url_parts[$part_nr]);
    }

    /* if we find '.' remove this element */
    else if($part_value = '.')
    {
        unset($absolute_url_parts[$part_nr]);
    }

    /* if this is a normal element, and we have unhandled '..', then remove this */
    else if($parent_folder_count > 0)
    {
        unset($absolute_url_parts[$part_nr]);
        $parent_folder_count--;
    }

    /* else: keep it */
}

/* restore the order by reversing again */
$absolute_url_parts = array_reverse($absolute_url_parts);

/* restore the list to a string again */
$absolute_url = implode('/', $absolute_url_parts);

/* done */
?>
于 2012-06-26T20:54:55.500 回答
0
$ab="file:///path/to/some/file.html";
$rel="another_file.php?id=5";

$exab=explode("/",$ab);
$exab[count($exab)-1]=$rel;

$newab=implode("/",$exab);

可能不是最优雅的解决方案,但它确实有效。

于 2012-06-26T20:47:25.347 回答
0
$file1 = "file://path/to/some/file.html";
$file2 = "anotherfile?q=1";

$newurl = substr_replace($file1, $file2, strrpos($file1, "/")+1);

http://codepad.org/370Yp1M7

于 2012-06-26T20:49:14.300 回答