问题描述

我正在尝试在我的 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。