41

有没有办法从解析的 url 反转 url?

$url = 'http://www.domain.com/dir/index.php?query=blabla#more_bla';
$parse = parse_url($url);
print_r($parse);
/*
array(
 'scheme'=>'http://',
 etc....
)
*/
$revere = reverse_url($parse); // probably does not exist but u get the point

echo $reverse;
//outputs:// "http://www.domain.com/dir/index.php?query=blabla#more_bla"

或者,如果有一种方法可以验证缺少其推荐网址的一部分的网址,例如

www.mydomain.com

mydomain.com

应该全部返回 http://www.mydomain.com 或带有正确的子域

4

6 回答 6

33

这是我用于分解和重建 URL 的两个函数:

function http_parse_query($query) {
    $parameters = array();
    $queryParts = explode('&', $query);
    foreach ($queryParts as $queryPart) {
        $keyValue = explode('=', $queryPart, 2);
        $parameters[$keyValue[0]] = $keyValue[1];
    }
    return $parameters;
}

function build_url(array $parts) {
    return (isset($parts['scheme']) ? "{$parts['scheme']}:" : '') . 
        ((isset($parts['user']) || isset($parts['host'])) ? '//' : '') . 
        (isset($parts['user']) ? "{$parts['user']}" : '') . 
        (isset($parts['pass']) ? ":{$parts['pass']}" : '') . 
        (isset($parts['user']) ? '@' : '') . 
        (isset($parts['host']) ? "{$parts['host']}" : '') . 
        (isset($parts['port']) ? ":{$parts['port']}" : '') . 
        (isset($parts['path']) ? "{$parts['path']}" : '') . 
        (isset($parts['query']) ? "?{$parts['query']}" : '') . 
        (isset($parts['fragment']) ? "#{$parts['fragment']}" : '');
}

// Example
$parts = parse_url($url);

if (isset($parts['query'])) {
    $parameters = http_parse_query($parts['query']);
    foreach ($parameters as $key => $value) {
        $parameters[$key] = $value; // do stuff with $value
    }
    $parts['query'] = http_build_query($parameters);
}

$url = build_url($parts);
于 2016-02-04T17:40:30.263 回答
26

你应该能够做到

http_build_url($parse)

注意:http_build_url只能通过安装 pecl_http 获得。

根据文档,它专门设计用于处理来自parse_url. 这两个函数都处理锚点、查询参数等,因此没有“$url 上未提及的其他属性”。

http://在丢失时添加,请在解析之前使用基本检查:

if (strpos($url, "http://") != 0)
    $url = "http://$url";
于 2010-12-04T18:10:35.030 回答
12

这个函数应该可以解决问题:

function unparse_url(array $parsed): string {
    $pass      = $parsed['pass'] ?? null;
    $user      = $parsed['user'] ?? null;
    $userinfo  = $pass !== null ? "$user:$pass" : $user;
    $port      = $parsed['port'] ?? 0;
    $scheme    = $parsed['scheme'] ?? "";
    $query     = $parsed['query'] ?? "";
    $fragment  = $parsed['fragment'] ?? "";
    $authority = (
        ($userinfo !== null ? "$userinfo@" : "") .
        ($parsed['host'] ?? "") .
        ($port ? ":$port" : "")
    );
    return (
        (\strlen($scheme) > 0 ? "$scheme:" : "") .
        (\strlen($authority) > 0 ? "//$authority" : "") .
        ($parsed['path'] ?? "") .
        (\strlen($query) > 0 ? "?$query" : "") .
        (\strlen($fragment) > 0 ? "#$fragment" : "")
    );
}

这是一个简短的测试:

function unparse_url_test() {
    foreach ([
        '',
        'foo',
        'http://www.google.com/',
        'http://u:p@foo:1/path/path?q#frag',
        'http://u:p@foo:1/path/path?#',
        'ssh://root@host',
        '://:@:1/?#',
        'http://:@foo:1/path/path?#',
        'http://@foo:1/path/path?#',
    ] as $url) {
        $parsed1 = parse_url($url);
        $parsed2 = parse_url(unparse_url($parsed1));

        if ($parsed1 !== $parsed2) {
            print var_export($parsed1, true) . "\n!==\n" . var_export($parsed2, true) . "\n\n";
        }
    }
}

unparse_url_test();
于 2015-07-29T04:29:55.597 回答
3

另一个实现:

function build_url(array $elements) {
    $e = $elements;
    return
        (isset($e['host']) ? (
            (isset($e['scheme']) ? "$e[scheme]://" : '//') .
            (isset($e['user']) ? $e['user'] . (isset($e['pass']) ? ":$e[pass]" : '') . '@' : '') .
            $e['host'] .
            (isset($e['port']) ? ":$e[port]" : '')
        ) : '') .
        (isset($e['path']) ? $e['path'] : '/') .
        (isset($e['query']) ? '?' . (is_array($e['query']) ? http_build_query($e['query'], '', '&') : $e['query']) : '') .
        (isset($e['fragment']) ? "#$e[fragment]" : '')
    ;
}

结果应该是:

{
    "host": "example.com"
}
/* //example.com/ */

{
    "scheme": "https",
    "host": "example.com"
}
/* https://example.com/ */

{
    "scheme": "http",
    "host": "example.com",
    "port": 8080,
    "path": "/x/y/z"
}
/* http://example.com:8080/x/y/z */

{
    "scheme": "http",
    "host": "example.com",
    "port": 8080,
    "user": "anonymous",
    "query": "a=b&c=d",
    "fragment": "xyz"
}
/* http://anonymous@example.com:8080/?a=b&c=d#xyz */

{
    "scheme": "http",
    "host": "example.com",
    "user": "root",
    "pass": "stupid",
    "path": "/x/y/z",
    "query": {
        "a": "b",
        "c": "d"
    }
}
/* http://root:stupid@example.com/x/y/z?a=b&c=d */

{
    "path": "/x/y/z",
    "query": "a=b&c=d"
}
/* /x/y/z?a=b&c=d */
于 2016-06-07T00:14:13.267 回答
3

这个答案是@BradMace 接受的答案的附录。我最初将此添加为评论,但他建议将其添加为单独的答案,所以在这里。

http_build_url($parse)由提供的原始答案pecl_http适用于扩展版本1.x- 版本2.x及更高版本是面向对象的并且语法已更改。

在较新的版本(在 上测试pecl_http v.3.2.3)实现应该是:

$httpUrl = new \http\Url($parsed);
$url = $httpUrl->toString();
于 2020-03-19T06:53:03.790 回答
2

十年后使用几十年前的方法:)

考虑到您将始终拥有方案和主机。(可选)路径、查询和片段偏移:

$a = parse_url('https://example.com/whatever-season/?drink=water&sleep=better');

使用经典的 sprintf 重新构建:

function buildUrl(array $a){
        return sprintf('%s://%s%s%s%s',
                            $a['scheme'], $a['host'], $a['path'] ?? '',
                            $a['query'] ? '?' . $a['query'] : '',
                            $a['fragment'] ? '#' . $a['fragment'] : '');
}

其中路径偏移由空合并运算符(PHP 7+) 操作。

于 2020-10-06T18:34:14.340 回答