Mettre en cache la requête distante (HTTP) avec l'API Transients

8

J'essaie d'utiliser la get_transient()méthode dans mon Wordpress, j'ai lu le document et semble faire ce qui a été décrit dans la documentation.

Je dois afficher la météo sur mon site Web et j'utilise une API météo tierce qui est mise à jour toutes les 6 heures.

Nous créons un cache local de la météo afin que l'API ne soit appelée qu'après expiration. (Autre raison: limitation du débit de l'API)

Voici mon code:

$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);
 }

Lorsque j'envoie un emplacement pour obtenir la météo ( say delhi) et s'il n'est pas là dans le cache, je m'attendais à ce qu'il revienne falsependant qu'il me renvoie la chaîne suivante

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

J'avais l'habitude var_dump($weather);de vérifier la valeur de$weather

Quelqu'un peut-il me corriger là où je fais mal?

Umesh Awasthi
la source
1
Ce n'est pas lié à get_transient()- mais à la demande d'API: comme indiqué par le message d'erreur. En plus de vous recommander d'utiliser, wp_remote_postvous devrez simplement vous assurer que la demande envoyée est valide.
Stephen Harris
@StephenHarris: Je ne suis pas sûr de l'appel car il est uniquement donné à l'intérieur if (false === $weather). J'ai mis à jour ma question
Umesh Awasthi
1
Le point est que le cache stockera tout ce que vous lui donnez - et dans ce cas, vous donnez un message d'erreur de l'API météo. Le cache ne retournera false que s'il n'y a rien de stocké - vous devez donc vérifier la réponse de l'API météo et si elle est valide - la stocker.
Stephen Harris
@StephenHarris: aha j'ai compris votre point, je l'ai complètement raté. J'ai juste commencé avec PHP et j'ai tout simplement ignoré tout et je n'ai même pas regardé attentivement le code :)
Umesh Awasthi

Réponses:

11

Capture des données distantes de l'API météo

Le msg, que vous montrez dans votre question est essentiellement le résultat de l'API météo. Et il est dit qu'aucune donnée n'est disponible pour votre emplacement.

La première chose que vous voulez faire est une recherche dans le Codex et la "WP HTTP API" .

La bonne façon / WP pour saisir des données à distance

Après avoir découvert l'API HTTP WP, vous verrez que la façon la plus courante de le faire est (simplifiée comme ceci):

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

S'il y a une erreur (comme indiqué dans votre exemple), vous pourrez l'attraper en utilisant la WP_Errorclasse:

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

Il est alors temps d'obtenir les données appropriées. Cela montrera 200et OK, si tout sur le côté distant a fonctionné. IMPORTANT: Les données distantes ne suivront probablement aucune norme que leur interne. Il peut donc y avoir des erreurs, mais vous obtiendrez toujours le 200/OKmessage positif de leur part.

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

Obtenez le résultat

Enfin, il est temps d'inspecter le résultat. Tout d'abord, nous nous débarrassons des espaces blancs avant / arrière. Dans l'exemple suivant, vous voyez comment utiliser l'API HTTP WP pour vérifier l'en-tête. Si nous avons attrapé JSON, alors nous allons avec json_decode()et si nous avons XML, alors nous allons avec la SimpleXMLclasse native PHP .

// 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...

Dans le cas d'un fichier CSV, vous devrez trouver une solution personnalisée ou rechercher une classe PHP sur les interwebs. Mais honnêtement: s'ils utilisent CSV, il est plus facile de rechercher un autre service.

Cachez les données avec un transitoire

L' API transitoire offre une assez belle façon de procéder:

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

Vous devriez alors pouvoir attraper le transitoire avec get_transient().

Erreurs courantes

Une erreur souvent rencontrée est que la vérification SSL ne fonctionne pas. Heureusement, vous pouvez l'activer / le désactiver assez facilement:

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

Il y a une chose assez drôle, comme vous le découvrirez en inspectant le fichier core approprié: Core a également un filtre pour les requêtes locales . Mais ne vous laissez pas berner par celui-ci. Ce filtre est uniquement destiné à être utilisé dans le cas où vous A) fournissez un service à distance depuis votre installation WP et B) le consommez vous-même! Je sais, cela peut être un bon #WTF?!moment que ce n'est pas un commutateur pour que vous utilisiez différents paramètres de vérification SSL entre votre installation locale et votre environnement / serveur de production, mais il a également une idée derrière: c'est pour tester les services que vous fournissez-vous comme je l'ai également expliqué à la communauté WP G + ici .

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

Débogage de la requête et de ses résultats

Sans creuser trop profondément dans le processus de mise à jour, mais l'API HTTP WP utilise la classe WP_HTTP. Il offre également une bonne chose: un crochet de débogage.

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

$responsepeut aussi être un WP_Errorobjet qui vous en dit peut-être plus.

Remarque: à partir d'un bref test, ce filtre semble ne fonctionner (pour une raison quelconque) que si vous le placez aussi près de l'endroit où vous effectuez réellement la demande. Alors peut-être que vous devez l'appeler à partir d'un rappel sur l'un des filtres ci-dessous.

OUI NON CURL?

Facile. Tout le côté génial de l '"API HTTP WP", que j'ai montré ci-dessus, est essentiellement un wrapper basé sur les fonctions pour les WP_HTTPinternes de classe, qui agit comme classe de base (et sera étendu pour différents scénarios). Les étendant les WP_HTTP_*classes sont Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Si vous accrochez un rappel à l' 'http_api_debug'action, le troisième argument vous indiquera quelle classe a été utilisée pour votre demande. Vous n'avez pas besoin d'appeler directement les classes. Utilisez simplement les fonctions.

Pour la plupart des demandes d'API HTTP / distantes, c'est la WP_HTTP_curlclasse, qui est un wrapper pour la curlbibliothèque native PHP .

À l'intérieur de la WP_HTTP_curlclasse, vous trouverez la request()méthode. Cette méthode propose deux filtres pour intercepter le comportement SSL: un pour les requêtes locales 'https_local_ssl_verify'et un pour les requêtes distantes 'https_ssl_verify'. WP définira probablement localaussi localhostet ce que vous obtenez dans returnde get_option( 'siteurl' );.

kaiser
la source
Remarque: Cette réponse peut être lue comme une extension de cette réponse que j'ai donnée .
kaiser
Merci pour les entrées, je ne suis pas sûr de la réponse de l'API waether car elle est appelée uniquement lorsque nous n'avons pas de données, j'ai vérifié l'URL de l'API et son retour me donne des données valides. J'essaierai de la déboguer plus
Umesh Awasthi
@UmeshAwasthi Veuillez essayer ce que j'ai écrit ci-dessus - étape par étape. Commencez par voir ce que vous obtenez en retour wp_remote_request()avec votre URL, puis allez plus loin avec la réponse. C'est un tutoriel assez complet et vous montre la bonne façon de faire des requêtes HTTP dans WP. Pour clarifier un peu plus: vous n'avez pas besoin d'appeler la WP_HTTP_curlclasse, car WordPress le fait déjà pour vous, lorsque vous utilisez les fonctions ci-dessus.
kaiser
je suis sur le point de tester cela. sera mis à jour une fois que je l'aurai terminé :)
Umesh Awasthi
1
bien que le problème soit autre chose, mais j'ai marqué votre réponse comme acceptée car elle offre une meilleure façon de faire le même travail et je suis d'avis que si la plate-forme fournit une API, il vaut mieux les utiliser Merci !!
Umesh Awasthi
3

Le problème n'est pas avec la fonction «transitoires». Cela ressemble à un message d'erreur renvoyé par votre API tierce. Vous devrez probablement vérifier cela avant d'utiliser set_transient. set_transientinsérera tout ce qui lui est donné et get_transientrécupérera tout ce qui se trouve dans la base de données. En d'autres termes, je suis assez sûr que le problème n'est pas là où vous le pensez.

$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);
        }
 }

Je pense à une partie de la sortie de votre API météo, vous devrez donc peut-être l'ajuster pour obtenir les résultats souhaités.

Remarque: votre API retourne JSON. Votre exemple décode pour:

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!',
      )),
    ),
  )),
))
s_ha_dum
la source
Merci pour l'entrée, mais cela me semble assez étrange car seul l'appel à l'API est donné uniquement à l'intérieur de la if (false === $weather)déclaration. Je n'étais pas au courant que la WP_HTTP_curlclasse essaiera de l'utiliser
Umesh Awasthi
@UmeshAwasthi, ce conditionnel n'a rien d'étrange. Si vous avez des données actuelles dans le cache transitoires, vous ne voulez pas les récupérer à partir de l'API. Ce n'est que si votre cache transitoire est obsolète que vous extrayez de nouvelles informations.
s_ha_dum