如何在PHP中正确创建HTML链接? [英] How to properly create HTML links in PHP?

查看:70
本文介绍了如何在PHP中正确创建HTML链接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题与 rawurlencode http_build_query & html特殊字符.

直到现在,我在普通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中,必须使用第三参数&amp;调用函数http_build_query,并且在header('Location: ...');中仅使用&调用上下文感知.另一种选择是将其通过htmlspecialchars传递,然后以HTML显示.

  • urlencode ((建议早于IMO淘汰))建议仅对查询字符串的值部分进行编码,然后将整个查询字符串通过htmlentities传递,然后以HTML显示.在我看来,这是非常不正确的.关键部分仍可能包含禁止的URL字符.

    $query_string = 'foo=' . urlencode($foo) . '&bar=' . urlencode($bar);
    echo '<a href="mycgi?' . htmlentities($query_string) . '">';
    

我的结论是按照以下方式做些事情:

$qs = [
    'a' => 'a',
    'quot;' => 'bar foo',
];
echo '<a href="?' . http_build_query($qs, null, '&amp;', PHP_QUERY_RFC3986) . '">Link</a>';

在PHP中创建HTML链接的推荐方法是什么?有没有比我想出的更简单的方法?我错过了任何关键点吗?

解决方案

由于在过去4个月中没有人能够提供答案,因此这里总结了我的发现.

如何使用查询字符串动态构建HTML链接?

如果您需要创建要在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>';

或者,您可以将第三个参数作为'&amp;'传递给http_build_query,剩下第二个参数null.这将使用&amp;而不是htmlspecialchars&.

关于空格.
为了在表单数据(即查询字符串)中使用,空格应该被编码为+,在其他任何地方都应该被编码为%20 例如new%20page.php?my+field=my+val.这是为了确保与所有浏览器的向后可比性.您可以使用更新的RFC3986,它将把空格编码为%20,并且可以在所有常见的浏览器中使用,并且可以与现代标准保持一致.

echo '<a href="?' . http_build_query($qs, null, '&amp;', PHP_QUERY_RFC3986) . '">Link</a>';


rawurlencodeurlencode

对于?之前的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)

This question is about the proper use of rawurlencode, http_build_query & htmlspecialchars.

Until now my standard way of creating HTML link in vanilla PHP was this:

$qs = [
    'foo' => 'foo~bar',
    'bar' => 'bar foo',
];
echo '<a href="?' . http_build_query($qs) . '">Link</a>';

Recently I have learned that this is not 100% correct. Here are few issues:

  • http_build_query uses by default PHP_QUERY_RFC1738 instead of PHP_QUERY_RFC3986. RFC3986 is the standard and superseded RFC1738 which in PHP is only kept for legacy use.
  • While the "special" HTML characters in the key and value part will be encoded to the percent-encoded representation, the argument separator will be an ampersand. In most sane situations this would not be a problem, but sometimes your key name might be quot; and then your link will become invalid:

    $qs = [
        'a' => 'a',
        'quot;' => 'bar',
    ];
    echo '<a href="?' . http_build_query($qs) . '">Link</a>';
    

    The code above will generate this link: ?a=a"%3B=bar!
    IMO this implies that the function http_build_query needs to be called context-aware with the 3-rd argument &amp; when in HTML, and with just & when in header('Location: ...');. Another option would be to pass it through htmlspecialchars before displaying in HTML.

  • PHP manual for urlencode (which should be deprecated long time ago IMO) suggests to encode only the value part of query string and then pass the whole query string through htmlentities before displaying in HTML. This looks very incorrect to me; the key part could still contain forbidden URL characters.

    $query_string = 'foo=' . urlencode($foo) . '&bar=' . urlencode($bar);
    echo '<a href="mycgi?' . htmlentities($query_string) . '">';
    

My conclusion is to do something along this lines:

$qs = [
    'a' => 'a',
    'quot;' => 'bar foo',
];
echo '<a href="?' . http_build_query($qs, null, '&amp;', PHP_QUERY_RFC3986) . '">Link</a>';

What is the recommended way to create HTML links in PHP? Is there an easier way than what I came up with? Have I missed any crucial points?

解决方案

Since nobody was able to provide an answer in the past 4 months, here are my findings summed up.

How to dynamically build HTML links with query string?

If you need to create query string to be used in HTML link (e.g. <a href="index.php?param1='.$value.'">Link</a>) then you should use http_build_query. This function accepts 4 parameters, with the first one being an array/object of query data. For the most part the other 3 parameters are irrelevant.

$qs = [
    'a' => 'a',
    'quot;' => 'bar foo',
];
echo '<a href="?' . http_build_query($qs) . '">Link</a>';

However, you should still pass the output of the function through htmlspecialchars to encode the & correctly. "A good framework will do this automatically, like Laravel's {{ }}"

echo '<a href="?' . htmlspecialchars(http_build_query($qs)) . '">Link</a>';

Alternatively you can pass the third argument to http_build_query as '&amp;', leaving the second one null. This will use &amp; instead of & which is what htmlspecialchars would do.

About spaces.
For use in form data (i.e. query strings) the space should be encoded as + and in any other place it should be encoded as %20 e.g. new%20page.php?my+field=my+val. This is to ensure backwards comparability with all browsers. You can use the newer RFC3986 which will encode the spaces as %20 and it will work in all common browsers as well as be up to date with modern standards.

echo '<a href="?' . http_build_query($qs, null, '&amp;', PHP_QUERY_RFC3986) . '">Link</a>';


rawurlencode vs urlencode

For any part of URL before ? you should use rawurlencode. For example:

$subdir = rawurlencode('blue+light blue');
echo '<a href="'.$subdir.'/index.php">rawurlencode</a>';

If in the above example you used urlencode the link would be broken. urlencode has very limited use and should be avoided.

Do not pass whole URL through rawurlencode. Separators / and other special characters in URL should not be encoded if they are to fulfil their function.


Footnote

There is no general agreement on the best practices for using http_build_query, other than the fact it should be passed through htmlspecialchars just like any other output in HTML context.

Laravel uses http_build_query($array, null, '&', PHP_QUERY_RFC3986)

CodeIgniter uses http_build_query($query)

Symfony uses http_build_query($extra, '', '&', PHP_QUERY_RFC3986)

Slim uses http_build_query($queryParams)

CakePHP uses http_build_query($query)

Twig uses http_build_query($url, '', '&', PHP_QUERY_RFC3986)

这篇关于如何在PHP中正确创建HTML链接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆