问题描述
我想通过 HTTP API 过滤任何 HTTP 请求 URI 。
用例:
-
WordPress 更新检查到 http://api.wordpress.org/core/version-check/1.6/,但 https://api.wordpress.org/core/version-check/1.6/也工作,我想永远使用这个。
-
新的 WordPress 文件来自 http://wordpress.org/wordpress-3.4.2.zip,但 https://wordpress.org/wordpress-3.4.2.zip 也可以使用。
-
有时我想调试请求并将这些临时重定向到本地服务器上的自定义域。
-
一些插件向其他服务器发出请求,当外部服务器关闭时,我想要替换这些请求。
更新请求是现在最重要的,因为仍然存在未固定的 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_HOST
和 WP_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_*
类是 Fsockopen
,Streams
,Curl
,Proxy
,Cookie
,Encoding
。如果您将回调挂接到'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
。
-
false
是apply_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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。