web-dev-qa-db-ja.com

Transients APIを使用してリモート(HTTP)要求をキャッシュする

私は私のWordpressでget_transient()メソッドを使おうとしています、私はドキュメントを読みました、そして、私はドキュメントで説明されたことをやっているようです。

私は私のウェブサイトに天気を表示する必要があり、私は6時間ごとに更新されるサードパーティの天気APIを使用しています。

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の値をチェックしました

誰かが私が間違っているところを私に直すことができますか?

8
Umesh Awasthi

天気APIリモートデータをキャッチする

あなたがあなたの質問に示しているmsgは、基本的に天気APIからの結果です。そして、それはあなたの場所のために利用可能なデータがないことを言います。

あなたが最初にしたいことは、 Codexと "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を示します。 重要:リモートデータは、おそらく内部データよりも標準に準拠しないでしょう。それでcanエラーがあるかもしれません、しかしあなたはまだそれらから正の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ファイルの場合は、カスタムソリューションを見つけるか、Web上で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' );

適切なコアファイルを調べるとわかるように、かなり面白いことが1つあります。コアは、 local request用のフィルタも持っています。しかし、これにだまされてはいけません。このフィルタは、A)WPインストール内からリモートサービスを提供している場合、およびB)自分で使用している場合にのみ使用することを目的としています。私は知っている、これはあなたがあなたのローカルインストールとあなたの本番環境/サーバーの間で異なるSSL検証設定を使うためのスイッチではないというかなり#WTF?!瞬間であるかもしれませんあなたは自分自身をI としてここで説明するWP G +コミュニティに説明しました

// 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 );

$responseWP_Errorオブジェクトになることもできます。

注:簡単なテストでは、このフィルタは(何らかの理由で)実際にリクエストを行っている場所の近くに配置した場合にのみ機能するようです。そのため、以下のいずれかのフィルタでコールバック内から呼び出す必要があります。

Y NO CURL?

簡単です。私が上に示した「WP HTTP API」のすべてのファンキーさは基本的に基本クラスとして機能する(そして異なるシナリオのために拡張される)WP_HTTPクラス内部のための関数ベースのラッパーです。拡張するWP_HTTP_*クラスはFsockopenStreamsCurlProxyCookieEncodingです。コールバックを'http_api_debug'-アクションにフックすると、3番目の引数はどのクラスがあなたのリクエストに使われたかを教えてくれます。 直接クラスを呼び出す必要はありません。関数を使用するだけです。

ほとんどのリモート/ HTTP APIリクエストにとって、これはWP_HTTP_curlクラスです。これはPHPネイティブのcurlライブラリのラッパーです。

WP_HTTP_curlクラスの中には、request()メソッドがあります。このメソッドは、SSLの振る舞いを傍受するための2つのフィルタを提供します。1つはローカル要求'https_local_ssl_verify'、もう1つはリモート要求'https_ssl_verify'です。 WPはおそらくlocallocalhostとして定義し、あなたがget_option( 'siteurl' );からreturnで得たものを定義するでしょう。

11
kaiser

問題は「トランジェント」機能に関するものではありません。それはあなたのサードパーティの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を返しています。 あなたの例は以下のものをデコードします:

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!',
      )),
    ),
  )),
))
3
s_ha_dum