繁体   English   中英

PHP相当于Python的`urljoin`

[英]PHP equivalent of Python's `urljoin`

从基础URL和潜在相对路径构建URL的PHP​​等价物是什么? Python提供了urlparse.urljoin但在PHP中似乎没有任何标准实现。

我发现最接近的是人们建议使用parse_url然后从部件重建URL,但实现这一点的实现通常会使协议相关链接出错(例如, http://example.com/foo example = //example.com/foo变成http://example.com/foohttps://example.com/foo ,继承基本URL的协议),它也不容易处理父目录链接之类的东西。 以下是urlparse.urljoin正常工作的urlparse.urljoin

>>> from urlparse import urljoin
>>> urljoin('http://example.com/some/directory/filepart', 'foo.jpg')
'http://example.com/some/directory/foo.jpg'
>>> urljoin('http://example.com/some/directory/', 'foo.jpg')
'http://example.com/some/directory/foo.jpg'
>>> urljoin('http://example.com/some/directory/', '../foo.jpg')
'http://example.com/some/foo.jpg'
>>> urljoin('http://example.com/some/directory/', '/foo.jpg')
'http://example.com/foo.jpg'
>>> urljoin('http://example.com/some/directory/', '//images.example.com/bar.jpg')
'http://images.example.com/bar.jpg'
>>> urljoin('https://example.com/some/directory/', '//images.example.com/bar.jpg')
'https://images.example.com/bar.jpg'
>>> urljoin('ftp://example.com/some/directory/', '//images.example.com/bar.jpg') 
'ftp://images.example.com/bar.jpg'
>>> urljoin('http://example.com:8080/some/directory/', '//images.example.com/bar.jpg')
'http://images.example.com/bar.jpg'

有没有一种在PHP中实现相同的惯用方法,或者一个备受好评的简单库或实现,实际上所有这些情况都是正确的?

因为显然需要这个功能,并且没有任何随机脚本覆盖所有基础,我已经在Github上启动了一个项目 ,试图做到正确。

urljoin()的实现目前如下:

function urljoin($base, $rel) {
    $pbase = parse_url($base);
    $prel = parse_url($rel);

    $merged = array_merge($pbase, $prel);
    if ($prel['path'][0] != '/') {
        // Relative path
        $dir = preg_replace('@/[^/]*$@', '', $pbase['path']);
        $merged['path'] = $dir . '/' . $prel['path'];
    }

    // Get the path components, and remove the initial empty one
    $pathParts = explode('/', $merged['path']);
    array_shift($pathParts);

    $path = [];
    $prevPart = '';
    foreach ($pathParts as $part) {
        if ($part == '..' && count($path) > 0) {
            // Cancel out the parent directory (if there's a parent to cancel)
            $parent = array_pop($path);
            // But if it was also a parent directory, leave it in
            if ($parent == '..') {
                array_push($path, $parent);
                array_push($path, $part);
            }
        } else if ($prevPart != '' || ($part != '.' && $part != '')) {
            // Don't include empty or current-directory components
            if ($part == '.') {
                $part = '';
            }
            array_push($path, $part);
        }
        $prevPart = $part;
    }
    $merged['path'] = '/' . implode('/', $path);

    $ret = '';
    if (isset($merged['scheme'])) {
        $ret .= $merged['scheme'] . ':';
    }

    if (isset($merged['scheme']) || isset($merged['host'])) {
        $ret .= '//';
    }

    if (isset($prel['host'])) {
        $hostSource = $prel;
    } else {
        $hostSource = $pbase;
    }

    // username, password, and port are associated with the hostname, not merged
    if (isset($hostSource['host'])) {
        if (isset($hostSource['user'])) {
            $ret .= $hostSource['user'];
            if (isset($hostSource['pass'])) {
                $ret .= ':' . $hostSource['pass'];
            }
            $ret .= '@';
        }
        $ret .= $hostSource['host'];
        if (isset($hostSource['port'])) {
            $ret .= ':' . $hostSource['port'];
        }
    }

    if (isset($merged['path'])) {
        $ret .= $merged['path'];
    }

    if (isset($prel['query'])) {
        $ret .= '?' . $prel['query'];
    }

    if (isset($prel['fragment'])) {
        $ret .= '#' . $prel['fragment'];
    }


    return $ret;
}

此函数将正确处理用户,密码,端口号,查询字符串,锚点,甚至file:/// URL(这似乎是此类现有函数中的常见缺陷)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM