函数文档

esc_url()

💡 云策文档标注

概述

esc_url() 是 WordPress 中用于检查和清理 URL 的核心函数,主要用于在输出到 HTML 或 XML 文档时对 URL 进行转义,确保安全性。它移除无效字符、过滤危险内容,并根据上下文(如显示用途)编码特定字符。

关键要点

  • 函数用途:清理和转义 URL,适用于文本节点、属性节点等输出场景,确保 URL 安全显示。
  • 参数说明:接受三个参数:$url(必需,要清理的 URL)、$protocols(可选,允许的协议数组,默认为 wp_allowed_protocols() 的返回值)、$_context(可选,私有参数,通常使用 'display' 用于显示)。
  • 安全特性:拒绝非白名单协议的 URL,移除无效和危险字符,编码 & 和 ' 等字符为 HTML 实体,防止 XSS 攻击。
  • 协议处理:如果 URL 不包含协议且非相对链接(如以 /、#、? 开头),则自动添加 http:// 或 https://(取决于 $protocols 的第一个元素)。
  • 相关函数:与 sanitize_url() 区分,后者用于数据库或重定向场景,而 esc_url() 专用于输出转义。
  • Hook 支持:应用 'clean_url' 过滤器,允许开发者对清理后的 URL 进行自定义修改。

代码示例

// 基本用法:清理并输出 URL
$url = 'https://example.com/page?param=1&another=2';
echo esc_url( $url );

// 指定允许的协议
$url = 'ftp://example.com/file';
echo esc_url( $url, array( 'ftp', 'http' ) );

// 在 HTML 属性中使用
echo '<a href="' . esc_url( $url ) . '">Link</a>';

// 扩展允许的协议(通过过滤器)
add_filter( 'wp_allowed_protocols', function( $protocols ) {
    $protocols[] = 'custom';
    return $protocols;
} );

注意事项

  • esc_url() 返回空字符串如果 URL 协议不在 $protocols 中或 URL 为空,使用时需检查返回值。
  • 对于数据库操作或重定向,应使用 sanitize_url() 而非 esc_url(),以避免不必要的编码。
  • 函数已替换废弃的 clean_url(),建议在新代码中统一使用 esc_url()。
  • 在显示上下文($_context='display')下,会自动编码 & 和 ' 字符,确保 HTML 兼容性。

📄 原文内容

Checks and cleans a URL.

Description

A number of characters are removed from the URL. If the URL is for displaying (the default behavior) ampersands are also replaced. The ‘clean_url’ filter is applied to the returned cleaned URL.

Parameters

$urlstringrequired
The URL to be cleaned.
$protocolsstring[]optional
An array of acceptable protocols.
Defaults to return value of wp_allowed_protocols() .

Default:null

$_contextstringoptional
Private. Use sanitize_url() for database usage.

Return

string The cleaned URL after the ‘clean_url’ filter is applied.
An empty string is returned if $url specifies a protocol other than those in $protocols, or if $url contains an empty string.

More Information

Always use esc_url when escaping URLs (in text nodes, attribute nodes or anywhere else). For sanitizing, sanitize_url() should be used instead. Rejects URLs that do not have one of the provided whitelisted protocols (defaulting to http, https, ftp, ftps, mailto, news, irc, gopher, nntp, feed, and telnet), eliminates invalid characters and removes dangerous characters. This function encodes characters as HTML entities: use it when generating an (X)HTML or XML document. Encodes ampersands (&) and single quotes (‘) as numeric entity references (&, ').

If the URL appears to be an absolute link that does not contain a scheme, prepends http://. Please note that relative urls (/my-url/parameter2/), as well as anchors (#myanchor) and parameter items (?myparam=yes) are also allowed and filtered as a special case, without prepending the default protocol to the filtered url.

Replaces the deprecated clean_url() .

Source

function esc_url( $url, $protocols = null, $_context = 'display' ) {
	$original_url = $url;

	if ( '' === $url ) {
		return $url;
	}

	$url = str_replace( ' ', '%20', ltrim( $url ) );
	$url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$|*'()[]\x80-\xff]|i', '', $url );

	if ( '' === $url ) {
		return $url;
	}

	if ( 0 !== stripos( $url, 'mailto:' ) ) {
		$strip = array( '%0d', '%0a', '%0D', '%0A' );
		$url   = _deep_replace( $strip, $url );
	}

	$url = str_replace( ';//', '://', $url );
	/*
	 * If the URL doesn't appear to contain a scheme, we presume
	 * it needs http:// prepended (unless it's a relative link
	 * starting with /, # or ?, or a PHP file). If the first item
	 * in $protocols is 'https', then https:// is prepended.
	 */
	if ( ! str_contains( $url, ':' ) && ! in_array( $url[0], array( '/', '#', '?' ), true ) &&
		! preg_match( '/^[a-z0-9-]+?.php/i', $url )
	) {
		$scheme = ( is_array( $protocols ) && 'https' === array_first( $protocols ) ) ? 'https://' : 'http://';
		$url    = $scheme . $url;
	}

	// Replace ampersands and single quotes only when displaying.
	if ( 'display' === $_context ) {
		$url = wp_kses_normalize_entities( $url );
		$url = str_replace( '&', '&', $url );
		$url = str_replace( "'", ''', $url );
	}

	if ( str_contains( $url, '[' ) || str_contains( $url, ']' ) ) {

		$parsed = wp_parse_url( $url );
		$front  = '';

		if ( isset( $parsed['scheme'] ) ) {
			$front .= $parsed['scheme'] . '://';
		} elseif ( '/' === $url[0] ) {
			$front .= '//';
		}

		if ( isset( $parsed['user'] ) ) {
			$front .= $parsed['user'];
		}

		if ( isset( $parsed['pass'] ) ) {
			$front .= ':' . $parsed['pass'];
		}

		if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
			$front .= '@';
		}

		if ( isset( $parsed['host'] ) ) {
			$front .= $parsed['host'];
		}

		if ( isset( $parsed['port'] ) ) {
			$front .= ':' . $parsed['port'];
		}

		$end_dirty = str_replace( $front, '', $url );
		$end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
		$url       = str_replace( $end_dirty, $end_clean, $url );

	}

	if ( '/' === $url[0] ) {
		$good_protocol_url = $url;
	} else {
		if ( ! is_array( $protocols ) ) {
			$protocols = wp_allowed_protocols();
		}
		$good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
		if ( strtolower( $good_protocol_url ) !== strtolower( $url ) ) {
			return '';
		}
	}

	/**
	 * Filters a string cleaned and escaped for output as a URL.
	 *
	 * @since 2.3.0
	 *
	 * @param string $good_protocol_url The cleaned URL to be returned.
	 * @param string $original_url      The URL prior to cleaning.
	 * @param string $_context          If 'display', replace ampersands and single quotes only.
	 */
	return apply_filters( 'clean_url', $good_protocol_url, $original_url, $_context );
}

Hooks

apply_filters( ‘clean_url’, string $good_protocol_url, string $original_url, string $_context )

Filters a string cleaned and escaped for output as a URL.

Changelog

Version Description
6.9.0 Prepends https:// to the URL if it does not already contain a scheme and the first item in $protocols is 'https'.
2.8.0 Introduced.

User Contributed Notes

  1. Skip to note 6 content

    Escaping the “img” tag’s “src” attribute is also something that this function should be used for:

    <img src="<?php echo esc_url( $image_url ); ?>" alt="..." />

    It should also be used for the “form” tag “action” attribute:

    <form action="<?php echo esc_url( $form_submit_url ); ?>">