在PHP中检查相对路径和绝对路径/ URL。

13

我需要实现函数来检查路径和网址是相对路径、绝对路径还是无效(在语法上无效-不是资源是否存在)。我应该寻找哪些情况的范围?

function check_path($dirOrFile) {
    // If it's an absolute path: (Anything that starts with a '/'?)
        return 'absolute';
    // If it's a relative path: 
        return 'relative';
    // If it's an invalid path:
        return 'invalid';
}

function check_url($url) {
    // If it's an absolute url: (Anything that starts with a 'http://' or 'https://'?)
        return 'absolute';
    // If it's a relative url:
        return 'relative';
    // If it's an invalid url:
        return 'invalid';
}

请使用以下PHP脚本将相对URL转换为绝对URL:http://nashruddin.com/PHP_Script_for_Converting_Relative_to_Absolute_URL。使用该链接中详细介绍的函数结果,并比较转换前后的结果。如果有变化,则可能存在相对URL。 - Marc B
1
<ocd>return语句中,您忘记了关闭单引号。</ocd> - Zirak
@Marc B- 虽然该链接有一些有用的部分,但如果我不知道传递给我的 URL 的基础是什么,它对我来说将无法正常工作-我将无法匹配它... - Yarin
7个回答

8

用途:

function isAbsolute($url) {
  return isset(parse_url($url)['host']);
}
解释: 如果设置了主机名,路径将是绝对路径。
例如:
$test = [
'/link?param=1'=>parse_url('/assa?ass'),
'//aaa.com/link?param=1'=>parse_url('//assa?ass'),
'http://aaa.com/link?param=1'=>parse_url('http://as.plassa?ass')
];
var_export($test);

/* Output:
[
  "/link?param=1" => array:2 [▼ // Not absolute
    "path" => "/assa"
    "query" => "ass"
  ]
  "//aaa.com/link?param=1" => array:2 [▼ // Absolute because of host
    "host" => "assa"
    "query" => "ass"
  ]
  "http://aaa.com/link?param=1" => array:3 [▼ // Absolute because of host
    "scheme" => "http"
    "host" => "as.plassa"
    "query" => "ass"
  ]
]
*/

提及此内容所需的最低PHP版本会很好。 - Valerio Bozz

5

绝对路径和URL

你是正确的,在Linux中,绝对URL必须以/开头,因此检查路径开头是否有斜杠就足够了。

对于URL,你需要检查http://https://,如你所写,但是还有更多以ftp://sftp://smb://开头的URL。因此,这非常取决于您要覆盖的使用范围。

无效的路径和URL

假设您是指Linux,路径中唯一禁止的字符是/\0。实际上,这取决于文件系统,但是对于大多数用途,您可以假定以上内容是正确的。

在Windows中,情况更加复杂。您可以在Path.GetInvalidPathChars方法文档的备注中阅读相关信息。

与Linux路径相比,URL更加复杂,因为只允许使用A-Za-z0-9-._~:/?#[]@!$&'()*+,;=(如此处的另一个答案所述)。

相对路径和URL

通常,既不是绝对路径也不是无效路径的路径和URL是相对路径和URL。


6
如果你希望你的PHP脚本能够在其他平台上移植,仅检查是否有前导斜杠是不够的,因为Windows上的绝对路径可能以反斜杠或 "C:" 开头...我想出了以下(Preg)正则表达式:/^(?:\/|\\|\w\:\\).*$/ - 这将匹配 "/file", "\file", "c:\file",但不匹配 "file""path/file" 等。 - mindplay.dk
1
其实,我记得曾经在Linux上写过一个带有\0的文件名,当时是在Ext3上(只是为了好玩)。另外,在文件名中加入\n也可以,这两个东西都能破坏99%的脚本(更不用说如果路径中有空格的话,其中一半已经崩溃了,哈哈)。 - Camilo Martin
嘿 @mindplay.dk,你的正则表达式对于C:/无法正常工作。但对于C:\可以。现在在Windows中,C:/路径也是合法的!有什么想法如何修复? - CMCDragonkai
我添加了一个额外的选项来修复:^(?:\/|\\|\w\:\\|\w\:\/).*$。它现在可以识别C:/。 - CMCDragonkai
由于PHP奇怪地转义反斜杠的方式,因此尝试在PHP上使其工作时,正则表达式必须转换为^(?:\/|\\\\|\w:\\\\|\w:\/).*$/。 - CMCDragonkai

4
由于我的声誉不佳,无法对答案进行评论,因此我必须回应ymakux的答案,他复制了Drupal库中的函数。
我正在使用这个函数,发现带有查询部分(?符号后的文本)且包含|符号的网址将被评估为false。
例如:
https://example.com/image.jpeg?fl=res,749,562,3|shr,,20|jpg,90

将被评估为false。

你所要做的就是添加

\|

到正则表达式的查询部分,使函数看起来像这样:

public static function isAbsoluteUrl($url)
    {
        $pattern = "/^(?:ftp|https?|feed)?:?\/\/(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*
        (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@)?(?:
        (?:[a-z0-9\-\.]|%[0-9a-f]{2})+|(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]))(?::[0-9]+)?(?:[\/|\?]
        (?:[\w#!:\.\?\+\|=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})*)?$/xi";

        return (bool) preg_match($pattern, $url);
    }

希望这能帮助有需要的人 :)

现在是难点所在...尝试将其修复到Drupal中 :) - Fuzzy76

4

使用Symfony FileSystem组件来检查路径是否为绝对路径:

public function isAbsolutePath($file)
{
    return strspn($file, '/\\', 0, 1)
        || (strlen($file) > 3 && ctype_alpha($file[0])
            && substr($file, 1, 1) === ':'
            && strspn($file, '/\\', 2, 1)
        )
        || null !== parse_url($file, PHP_URL_SCHEME)
    ;
}

3
这个函数来自Drupal。
public function is_absolute($url)
{
    $pattern = "/^(?:ftp|https?|feed):\/\/(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*
    (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@)?(?:
    (?:[a-z0-9\-\.]|%[0-9a-f]{2})+|(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\]))(?::[0-9]+)?(?:[\/|\?]
    (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})*)?$/xi";

    return (bool) preg_match($pattern, $url);
}

3
如果您已经知道URL格式正确:
if(strpos($uri,'://')!==false){
    //protocol: absolute url
}elseif(substr($uri,0,1)=='/'){
    //leading '/': absolute to domain name (half relative)
}else{
    //no protocol and no leading slash: relative to this page
}

1
substr($uri,0,1) != '/' 应该改为 substr($uri,0,1) == '/' 吗? - Chris Happy
1
是的 @ChrisHappy,奇怪的是有些人用那个错别字标记了它 :| 也许他们在评论中修正了它。 - Luca C.

2
我最近开始了一个composer包,可以检查URL是否是相对的/绝对的(当然还有更多功能)。
在这里查看存储库:https://github.com/Enrise/UriHelper 或者在这里查看composer Packagist包:https://packagist.org/packages/enrise/urihelper 以下是一些示例:
$uri = new \Enrise\Uri('http://usr:pss@example.com:81/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment');
echo $uri->getScheme(); // http
echo $uri->getUser(); // usr
echo $uri->getPass(); // pss
echo $uri->getHost(); // example.com
echo $uri->getPort(); // 81
echo $uri->getPath(); // /mypath/myfile.html
echo $uri->getQuery(); // a=b&b[]=2&b[]=3
echo $uri->getFragment(); // myfragment
echo $uri->isSchemeless(); // false
echo $uri->isRelative(); // false

$uri->setScheme('scheme:child:scheme.VALIDscheme123:');
$uri->setPort(null);

echo $uri->getUri(); //scheme:child:scheme.VALIDscheme123:usr:pss@example.com/mypath/myfile.html?a=b&b[]=2&b[]=3#myfragment

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接