函数文档

wp_validate_redirect()

💡 云策文档标注

概述

wp_validate_redirect() 函数用于验证重定向 URL 的安全性,确保其主机在允许列表中,并返回经过清理的 URL。如果 URL 不被允许,则返回备用 URL。

关键要点

  • 验证重定向 URL 的主机是否在允许列表中,插件可通过 allowed_redirect_hosts 过滤器修改此列表。
  • 仅允许 'http' 和 'https' 协议,拒绝 'data:' 等其他协议。
  • 如果 URL 格式错误、主机未允许或包含无效组件,则返回备用 URL。
  • 函数内部使用 wp_sanitize_redirect() 和 wp_normalize_path() 等辅助函数进行清理和路径处理。

代码示例

function wp_validate_redirect( $location, $fallback_url = '' ) {
    $location = wp_sanitize_redirect( trim( $location, " tnrx08x0B" ) );
    if ( str_starts_with( $location, '//' ) ) {
        $location = 'http:' . $location;
    }
    $cut = strpos( $location, '?' );
    $test = $cut ? substr( $location, 0, $cut ) : $location;
    $lp = parse_url( $test );
    if ( false === $lp ) {
        return $fallback_url;
    }
    if ( isset( $lp['scheme'] ) && ! ( 'http' === $lp['scheme'] || 'https' === $lp['scheme'] ) ) {
        return $fallback_url;
    }
    if ( ! isset( $lp['host'] ) && ! empty( $lp['path'] ) && '/' !== $lp['path'][0] ) {
        $path = '';
        if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
            $path = dirname( parse_url( 'http://placeholder' . $_SERVER['REQUEST_URI'], PHP_URL_PATH ) . '?' );
            $path = wp_normalize_path( $path );
        }
        $location = '/' . ltrim( $path . '/', '/' ) . $location;
    }
    if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
        return $fallback_url;
    }
    foreach ( array( 'user', 'pass', 'host' ) as $component ) {
        if ( isset( $lp[ $component ] ) && strpbrk( $lp[ $component ], ':/?#@' ) ) {
            return $fallback_url;
        }
    }
    $wpp = parse_url( home_url() );
    $allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array( $wpp['host'] ), isset( $lp['host'] ) ? $lp['host'] : '' );
    if ( isset( $lp['host'] ) && ( ! in_array( $lp['host'], $allowed_hosts, true ) && strtolower( $wpp['host'] ) !== $lp['host'] ) ) {
        $location = $fallback_url;
    }
    return $location;
}

注意事项

  • 函数自 WordPress 2.8.1 版本引入,用于增强重定向安全性。
  • 允许的主机列表默认包含当前站点的 host,可通过 allowed_redirect_hosts 过滤器扩展或限制。
  • 在 PHP 5 中,parse_url() 可能因 URL 查询部分包含 'http://' 而失败,函数通过截取处理避免此问题。

📄 原文内容

Validates a URL for use in a redirect.

Description

Checks whether the $location is using an allowed host, if it has an absolute path. A plugin can therefore set or remove allowed host(s) to or from the list.

If the host is not allowed, then the redirect is to $fallback_url supplied.

Parameters

$locationstringrequired
The redirect to validate.
$fallback_urlstringrequired
The value to return if $location is not allowed.

Return

string Redirect-sanitized URL.

Source

function wp_validate_redirect( $location, $fallback_url = '' ) {
	$location = wp_sanitize_redirect( trim( $location, " tnrx08x0B" ) );
	// Browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'.
	if ( str_starts_with( $location, '//' ) ) {
		$location = 'http:' . $location;
	}

	/*
	 * In PHP 5 parse_url() may fail if the URL query part contains 'http://'.
	 * See https://bugs.php.net/bug.php?id=38143
	 */
	$cut  = strpos( $location, '?' );
	$test = $cut ? substr( $location, 0, $cut ) : $location;

	$lp = parse_url( $test );

	// Give up if malformed URL.
	if ( false === $lp ) {
		return $fallback_url;
	}

	// Allow only 'http' and 'https' schemes. No 'data:', etc.
	if ( isset( $lp['scheme'] ) && ! ( 'http' === $lp['scheme'] || 'https' === $lp['scheme'] ) ) {
		return $fallback_url;
	}

	if ( ! isset( $lp['host'] ) && ! empty( $lp['path'] ) && '/' !== $lp['path'][0] ) {
		$path = '';
		if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
			$path = dirname( parse_url( 'http://placeholder' . $_SERVER['REQUEST_URI'], PHP_URL_PATH ) . '?' );
			$path = wp_normalize_path( $path );
		}
		$location = '/' . ltrim( $path . '/', '/' ) . $location;
	}

	/*
	 * Reject if certain components are set but host is not.
	 * This catches URLs like https:host.com for which parse_url() does not set the host field.
	 */
	if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
		return $fallback_url;
	}

	// Reject malformed components parse_url() can return on odd inputs.
	foreach ( array( 'user', 'pass', 'host' ) as $component ) {
		if ( isset( $lp[ $component ] ) && strpbrk( $lp[ $component ], ':/?#@' ) ) {
			return $fallback_url;
		}
	}

	$wpp = parse_url( home_url() );

	/**
	 * Filters the list of allowed hosts to redirect to.
	 *
	 * @since 2.3.0
	 *
	 * @param string[] $hosts An array of allowed host names.
	 * @param string   $host  The host name of the redirect destination; empty string if not set.
	 */
	$allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array( $wpp['host'] ), isset( $lp['host'] ) ? $lp['host'] : '' );

	if ( isset( $lp['host'] ) && ( ! in_array( $lp['host'], $allowed_hosts, true ) && strtolower( $wpp['host'] ) !== $lp['host'] ) ) {
		$location = $fallback_url;
	}

	return $location;
}

Hooks

apply_filters( ‘allowed_redirect_hosts’, string[] $hosts, string $host )

Filters the list of allowed hosts to redirect to.

Changelog

Version Description
2.8.1 Introduced.