这个问题与rawurlencode,http_build_query和htmlspecialchars的正确使用有关。
直到现在,我在普通PHP中创建HTML链接的标准方法是:
$qs = [
'foo' => 'foo~bar',
'bar' => 'bar foo',
];
echo '<a href="?' . http_build_query($qs) . '">Link</a>';
最近我了解到这不是100%正确的。这里有几个问题:
http_build_query
默认使用 PHP_QUERY_RFC1738 而不是 PHP_QUERY_RFC3986 。 RFC3986是被取代的标准RFC1738,在PHP中仅保留用于传统用途。虽然键和值部分中的“特殊” HTML字符将被编码为百分比编码的表示形式,但参数分隔符将为“&”号。在大多数理智的情况下,这不是问题,但是有时您的密钥名称可能是quot;
,然后您的链接将变得无效:
$qs = [
'a' => 'a',
'quot;' => 'bar',
];
echo '<a href="?' . http_build_query($qs) . '">Link</a>';
上面的代码将生成此链接:?a=a"%3B=bar
!
IMO表示,在HTML中,需要使用第三参数http_build_query
调用函数&
,并在&
中仅使用header('Location: ...');
调用上下文感知。另一种选择是将其通过htmlspecialchars
传递,然后以HTML显示。
urlencode
的PHP手册( IMO早已不推荐使用)建议仅对查询字符串的值部分进行编码,然后将整个查询字符串通过{ {1}},然后以HTML显示。在我看来,这是非常不正确的。关键部分仍可能包含禁止的URL字符。
htmlentities
我的结论是按照以下方式做些事情:
$query_string = 'foo=' . urlencode($foo) . '&bar=' . urlencode($bar);
echo '<a href="mycgi?' . htmlentities($query_string) . '">';
在PHP中创建HTML链接的推荐方法是什么?有没有比我想出的更简单的方法?我错过了任何要点吗?
答案 0 :(得分:0)
由于过去4个月中没有人能够提供答案,因此以下是我的发现。
如果您需要创建要在HTML链接中使用的查询字符串(例如<a href="index.php?param1='.$value.'">Link</a>
),则应使用http_build_query
。
该函数接受4个参数,第一个是查询数据的数组/对象。在大多数情况下,其他三个参数无关。
$qs = [
'a' => 'a',
'quot;' => 'bar foo',
];
echo '<a href="?' . http_build_query($qs) . '">Link</a>';
但是,您仍然应该通过htmlspecialchars
传递函数的输出,以正确编码&
。 “一个好的框架会自动执行此操作,例如Laravel的{{}}”
echo '<a href="?' . htmlspecialchars(http_build_query($qs)) . '">Link</a>';
或者,您可以将第三个参数作为http_build_query
传递给'&'
,而将第二个参数null
传递给&
。这将使用&
来代替htmlspecialchars
。{p>
关于空格。
为了在表单数据(即查询字符串)中使用,空格should be encoded as +
and in any other place it should be encoded as %20
例如new%20page.php?my+field=my+val
。这是为了确保与所有浏览器的向后可比性。您可以使用更新的RFC3986,它将把空格编码为%20
,并且可以在所有常见的浏览器中使用,并且可以与现代标准保持一致。
echo '<a href="?' . http_build_query($qs, null, '&', PHP_QUERY_RFC3986) . '">Link</a>';
rawurlencode
与urlencode
对于?
之前的URL的任何部分,都应使用rawurlencode
。例如:
$subdir = rawurlencode('blue+light blue');
echo '<a href="'.$subdir.'/index.php">rawurlencode</a>';
如果在上例中使用urlencode
,则链接将断开。 urlencode
的用途非常有限,应避免使用。
请勿通过rawurlencode
传递整个URL。如果分隔符/
和URL中的其他特殊字符要实现其功能,则不应进行编码。
脚注
关于使用http_build_query
的最佳实践没有普遍的共识,只是它应该像HTML上下文中的任何其他输出一样通过htmlspecialchars
传递。
Laravel使用http_build_query($array, null, '&', PHP_QUERY_RFC3986)
CodeIgniter使用http_build_query($query)
Symfony使用http_build_query($extra, '', '&', PHP_QUERY_RFC3986)
Slim使用http_build_query($queryParams)
CakePHP使用http_build_query($query)
Twig使用http_build_query($url, '', '&', PHP_QUERY_RFC3986)