HTTP-Anforderung (Cache Remote) mit Transients API

8

Ich versuche, die get_transient()Methode in meinem Wordpress zu verwenden. Ich habe das Dokument gelesen und scheine das zu tun, was in den Dokumenten beschrieben wurde.

Ich muss das Wetter auf meiner Website anzeigen und verwende eine Wetter-API eines Drittanbieters, die alle 6 Stunden aktualisiert wird.

Wir erstellen einen lokalen Wetter-Cache, damit die API erst nach Ablauf der Zeit aufgerufen wird. (Anderer Grund: API-Ratenbegrenzung)

Das ist mein 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);
 }

Wenn ich einen Ort sende, um Wetter ( say delhi) zu erhalten, und wenn er nicht im Cache vorhanden ist, habe ich erwartet, dass er zurückkehrt, falsewährend er mir die folgende Zeichenfolge zurückgibt

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

Ich habe var_dump($weather);den Wert von überprüft$weather

Kann mich jemand korrigieren, wo ich falsch mache?

Umesh Awasthi
quelle
1
Dies hängt nicht mit get_transient()- sondern mit der API-Anforderung zusammen: wie in der Fehlermeldung angegeben. Abgesehen davon, dass Sie die Verwendung empfehlen, müssen wp_remote_postSie nur sicherstellen, dass die gesendete Anfrage gültig ist.
Stephen Harris
@ StephenHarris: Ich bin nicht sicher über den Anruf, da er nur im Inneren gegeben wird. if (false === $weather)Ich habe meine Frage aktualisiert
Umesh Awasthi
1
Der Punkt ist, dass der Cache alles speichert, was Sie ihm geben - und in diesem Fall geben Sie eine Fehlermeldung von der Wetter-API aus. Der Cache gibt nur dann false zurück, wenn nichts gespeichert ist. Überprüfen Sie daher die Antwort der Wetter-API und speichern Sie sie, falls sie gültig ist.
Stephen Harris
@ StephenHarris: Aha, ich habe verstanden, dass Ihr Punkt es einfach komplett verpasst hat. Ich habe gerade mit PHP angefangen und einfach alles ignoriert und
mir

Antworten:

11

Abrufen der Remote-Daten der Wetter-API

Das msg, was Sie in Ihrer Frage anzeigen, ist im Grunde das Ergebnis der Wetter-API. Und es heißt, dass für Ihren Standort keine Daten verfügbar sind.

Das erste, was Sie tun möchten, ist eine Recherche im Codex und in der "WP HTTP API" .

Der richtige / WP-Weg, um entfernte Daten zu erfassen

Nachdem Sie sich mit der WP-HTTP-API vertraut gemacht haben, werden Sie feststellen, dass die übliche Vorgehensweise (wie folgt vereinfacht) lautet:

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

Wenn ein Fehler auftritt (wie in Ihrem Beispiel gezeigt), können Sie ihn mithilfe der folgenden WP_ErrorKlasse abfangen :

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

Dann ist es Zeit, die entsprechenden Daten zu erhalten. Dies wird angezeigt 200und OKwenn alles auf der Remote-Seite geklappt hat. WICHTIG: Die Remote-Daten folgen wahrscheinlich keinem anderen Standard als dem internen. Es kann also zu Fehlern kommen, aber Sie erhalten trotzdem die positive 200/OKNachricht von ihnen zurück.

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

Holen Sie sich das Ergebnis

Schließlich ist es Zeit, das Ergebnis zu überprüfen. Zuerst entfernen wir führende / nachfolgende Leerzeichen. Im folgenden Beispiel sehen Sie, wie Sie die WP-HTTP-API zum Überprüfen des Headers verwenden. Wenn wir gefangen haben JSON, dann gehen wir mit json_decode()und wenn wir haben XML, dann gehen wir mit PHPs Native SimpleXMLClass.

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

Im Falle einer CSV-Datei müssen Sie eine benutzerdefinierte Lösung finden oder in den Interwebs nach einer PHP-Klasse suchen. Aber ehrlich: Wenn sie CSV verwenden, ist es einfacher, nach einem anderen Dienst zu suchen.

Zwischenspeichern Sie die Daten mit einem Transienten

Die Transient-API bietet eine gute Möglichkeit, dies zu tun:

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

Sie sollten dann in der Lage sein, den Übergang mit zu fangen get_transient().

Häufige Fehler

Ein häufig auftretender Fehler ist, dass die SSL-Überprüfung nicht funktioniert. Gerne können Sie es ganz einfach ein- und ausschalten:

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

Es gibt eine ziemlich lustige Sache, wie Sie bei der Überprüfung der entsprechenden Kerndatei herausfinden werden: Core hat auch einen Filter für lokale Anforderungen. Aber lassen Sie sich von diesem nicht täuschen. Dieser Filter ist nur für den Fall gedacht, dass Sie A) einen Remote-Dienst innerhalb Ihrer WP-Installation bereitstellen und B) ihn auch selbst verbrauchen! Ich weiß, dies kann ein ziemlicher #WTF?!Moment sein, in dem dies kein Wechsel für Sie ist, um unterschiedliche SSL-Überprüfungseinstellungen zwischen Ihrer lokalen Installation und Ihrer Produktionsumgebung / Ihrem Server zu verwenden, aber es steckt auch eine Idee dahinter: Es geht darum, Dienste zu testen, die Sie verwenden Stellen Sie sich selbst zur Verfügung, wie ich es auch der WP G + Community hier erklärt habe .

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

Debuggen der Anfrage und ihrer Ergebnisse

Ohne zu tief in den Aktualisierungsprozess einzudringen, verwendet die WP-HTTP-API jedoch die WP_HTTP-Klasse. Es bietet auch eine schöne Sache: Ein Debug-Hook.

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

Wo $responsekann auch ein WP_ErrorObjekt sein, das Ihnen vielleicht mehr sagt.

Hinweis: Nach einem kurzen Test scheint dieser Filter (aus irgendeinem Grund) nur zu funktionieren, wenn Sie ihn so nahe an der Stelle platzieren, an der Sie die Anforderung tatsächlich ausführen. Vielleicht müssen Sie es innerhalb eines Rückrufs auf einem der folgenden Filter aufrufen.

Y NO CURL?

Einfach. Die oben gezeigte Funky der "WP HTTP API" ist im Grunde ein funktionsbasierter Wrapper für die WP_HTTPKlasseninternale, der als Basisklasse fungiert (und für verschiedene Szenarien erweitert wird). Die Verlängerungs WP_HTTP_*Klassen sind Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Wenn Sie einen Rückruf in die 'http_api_debug'-action einbinden, gibt das dritte Argument an, welche Klasse für Ihre Anforderung verwendet wurde. Sie müssen die Klassen nicht direkt aufrufen. Verwenden Sie einfach die Funktionen.

Bei den meisten Remote- / HTTP-API-Anforderungen handelt es sich um die WP_HTTP_curlKlasse, die ein Wrapper für die native PHP- curlBibliothek ist.

In der WP_HTTP_curlKlasse finden Sie die request()Methode. Diese Methode bietet zwei Filter zum Abfangen des SSL-Verhaltens: einen für lokale Anforderungen 'https_local_ssl_verify'und einen für Remote-Anforderungen 'https_ssl_verify'. WP wird wahrscheinlich definieren , localwie localhostund was Sie in erhalten returnaus get_option( 'siteurl' );.

Kaiser
quelle
Hinweis: Diese Antwort kann als Erweiterung zu meiner Antwort gelesen werden .
Kaiser
Vielen Dank für die Eingaben. Ich bin mir nicht sicher, ob die Antwort von der Waether-API aufgerufen wird, wenn wir keine Daten haben. Ich habe die URL für die API überprüft und mir gültige Daten zurückgegeben. Ich werde versuchen, sie weiter zu debuggen
Umesh Awasthi
@UmeshAwasthi Bitte versuchen Sie, was ich oben geschrieben habe - Schritt für Schritt. Sehen Sie zuerst, was Sie wp_remote_request()mit Ihrer URL zurückbekommen , und fahren Sie dann mit der Antwort fort. Es ist ein ziemlich vollständiges Tutorial und zeigt Ihnen , wie Sie HTTP-Anforderungen in WP richtig stellen können. Um einen Bissen mehr zu verdeutlichen: Sie müssen die WP_HTTP_curlKlasse nicht aufrufen , da WordPress dies bereits für Sie erledigt, wenn Sie die oben gezeigten Funktionen verwenden.
Kaiser
Ich bin auf dem Weg, dies zu testen. Wird aktualisiert, sobald ich es abgeschlossen habe :)
Umesh Awasthi
1
Obwohl das Problem etwas anderes war, habe ich Ihre Antwort als akzeptiert markiert, da sie eine bessere Möglichkeit bietet, dieselbe Arbeit zu erledigen, und ich bin der Meinung, dass es besser ist, sie zu verwenden, wenn die Plattform eine API bereitstellt. Danke !!
Umesh Awasthi
3

Das Problem liegt nicht bei der Funktion "Transienten". Das sieht aus wie eine Fehlermeldung, die von Ihrer Drittanbieter-API zurückgegeben wird. Sie müssen dies wahrscheinlich überprüfen, bevor Sie es verwenden set_transient. set_transientfügt alles ein, was angegeben ist, und get_transientruft alles ab, was sich in der Datenbank befindet. Mit anderen Worten, ich bin mir ziemlich sicher, dass das Problem nicht dort liegt, wo Sie denken, dass es liegt.

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

Ich vermute einige der Ausgaben Ihrer Wetter-API, daher müssen Sie diese möglicherweise anpassen, um die gewünschten Ergebnisse zu erzielen.

Hinweis: Ihre API gibt JSON zurück. Ihr Beispiel dekodiert zu:

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
quelle
Vielen Dank für die Eingabe, aber es scheint mir ziemlich seltsam, da nur der Aufruf der API nur innerhalb der if (false === $weather)Anweisung erfolgt. Ich war mir nicht bewusst, dass die WP_HTTP_curlKlasse versuchen wird, dies zu verwenden
Umesh Awasthi
@UmeshAwasthi, an dieser Bedingung ist nichts Seltsames. Wenn Sie aktuelle Daten im Transienten-Cache haben, möchten Sie diese nicht von der API abrufen. Nur wenn Ihr Transienten-Cache veraltet ist, rufen Sie neue Informationen ab.
s_ha_dum