函数文档

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:

Parameters

$urlstringrequired
Request URL.

Return

string|false Returns false if the URL is not safe, or the original URL if it is safe.

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.

User Contributed Notes