问题描述

我想通过 HTTP API 过滤任何 HTTP 请求 URI 。

用例:

  1. WordPress 更新检查到 http://api.wordpress.org/core/version-check/1.6/,但 https://api.wordpress.org/core/version-check/1.6/也工作,我想永远使用这个。

  2. 新的 WordPress 文件来自 http://wordpress.org/wordpress-3.4.2.zip,但 https://wordpress.org/wordpress-3.4.2.zip 也可以使用。

  3. 有时我想调试请求并将这些临时重定向到本地服务器上的自定义域。

  4. 一些插件向其他服务器发出请求,当外部服务器关闭时,我想要替换这些请求。

更新请求是现在最重要的,因为仍然存在未固定的 bug 16778(more information),并且 HTTPS 请求降低了 Man-in-the 中间攻击的风险。

我有 searched thoroughly,我已经研究了核心代码… 但最终像 Nacin 两年前一样:

I thought for sure you could filter the URL of an HTTP request, but now I can’t find one.

我错过了什么?我有:)

最佳解决方案

不到一个答案,但只是从我的经验直接列出的事情 – 也许你忽略了一些东西。

调试请求& 其结果

没有 diggin’ 更深入到更新过程,但 WP HTTP API 使用 WP_HTTP 类。它还提供了一个好东西:调试钩。

do_action( 'http_api_debug', $response, 'response', $class, $args, $url );

哪里 $response 也可以是一个 WP_Error 对象,可能会告诉你更多。

注意:从一个简短的测试,这个过滤器似乎只是 (由于某种原因) 工作,如果你把它放在你实际执行请求的地方。所以也许你需要从一个下面的过滤器的回调中调用它。

WP_HTTP 类参数

Classes 参数本身是可过滤的,但是 afa 有些可以通过方法内部的方式重新设置为 WP 假定需要的。

apply_filters( 'http_request_args', $r, $url );

其中一个参数是 ssl_verify,默认情况下为 true(但是对于我来说,当从 – 例如 GitHub 更新时会导致大量问题) 。编辑:调试测试请求后,我发现另一个参数设置为验证 SSL 是否设置为 true 。它被称为 sslverify(不分离下划线) 。不知道这是进入游戏,如果它实际上在使用或放弃,如果你有机会影响其价值。我发现它使用'http_api_debug'过滤器。

完全定制

您也可以”simply” 覆盖整个内部部件,并使用自定义设置。有一个过滤器。

apply_filters( 'pre_http_request', false, $r, $url );

第一个 arg 需要设置为 true 。比起 $r 中的参数和 parse_url( $url ); 的结果进行交互。

Proxy

另一件可能工作的事情可能是通过自定义代理运行所有内容。这需要您的 wp-config.php 中的一些设置。我从来没有尝试过,但是我经常碰到这些常数,并总结了一些应该工作的例子,并且包括一些意见,以防我有一天需要它。您必须将 WP_PROXY_HOSTWP_PROXY_PORT 定义为最小值。设置。否则没有任何工作,它只会绕过您的代理。

# HTTP Proxies
# Used for e.g. in Intranets
# Fixes Feeds as well
# Defines the proxy adresse.
define( 'WP_PROXY_HOST',          '127.0.84.1' );
# Defines the proxy port.
define( 'WP_PROXY_PORT',          '8080' );
# Defines the proxy username.
define( 'WP_PROXY_USERNAME',      'my_user_name' );
# Defines the proxy password.
define( 'WP_PROXY_PASSWORD',      'my_password' );
# Allows you to define some adresses which
# shouldn't be passed through a proxy.
define( 'WP_PROXY_BYPASS_HOSTS',  'localhost, www.example.com' );

EDIT

WP_HTTP 类通常作为基类 (将针对不同的场景进行扩展) 。扩展的 WP_HTTP_*类是 FsockopenStreamsCurlProxyCookieEncoding 。如果您将回调挂接到'http_api_debug' -action,则第三个参数将告诉您哪个类用于您的请求。

WP_HTTP_curl 类中,可以找到 request()方法。此方法提供两个过滤器来拦截 SSL 行为:一个用于本地请求'https_local_ssl_verify',一个用于远程请求'https_ssl_verify'。 WP 可能将 local 定义为 localhost,并从 get_option( 'siteurl' ); 返回。

所以我会做的是在你执行该请求之前尝试以下的权限 (或者从一个挂钩到最接近请求的回调中)

add_filter( 'https_ssl_verify', '__return_true' );

# Local requests should be checked with something like
# 'localhost' === $_SERVER['HTTP_HOST'] or similar
# add_filter( 'https_local_ssl_verify', '__return_true' );

Sidenote:在大多数情况下,WP_HTTP_curl 将用于处理代理。

次佳解决方案

基于 @ kaiser 的有用答案,我写了一些似乎工作得很好的代码。这就是为什么我把它标记为 「答案」 的原因。

让我解释一下我的解决方案

逻辑

当通过 API 发送的请求通过 WP_Http::request()运行。这是… 的方法

@todo Refactor this code.

… 在其标题我不能同意。

现在有一些过滤器。我决定滥用 pre_http_request 作为我的需要:

add_filter( 'pre_http_request', 't5_update_wp_per_https', 10, 3 );

我们在这里得到三个参数:false, $r, $url

  • falseapply_filters()的预期回报值。如果我们发回任何东西,WordPress 立即停止,原始请求将不会被发送。

  • $r 是该请求的一组参数。我们必须在一分钟内改变这些。

  • $url 是 – 惊喜! – 网址。

所以在我们的回调 t5_update_wp_per_https()中,我们看看 URL,如果是我们想要过滤的 URL,我们不用说 「no」(false) 对 WordPress 说 NO 。

旁注:遵循以下可以通过以下方式阻止所有 HTTP 请求:add_filter( 'pre_http_request', '__return_true' );

我们用更好的 URL 和稍微调整的参数 ($r,更名为 $args 可读性) 来触发我们自己的请求。

代码

请阅读在线评论,他们很重要。

<?php
/**
 * Plugin Name: T5 Update WP per HTTPS
 * Description: Forces update checks and downloads for WP to use HTTPS.
 * Plugin URI:  http://wordpress.stackexchange.com/questions/72529/filter-any-http-request-uri
 * Version:     2012.11.14
 * Author:      Thomas Scholz
 * Author URI:  http://toscho.de
 * Licence:     MIT
 * License URI: http://opensource.org/licenses/MIT
 */

add_filter( 'pre_http_request', 't5_update_wp_per_https', 10, 3 );

/**
 * Force HTTPS requests for update checks and new WP version downloads.
 *
 * @wp-hook pre_http_request
 * @param   bool   $false
 * @param   array  $args
 * @param   string $url
 * @return  FALSE|array|object FALSE if everything is okay, an array of request
 *                            results or an WP_Error instance.
 */
function t5_update_wp_per_https( $false, $args, $url )
{
    // Split the URL into useful parts.
    $url_data = parse_url( $url );

    // It is already HTTPS.
    if ( 'https' === strtolower( $url_data['scheme'] ) )
        return FALSE;

    // Not our host.
    if ( FALSE === stripos( $url_data['host'], 'wordpress.org' ) )
        return FALSE;

    // Make that an HTTPS request.
    $new_url = substr_replace( $url, 'https', 0, 4 );

    // WP_Http cannot verify the wordpress.org certificate.
    $args['sslverify'] = FALSE;

    // It is slow. We wait at least 30 seconds.
    30 > $args['timeout'] and $args['timeout'] = 30;

    // Get an instance of WP_Http.
    $http    = _wp_http_get_object();

    // Get the result.
    $result = $http->request( $new_url, $args );

    /* prepend this line with a '#' to debug like a boss.
    print '<pre>'
    . htmlspecialchars( print_r( $result, TRUE ), ENT_QUOTES, 'utf-8', FALSE )
    . '</pre>';
    die();
    /**/

    return $result;
}

测试

没有这个插件 WordPress 使用:

  • http://api.wordpress.org/core/version-check/1.6/进行更新检查,

  • http://wordpress.org/wordpress-3.4.2.zip 下载新文件。

我测试了两个本地安装,单个站点和 multi-site 设置在 Win 7. 要强制更新,我将 wp-includes/version.php 中的 $wp_version 设置为 1 和 TwentyEleven 版本到 1.3

要观看网络流量,我使用 Wireshark:它是免费的,它运行在 Windows 和 Linux 上,它提供了一些令人印象深刻的过滤工具。

看 HTTPS 是有点困难:你看到加密的数据… 这毕竟是一个想法。要查看我的插件是否应该做什么,我先看看未加密的流量,并注意用于连接到 wordpress.org 的 IP 地址。那是 72.233.56.138,有时是 72.233.56.139 。不奇怪,有一个负载平衡器,可能还有很多其他工具,所以我们不能依赖一个 IP 地址。

然后我将 ip.addr == 72.233.56.138 键入过滤器掩码,激活插件,进入 wp-admin/update-core.php 并观看 Wireshark 的流量。绿线是纯文本的要求 – 正是我们不想要的。红线和黑线是成功的标志。

更新检查很好:它找到了 「newer」 版本。主题和核心的实际更新也很好。正是我需要的

而且,如果有一个简单的过滤器,URL 可能会更容易。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。