Richiesta cache (HTTP) remota con API Transients


8

Sto cercando di utilizzare il get_transient()metodo nel mio Wordpress, ho letto il documento e sembra che stia facendo ciò che è stato descritto nei documenti.

Devo mostrare il meteo sul mio sito Web e sto utilizzando un'API meteorologica di terze parti che viene aggiornata ogni 6 ore.

Stiamo creando una cache locale del tempo in modo che l'API venga chiamata solo dopo la scadenza. (Altro motivo: limitazione della tariffa API)

Questo è il mio codice:

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

Quando sto inviando una posizione per ottenere weather ( say delhi) e se non è presente nella cache, mi aspettavo che tornasse falsementre mi restituiva la stringa seguente

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

Prima var_dump($weather);controllavo il valore di$weather

Qualcuno può correggermi dove sto sbagliando?


1
Questo non è correlato a get_transient()- ma con la richiesta API: come indicato dal messaggio di errore. Oltre a consigliarti di utilizzare, wp_remote_postdevi solo assicurarti che la richiesta inviata sia valida.
Stephen Harris,

@StephenHarris: Non sono sicuro della chiamata in quanto è stato dato solo all'interno. if (false === $weather)Ho aggiornato la mia domanda
Umesh Awasthi,

1
Il punto è che la cache memorizzerà tutto ciò che gli viene fornito - e in questo caso stai dando un messaggio di errore dall'API meteo. La cache restituirà false solo se non è stato archiviato nulla, quindi è necessario controllare la risposta dall'API meteorologica e, se è valida, archiviarla.
Stephen Harris,

@StephenHarris: aha ho capito che il tuo punto è sfuggito completamente. Ho appena iniziato con PHP e ho semplicemente ignorato tutto e non ho nemmeno guardato attentamente il codice :)
Umesh Awasthi,

Risposte:


11

Cattura dei dati remoti dell'API meteo

Il msg, che stai mostrando nella tua domanda è fondamentalmente il risultato dell'API meteo. E dice che non ci sono dati disponibili per la tua posizione.

La prima cosa che vuoi fare è una ricerca nel Codex e nella "API HTTP WP" .

Il modo giusto / WP per acquisire dati remoti

Dopo aver appreso dell'API HTTP WP, vedrai che il modo comune per farlo è (semplificato in questo modo):

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

Se c'è un errore (come mostrato nel tuo esempio), allora sarai in grado di prenderlo usando 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()
);

Quindi è il momento di ottenere i dati appropriati. Questo mostrerà 200e OK, se tutto sul lato remoto ha funzionato. IMPORTANTE: i dati remoti probabilmente non seguiranno uno standard rispetto a quelli interni. Quindi ci possono essere errori, ma riceverai comunque il 200/OKmessaggio positivo da loro.

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

Ottieni il risultato

Finalmente è il momento di ispezionare il risultato. Innanzitutto, ci sbarazziamo degli spazi bianchi iniziali / finali. Nel seguente esempio, viene illustrato come utilizzare l'API HTTP WP per controllare l'intestazione. Se prendiamo JSON, quindi andiamo con json_decode()e se abbiamo XML, andiamo con la SimpleXMLclasse nativa di 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...

Nel caso di un file CSV, dovrai trovare una soluzione personalizzata o cercare una classe PHP negli interwebs. Ma onestamente: se stanno usando CSV, è più facile cercare un altro servizio.

Memorizza nella cache i dati con un Transitorio

L' API Transient offre un modo abbastanza carino per farlo:

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

Dovresti quindi essere in grado di catturare il transitorio con get_transient().

Errori comuni

Un errore spesso riscontrato è che la verifica SSL non funziona. Volentieri puoi accenderlo / spegnerlo abbastanza facilmente:

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

C'è una cosa piuttosto divertente, come scoprirai controllando il file core appropriato: Core ha anche un filtro per le richieste locali . Ma non lasciarti ingannare da questo. Questo filtro ha lo scopo di abituarsi solo nel caso in cui A) fornisca un servizio remoto all'interno dell'installazione WP e B) lo consumi anche tu! Lo so, questo può essere un bel #WTF?!momento in cui questo non è uno switch per utilizzare diverse impostazioni di verifica SSL tra l'installazione locale e l'ambiente / server di produzione, ma ha anche un'idea alla base: è testare i servizi che fornisci te stesso come ho spiegato anche alla community di WP G + qui .

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

Debug della richiesta e dei suoi risultati

Senza approfondire troppo il processo di aggiornamento, ma l'API HTTP WP utilizza la classe WP_HTTP. Offre anche una bella cosa: un hook di debug.

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

Dove $responsepuò anche essere un WP_Erroroggetto che forse ti dice di più.

Nota: da un breve test, questo filtro sembra funzionare (per qualche motivo) solo se lo posizioni il più vicino possibile al punto in cui stai effettivamente facendo la richiesta. Quindi forse è necessario chiamarlo dall'interno di una richiamata su uno dei filtri di seguito.

Y NO CURL?

Facile. Tutta la stranezza dell '"API HTTP WP", che ho mostrato sopra, è fondamentalmente un wrapper basato sulle funzioni per gli WP_HTTPinterni di classe, che funge da classe di base (e verrà esteso per diversi scenari). Estendentisi WP_HTTP_*classi sono Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Se si aggancia un callback 'http_api_debug'all'azione, il terzo argomento ti dirà quale classe è stata utilizzata per la tua richiesta. Non devi chiamare direttamente le lezioni. Basta usare le funzioni.

Per la maggior parte delle richieste API HTTP / remote, è la WP_HTTP_curlclasse, che è un wrapper per la curllibreria nativa di PHP .

All'interno della WP_HTTP_curlclasse troverai il request()metodo. Questo metodo offre due filtri per intercettare il comportamento SSL: uno per le richieste locali 'https_local_ssl_verify'e uno per le richieste remote 'https_ssl_verify'. WP probabilmente definire localcome localhoste cosa si ottiene in returnda get_option( 'siteurl' );.


Nota: questa risposta può essere letta come estensione a questa risposta che ho dato .
Kaiser

Grazie per gli input, non sono sicuro della risposta dell'API waether in quanto viene chiamato solo quando non abbiamo dati, ho controllato l'URL per l'API e mi sta restituendo dati validi. Proveremo a eseguire il debug di più
Umesh Awasthi,

@UmeshAwasthi Per favore prova ciò che ho scritto sopra - passo dopo passo. Per prima cosa vedi da cosa ricevi wp_remote_request()con il tuo URL, quindi vai oltre con la risposta. È un tutorial abbastanza completo e ti mostra il modo giusto di effettuare richieste HTTP in WP. Per chiarire un po 'di più: non è necessario chiamare la WP_HTTP_curlclasse, poiché WordPress lo fa già per te, quando si utilizzano le funzioni mostrate sopra.
Kaiser

sono sulla buona strada per provare this.will aggiornato una volta completato :)
Umesh Awasthi,

1
sebbene il problema fosse qualcos'altro, ma ho contrassegnato la tua risposta come accettata in quanto fornisce un modo migliore per fare lo stesso lavoro e sono dell'opinione che se la piattaforma fornisce alcune API, è meglio usarle Grazie !!
Umesh Awasthi,

3

Il problema non riguarda la funzione "transitori". Sembra un messaggio di errore restituito dall'API di terze parti. Probabilmente è necessario verificarlo prima dell'uso set_transient. set_transientinserirà tutto ciò che viene dato e get_transientrecupererà ciò che è presente nel DB. In altre parole, sono abbastanza sicuro che il problema non è dove pensi che sia.

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

Sto indovinando un po 'dell'output della tua API meteo, quindi potrebbe essere necessario modificarlo per ottenere i risultati desiderati.

Nota: l'API sta restituendo JSON. Il tuo esempio decodifica in:

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

Grazie per l'input, ma mi sembra abbastanza strano poiché l'unica chiamata all'API viene data solo all'interno if (false === $weather)WP_HTTP_curl
dell'istruzione.Non

@UmeshAwasthi, non c'è niente di strano in questo condizionale. Se nella cache dei transitori sono presenti dati correnti, non si desidera recuperarli dall'API. È solo se la cache dei transitori non è aggiornata che si estraggono nuove informazioni.
s_ha_dum,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.