wp_http_validate_url()
云策文档标注
概述
wp_http_validate_url() 函数用于验证 URL 是否安全,以便在 HTTP API 中使用。它检查协议、主机名、端口等,并返回原始 URL 或 false。
关键要点
- 仅支持 http 和 https 协议,其他协议如 ftp 被视为不安全。
- 验证 URL 格式,拒绝包含登录信息(如 user:pass)或无效主机名的 URL。
- 默认阻止本地网络 IP 地址(如 192.168.0.1),但可通过 'http_request_host_is_external' 过滤器允许。
- 默认仅允许端口 80、443 和 8080,可通过 'http_allowed_safe_ports' 过滤器自定义。
- 函数返回 false 表示 URL 不安全,否则返回原始 URL。
代码示例
function wp_http_validate_url( $url ) {
if ( ! is_string( $url ) || '' === $url || is_numeric( $url ) ) {
return false;
}
$original_url = $url;
$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) ) {
return false;
}
$parsed_url = parse_url( $url );
if ( ! $parsed_url || empty( $parsed_url['host'] ) ) {
return false;
}
if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) ) {
return false;
}
if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) ) {
return false;
}
$parsed_home = parse_url( get_option( 'home' ) );
$same_host = isset( $parsed_home['host'] ) && strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
$host = trim( $parsed_url['host'], '.' );
if ( ! $same_host ) {
if ( preg_match( '#^(([1-9]?d|1dd|25[0-5]|2[0-4]d).){3}([1-9]?d|1dd|25[0-5]|2[0-4]d)$#', $host ) ) {
$ip = $host;
} else {
$ip = gethostbyname( $host );
if ( $ip === $host ) {
return false;
}
}
if ( $ip ) {
$parts = array_map( 'intval', explode( '.', $ip ) );
if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0]
|| ( 172 === $parts[0] && 16 = $parts[1] )
|| ( 192 === $parts[0] && 168 === $parts[1] )
) {
if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) ) {
return false;
}
}
}
}
if ( empty( $parsed_url['port'] ) ) {
return $url;
}
$port = $parsed_url['port'];
$allowed_ports = apply_filters( 'http_allowed_safe_ports', array( 80, 443, 8080 ), $host, $url );
if ( is_array( $allowed_ports ) && in_array( $port, $allowed_ports, true ) ) {
return $url;
}
if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port ) {
return $url;
}
return false;
}注意事项
- 对于用户提交的 URL 验证,建议使用 esc_url_raw() 进行额外处理,例如通过比较 esc_url_raw( $url ) === $url 来确保安全性。
- 函数内部使用 wp_kses_bad_protocol() 来清理协议,确保仅允许 http 和 https。
- 注意过滤器 'http_request_host_is_external' 和 'http_allowed_safe_ports' 可用于扩展验证规则。
原文内容
Validates a URL as safe for use in the HTTP API.
Description
The only supported protocols are http and https.
Examples of URLs that are considered unsafe:
ftp://example.com/caniload.php– Invalid protocol – only http and https are allowed.http:///example.com/caniload.php– Malformed URL.http://user:pass@example.com/caniload.php– Login information.http://example.invalid/caniload.php– Invalid hostname, as the IP cannot be looked up in DNS.
Examples of URLs that are considered unsafe by default but can be allowed with filters:
http://192.168.0.1/caniload.php– IP address from LAN network.
This can be changed with the ‘http_request_host_is_external’ filter.http://198.143.164.252:81/caniload.php– By default, only ports 80, 443, and 8080 are allowed.
This can be changed with the ‘http_allowed_safe_ports’ filter.
Parameters
$urlstringrequired-
Request URL.
Source
function wp_http_validate_url( $url ) {
if ( ! is_string( $url ) || '' === $url || is_numeric( $url ) ) {
return false;
}
$original_url = $url;
$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) ) {
return false;
}
$parsed_url = parse_url( $url );
if ( ! $parsed_url || empty( $parsed_url['host'] ) ) {
return false;
}
if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) ) {
return false;
}
if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) ) {
return false;
}
$parsed_home = parse_url( get_option( 'home' ) );
$same_host = isset( $parsed_home['host'] ) && strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
$host = trim( $parsed_url['host'], '.' );
if ( ! $same_host ) {
if ( preg_match( '#^(([1-9]?d|1dd|25[0-5]|2[0-4]d).){3}([1-9]?d|1dd|25[0-5]|2[0-4]d)$#', $host ) ) {
$ip = $host;
} else {
$ip = gethostbyname( $host );
if ( $ip === $host ) { // Error condition for gethostbyname().
return false;
}
}
if ( $ip ) {
$parts = array_map( 'intval', explode( '.', $ip ) );
if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0]
|| ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
|| ( 192 === $parts[0] && 168 === $parts[1] )
) {
// If host appears local, reject unless specifically allowed.
/**
* Checks if HTTP request is external or not.
*
* Allows to change and allow external requests for the HTTP request.
*
* @since 3.6.0
*
* @param bool $external Whether HTTP request is external or not.
* @param string $host Host name of the requested URL.
* @param string $url Requested URL.
*/
if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) ) {
return false;
}
}
}
}
if ( empty( $parsed_url['port'] ) ) {
return $url;
}
$port = $parsed_url['port'];
/**
* Controls the list of ports considered safe in HTTP API.
*
* Allows to change and allow external requests for the HTTP request.
*
* @since 5.9.0
*
* @param int[] $allowed_ports Array of integers for valid ports. Default allowed ports
* are 80, 443, and 8080.
* @param string $host Host name of the requested URL.
* @param string $url Requested URL.
*/
$allowed_ports = apply_filters( 'http_allowed_safe_ports', array( 80, 443, 8080 ), $host, $url );
if ( is_array( $allowed_ports ) && in_array( $port, $allowed_ports, true ) ) {
return $url;
}
if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port ) {
return $url;
}
return false;
}
Hooks
- apply_filters( ‘http_allowed_safe_ports’, int[] $allowed_ports, string $host, string $url )
-
Controls the list of ports considered safe in HTTP API.
- apply_filters( ‘http_request_host_is_external’, bool $external, string $host, string $url )
-
Checks if HTTP request is external or not.
Changelog
| Version | Description |
|---|---|
| 3.5.2 | Introduced. |
Skip to note 2 content
Michael Nelson
If you’re validating a URL submitted by a user, I’d suggest instead using esc_url_raw(). Like so: `esc_url_raw( $url ) === $url`.