PHP: 如何给绝对 URL 添加尾部斜杠

17

所以你更希望URL路径不为空,对吗? - Gumbo
http://www.domain.com?message=hello怎么样? - Kobi
@Gumbo - 我不确定你的意思。 - StackOverflowNewbie
@Kobi - 说得好。我想在问号之前应该有一个斜杠。 - StackOverflowNewbie
@StackOverflowNewbie:路径位于权限(即主机名www.domain.com)之后,可选查询或片段之前。 - Gumbo
5个回答

23

对于这个非常具体的问题,也可以考虑不使用正则表达式。如果你的列表很长(有几千个URL),时间很重要,那么你可以选择手动编写这个非常简单的操作。

这样做也能达到同样的效果:

$str .= (substr($str, -1) == '/' ? '' : '/');

这种方法当然远不如正则表达式那样优雅和灵活,但它避免了解析正则表达式字符串的开销,并且运行速度与 PHP 的能力一样快。
虽然这取决于读者对正则表达式语法的熟悉程度(有些人可能会觉得更易读),但可以说它比正则表达式可读性差。

它肯定不会检查字符串是否真的是一个格式正确的 URL(例如zerkms的正则表达式),但你已经知道你的字符串是 URL,所以这有点多余。

尽管如此,如果您的列表只有10到20个URL之类的数量,那么请忘掉这篇文章。使用正则表达式,两者的差别将为零。


33
$str = rtrim($string, '/') . '/'; 该代码的作用是去除字符串末尾的斜杠并在其后添加一个斜杠。 - user1575941
这当然远不及正则表达式那样优雅或灵活。-- 不,不,恰恰相反!对于像这样简单的任务,膝跳反应地使用 preg_... 是完全不优雅的。顺便说一下,谈到优雅:@Vino 的“smartlet”可能是这个页面上最酷的东西,干得好! :) - Sz.
请注意,这不会规范化具有多个尾部斜杠的URL。 (我看到OP在接受答案下的评论中提到了规范化作为要求;而且这是一个不错的想法。)@Vino的可以。 (那应该是一个单独的答案,并且被接受。) - Sz.

15

你可以使用parse_url()来完成这个任务,而不是使用正则表达式。例如:

$url = parse_url("http://www.example.com/ab/abc.html?a=b#xyz");
if(!isset($url['path'])) $url['path'] = '/';
$surl = $url['scheme']."://".$url['host'].$url['path'].'?'.$url['query'].'#'.$url['fragment'];
echo $surl;

@Pekka,正则表达式有什么问题吗?你不能确定parse_url是否在内部使用它。特别是当它解析的不仅仅是单个斜杠时。 - Your Common Sense
@Col - 嗯,在这种情况下,OP明确要求一个非正则表达式的解决方案。在更一般的情况下,最好的答案总是“取决于具体情况”,尽管URL通常比(\w+\.)\w+更复杂...实际上,我并不完全理解这个问题的基础,为什么要添加斜杠呢? - Kobi
2
@Col 我倾向于选择标准的URL解析函数而不是正则表达式,因为1.) 作为标准函数,它们应该处理每一个可能的边缘情况,2.) 如果你或同事不擅长正则表达式(像我一样),那么正则表达式会降低可维护性。当然,正则表达式本身没有问题。你能想到这种解决方案不适用的场景吗?如果有,你能展示一下吗?我没有看出来。 - Pekka
这不是一个好的解决方案... php > $url = parse_url("http://www.example.com"); php > if(!isset($url['path'])) $url['path'] = '/'; php > $surl = $url['scheme']."://".$url['host'].$url['path'].'?'.$url['query'].'#'.$url['fragment']; php > echo $surl; http://www.example.com/?# - Yuda Prawira
@Gunslinger_: 只需为$url数组的元素查询和片段添加isset检查。理想情况下,我们将使用isset来检查我们正在使用的$url数组中的每个元素。我没有在示例中添加它,因为我认为这是显而易见的,并且会削弱示例的基本前提。 - asleepysamurai
显示剩余2条评论

5
$url = 'http://www.domain.com';

$need_to_add_trailing_slash = preg_match('~^https?://[^/]+$~', $url);

3
你也可以这样做:$url = preg_replace("~^https?://[^/]+$~", "$0/", $url); - Kobi

1

这可能不是最优雅的解决方案,但它非常有效。首先我们获取完整的URL,然后检查是否有尾部斜杠。如果没有,检查是否没有查询字符串,它不是实际文件,也不是实际目录。如果URL满足所有这些条件,我们将添加尾部斜杠并进行301重定向。

如果您不熟悉PHP头文件...请注意,在此代码之前不能有任何输出 - 即使是空格。

$url = $_SERVER['REQUEST_URI'];
$lastchar = substr( $url, -1 );
if ( $lastchar != '/' ):
    if ( !$_SERVER['QUERY_STRING'] and !is_file( $_SERVER['DOCUMENT_ROOT'].$url ) and     !is_dir( $_SERVER['DOCUMENT_ROOT'].$url ) ):
        header("HTTP/1.1 301 Moved Permanently");
        header( "Location: $url/" );
    endif;
endif;

哎呀,我不认为完全重定向用户是必要的。这可能会导致无限循环——如果客户端因某种原因去掉了尾部斜杠怎么办?使用 substr 的做法是可以的,但你应该只在脚本中需要它的变量上加上尾部斜杠,而不是重定向用户。 - Chris Baker

1

试试这个:

if (!preg_match("/.*\/$/", $url)) {

     $url = "$url" . "/";
}

3
.*是冗余的,如果选择不同的分隔符,就可以避免转义/ - Matteo Riva

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