转义输出是通过剥离不需要的数据(如格式错误的 HTML 或脚本标签)来保护输出数据的过程。此过程有助于在将数据呈现给最终用户之前确保数据安全。

转义函数

WordPress 提供了许多辅助函数,可用于大多数常见场景。

请仔细关注每个函数的作用,因为有些会移除 HTML,而有些则允许保留 HTML。您必须根据要输出的内容和上下文选择最合适的函数。始终应在 echo 时进行转义,而不是在此之前。

  • esc_html() – 在任何 HTML 元素包围要显示的数据部分时使用。这将移除 HTML。
<h4><?php echo esc_html( $title ); ?></h4>
  • esc_js() – 用于内联 JavaScript。
<div onclick='<?php echo esc_js( $value ); ?>' />
  • esc_url() – 用于所有 URL,包括 HTML 元素的 src 和 href 属性中的 URL。
<img alt="" src="<?php echo esc_url( $media_url ); ?>" />
  • esc_url_raw() – 当在数据库中存储 URL 或在其他需要未编码 URL 的情况下使用。
  • esc_xml() – 用于转义 XML 块。
  • esc_attr() – 用于所有打印到 HTML 元素属性中的内容。
<ul class="<?php echo esc_attr( $stored_class ); ?>">
  • esc_textarea() – 用于对 textarea 元素内的文本进行编码。
  • wp_kses() – 用于安全地转义所有非受信任的 HTML(帖子文本、评论文本等)。这会保留 HTML。
  • wp_kses_post() – wp_kses() 的替代版本,自动允许帖子内容中允许的所有 HTML。
  • wp_kses_data() – wp_kses() 的替代版本,仅允许帖子评论中允许的 HTML。

自定义转义示例

如果您需要以特定方式转义输出,wp_kses()(发音为"kisses")函数将非常有用。

该函数确保您的输出中只会出现指定的 HTML 元素、属性和属性值,并规范化 HTML 实体。

<?php
echo wp_kses_post( $partial_html );
echo wp_kses(
    $another_partial_html,
    array(
        'a'      => array(
            'href'  => array(),
            'title' => array(),
        ),
        'br'     => array(),
        'em'     => array(),
        'strong' => array(),
    )
); ?>

在此示例中,除了 <a>、<br>、<em> 和 <strong> 之外的所有标签都将被移除。此外,如果传递了 <a> 标签,转义将确保只返回 href 和 title。

始终延迟转义

最好在尽可能晚的时候进行输出转义,理想情况下是在输出数据时进行。

延迟转义有几个好处:

  • 代码审查和部署可以更快,因为可以一眼看出输出是否安全,而不必在许多行代码中查找是否已经进行了转义以及在哪里转义的。
  • 变量可能在首次转换后到输出前被意外更改,从而引入潜在漏洞。
  • 延迟转义使得自动代码扫描更容易,节省时间并减少审查和部署时间。
  • 尽可能延迟转义可以使代码更健壮且面向未来。
  • 在输出时进行转义/转换消除了任何歧义并增加了清晰度(始终为维护者开发)。
// 可以,但不够好。
$url = esc_url( $url );
$text = esc_html( $text );
echo '<a href="'. $url . '">' . $text . '</a>';

// 好得多!
echo '<a href="'. esc_url( $url ) . '">' . esc_html( $text ) . '</a>';

… 除非无法延迟时

有时延迟转义并不实际。在极少数情况下,输出无法传递给 wp_kses(),因为根据定义,它会剥离正在生成的脚本。

在这种情况下,始终在创建字符串时进行转义,并将值存储在以 _escaped、_safe 或 _clean 作为后缀的变量中(例如,$variable 变为 $variable_escaped 或 $variable_safe)。

如果函数无法内部输出并延迟转义,则必须始终返回“安全”HTML。这使得可以直接执行 echo my_custom_script_code();,而无需通过允许此类标签的 wp_kses() 版本的脚本标签。

与本地化结合转义

与其使用 echo 输出数据,通常使用 WordPress 本地化函数,例如 _e() 或 __()。

这些函数只是在转义函数内包装一个本地化函数:

esc_html_e( 'Hello World', 'text_domain' );
// 等同于
echo esc_html( __( 'Hello World', 'text_domain' ) );

这些辅助函数结合了本地化和转义:

示例

转义在任何地方使用的任意数值变量

echo $int;

根据它是整数还是浮点数,(int)、absint()、(float) 都是正确且可接受的。
有时,number_format() 或 number_format_i18n() 可能更合适。

intval()、floatval() 是可接受的,但是过时的(PHP4)函数。

转义 HTML 属性内的任意变量

echo '<div id="', $prefix, '-box', $id, '">';

这应该用一次 esc_attr() 调用进行转义。
当变量用作属性或 URL 的一部分时,最好转义整个字符串,这样变量前面潜在的转义字符将被正确转义。

正确:

echo '<div id="', esc_attr( $prefix . '-box' . $id ), '">';

错误:

echo '<div id="', esc_attr( $prefix ), '-box', esc_attr( $id ), '">';

注意:使用 wp_create_nonce() 创建的 nonce 如果在 HTML 属性中使用,也应这样转义。

在 HTML 属性中转义任意 URL,但也适用于其他上下文

echo '<a href="', $url, '">';

这应该使用 esc_url() 进行转义。

正确:

echo '<a href="', esc_url( $url ), '">';

错误:

echo '<a href="', esc_attr( $url ), '">';
echo '<a href="', esc_attr( esc_url( $url ) ), '">';

通过 wp_localize_script() 将任意变量传递给 JavaScript

wp_localize_script( 'handle', 'name',
	array(
		'prefix_nonce' => wp_create_nonce( 'plugin-name' ),
		'ajaxurl'      => admin_url( 'admin-ajax.php' ),
		'errorMsg'     => __( 'An error occurred', 'plugin-name' ),
	)
);

无需转义,WordPress 会自动转义。

转义 JavaScript 块内的任意变量

<script type="text/javascript">
    var myVar = <?php echo $my_var; ?>
</script>

$my_var 应使用 esc_js() 进行转义。

正确:

<script type="text/javascript">
    var myVar = <?php echo esc_js( $my_var ); ?>
</script>

转义内联 JavaScript 内的任意变量

<a href="#" onclick="do_something(<?php echo $var; ?>); return false;">

$var 应使用 esc_js() 进行转义。

正确:

<a href="#" onclick="do_something(<?php echo esc_js( $var ); ?>); return false;">

转义供 JavaScript 使用的 HTML 属性内的任意变量

<a href="#" data-json="<?php echo $var; ?>">

$var 应使用 esc_js()、json_encode() 或 wp_json_encode() 进行转义。

正确:

<a href="#" data-json="<?php echo esc_js( $var ); ?>">

转义 HTML textarea 内的任意字符串

echo '<textarea>', $data, '</textarea>';

$data 应使用 esc_textarea() 进行转义。

正确:

echo '<textarea>', esc_textarea( $data ), '</textarea>';

转义 HTML 标签内的任意字符串

echo '<div>', $phrase, '</div>';

这取决于$phrase是否预期包含 HTML。

  • 如果不包含,请使用esc_html()或其任何变体。
  • 如果预期包含 HTML,请使用wp_kses_post()、wp_kses_allowed_html()或wp_kses()并指定您想要允许的 HTML 标签集合。

转义 XML 或 XSL 上下文中的任意字符串

echo '<loc>', $var, '</loc>';

使用esc_xml()或ent2ncr()进行转义。

正确做法:

echo '<loc>', ent2ncr( $var ), '</loc>';