问题描述
我正在尝试在我的 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()
);
那么是时候得到适当的数据了。这将显示 200
和 OK
,如果远程方面的所有内容都已经完成。重要信息:远程数据可能不符合其内部标准。所以可能会有错误,但是您仍然会从中获得积极的 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_*
类是 Fsockopen
,Streams
,Curl
,Proxy
,Cookie
,Encoding
。如果您将回调挂接到'http_api_debug'
-action,则第三个参数将告诉您哪个类用于您的请求。你不必直接调用班级。只需使用功能。
For most remote/HTTP API requests, it’s the
WP_HTTP_curl
class, which is a wrapper for PHPs nativecurl
library.
在 WP_HTTP_curl
类中,可以找到 request()
方法。此方法提供两个过滤器来拦截 SSL 行为:一个用于本地请求'https_local_ssl_verify'
,一个用于远程请求'https_ssl_verify'
。 WP 可能会将 local
定义为 localhost
,以及 return
在 get_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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。