問題描述

我想通過 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。