問題描述

我正在嘗試在我的 WordPress 中使用 get_transient()方法,我已經閲讀了該文檔,似乎我正在做文檔中描述的內容。

我需要在我的網站上顯示天氣,我正在使用第三方天氣 API,每 6 小時更新一次。

我們正在創建一個本地緩存的天氣,所以 API 應該只在到期後被調用。 (其他原因:API 限速)

這是我的代碼:

$country   = 'India';
$API_Key  = 'xxxxxxxxxxxxxx';
$url        = 'http://weatherAPI.com/feed/weather.ashx?q='.$latlong.'&format=json&num_of_days=4&key='.$API_Key;

$weather = get_transient($location);
if (false === $weather) {
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
        $weather = curl_exec($ch);
        curl_close($ch);
        set_transient($location, $weather, 60*60*6);
 }

當我發送一個位置來獲取天氣 (say delhi),如果它不在緩存中,我期待它會返回 false,當它返回我的字符串

'{ "data": { "error": [ {"msg": "Unable to find any matching weather location to the query submitted!" } ] }}'

我用 var_dump($weather); 檢查 $weather 的值

任何人可以糾正我在做錯什麼?

最佳解決方案

捕捉天氣 API 遠程數據

msg,您在問題中顯示的基本上是天氣 API 的結果。它説,您的位置沒有可用的數據。

你想做的第一件事是 the Codex and the “WP HTTP API” 的一些研究。

正確/WP 方式來抓取遠程數據

在您瞭解了 WP HTTP API 之後,您會看到通常的方式 (簡化為這樣):

$response = wp_remote_request( 'http://example.com?some=parameter', array(
    'ssl_verify' => true
) );

如果有一個錯誤 (如您的示例所示),那麼您將能夠使用 WP_Error 類來捕獲它:

is_wp_error( $response ) AND printf(
    'There was an ERROR in your request.<br />Code: %s<br />Message: %s',
    $response->get_error_code(),
    $response->get_error_message()
);

那麼是時候得到適當的數據了。這將顯示 200OK,如果遠程方面的所有內容都已經完成。重要信息:遠程數據可能不符合其內部標準。所以可能會有錯誤,但是您仍然會從中獲得積極的 200/OK 消息。

$response_code   = wp_remote_retrieve_response_code( $response );
$response_status = wp_remote_retrieve_response_message( $response );

得到結果

最後是時候檢查結果了。首先,我們擺脱了前導/尾隨的空白。在下面的示例中,您將瞭解如何使用 WP HTTP API 來檢查頭文件。如果我們抓住了 JSON,那麼我們去 json_decode(),如果我們得到了 XML,那麼我們去使用 PHP 本機的 SimpleXML 類。

// Prepare the data:
$content = trim( wp_remote_retrieve_body( $response ) );
// Convert output to JSON
if ( strstr( wp_remote_retrieve_header( $response, 'content-type' ), 'json' ) )
{
    $content = json_decode( $content );
}
// … else, after a double check, we simply go with XML string
elseif ( strstr(
        wp_remote_retrieve_header( $response, 'content-type' ),
        'application/xhtml+xml'
    ) )
{
    // Lets make sure it is really an XML file
    // We also get cases where it's "<?XML" and "<?xml"
    if ( '<?xml' !== strtolower( substr( $content, 0, 5 ) ) )
        return false;

    // Also return stuff wrapped up in <![CDATA[Foo]]>
    $content = simplexml_load_string( $content, null, LIBXML_NOCDATA );
}
// If both didn't work out, then we maybe got a CSV, or something else...

在 CSV 文件的情況下,您必須找到一個自定義解決方案或搜索 interwebs 上的 PHP 類。但誠實地説:如果他們使用 CSV,那麼搜索其他服務會更容易。

使用瞬態緩存數據

Transient API 提供了一個很好的方式來做到這一點:

// Set Transient
$transient = set_transient(
    'Your cache key',
    $content,
    60*60*6
);

您應該可以用 get_transient()來捕捉瞬態。

常見錯誤

經常遇到的錯誤是 SSL 驗證不起作用。很高興你可以打開/關閉很容易:

// ON:
add_filter( 'https_ssl_verify', '__return_true' );
// OFF:
add_filter( 'https_ssl_verify', '__return_false' );

有一個很有趣的事情,你會發現在檢查相應的核心文件時:Core 還有一個本地請求的過濾器。但不要被這個愚弄。此過濾器僅用於在您安裝 A) 的 WP 安裝中提供遠程服務,並且 B) 也自己消耗它們!我知道,這可能是一個 #WTF?! 時刻,這不是您在本地安裝和生產環境/服務器之間使用不同 SSL 驗證設置的開關,但它也有一個想法:它是測試服務你提供自己作為我 also explained to the WP G+ community here

// Debug your own service without SSL verification.
add_filter( 'https_local_ssl_verify', '__return_false' );

調試請求& 其結果

沒有 diggin’ 更深入到更新過程,但 WP HTTP API 使用 WP_HTTP 類。它還提供了一個好東西:調試鈎。

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

哪裏 $response 也可以是一個 WP_Error 對象,可能會告訴你更多。

注意:從一個簡短的測試,這個過濾器似乎只是 (由於某種原因) 工作,如果你把它放在你實際執行請求的地方。所以也許你需要從一個下面的過濾器的回調中調用它。

沒有 CURL?

簡單。上面顯示的 「WP HTTP API」 的所有功能基本上都是基於 WP_HTTP 類內部函數的包裝器,它作為基類 (將被擴展為不同的場景) 。擴展的 WP_HTTP_*類是 FsockopenStreamsCurlProxyCookieEncoding 。如果您將回調掛接到'http_api_debug' -action,則第三個參數將告訴您哪個類用於您的請求。你不必直接調用班級。只需使用功能。

For most remote/HTTP API requests, it’s the WP_HTTP_curl class, which is a wrapper for PHPs native curl library.

WP_HTTP_curl 類中,可以找到 request()方法。此方法提供兩個過濾器來攔截 SSL 行為:一個用於本地請求'https_local_ssl_verify',一個用於遠程請求'https_ssl_verify'。 WP 可能會將 local 定義為 localhost,以及 returnget_option( 'siteurl' ); 中得到的結果。

次佳解決方案

問題不在於’transients’ 功能。這似乎是從您的第三方 API 返回的錯誤消息。在使用 set_transient 之前,您可能需要檢查。 set_transient 將插入任何給定的東西,get_transient 將檢索 DB 中的任何內容。換句話説,我相當確定問題不在你認為的地方。

$weather = get_transient($location);
if (false === $weather) {
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
        $weather = curl_exec($ch);
        curl_close($ch);
        // now check $weather to see if you got a valid result
        $check = json_decode($weather);
        if (isset($check->data->error)) {
          // there is a problem; do not insert; try something else
        } else {
          set_transient($location, $weather, 60*60*6);
        }
 }

我猜測你的天氣 API 的一些輸出,所以你可能需要調整,以獲得你想要的結果。

注意:您的 API 正在返回 JSON 。 Your example decodes to:

stdClass::__set_state(array(
   'data' =>
  stdClass::__set_state(array(
     'error' =>
    array (
      0 =>
      stdClass::__set_state(array(
         'msg' => 'Unable to find any matching weather location to the query submitted!',
      )),
    ),
  )),
))

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。