Solicitação remota de cache (HTTP) com API de transientes

8

Estou tentando usar o get_transient()método no meu Wordpress, li o documento e parece que estou fazendo o que foi descrito nos documentos.

Preciso mostrar o clima no meu site e estou usando uma API climática de terceiros que é atualizada a cada 6 horas.

Estamos criando um cache local do tempo para que a API só seja chamada após o prazo de validade. (Outro motivo: limitação da taxa da API)

Este é o meu código:

$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 estou enviando um local para obter weather ( say delhi) e se ele não estiver no cache, esperava que ele retornasse falseenquanto me retornasse a sequência de caracteres

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

Eu costumava var_dump($weather);verificar o valor de$weather

Alguém pode me corrigir onde estou fazendo errado?

Umesh Awasthi
fonte
1
Isso não está relacionado a get_transient()- mas com a solicitação da API: conforme fornecido pela mensagem de erro. Além de recomendar o uso, wp_remote_postvocê só precisa garantir que a solicitação enviada seja válida.
Stephen Harris
@StephenHarris: Eu não tenho certeza sobre a chamada como seu único a ser dada dentro if (false === $weather).i ter actualizado a minha pergunta
Umesh Awasthi
1
O ponto é que o cache armazenará tudo o que você fornecer - e, nesse caso, você está enviando uma mensagem de erro da API do tempo. O cache só retornará falso se não houver nada armazenado - portanto, você deve verificar a resposta da API do tempo e se é válida - armazená-lo.
Stephen Harris
@StephenHarris: aha que eu obtive seu ponto só perdeu completely.i apenas começou com PHP e eu simplesmente ignorou tudo e nem mesmo olhou atentamente para o código :)
Umesh Awasthi

Respostas:

11

Captura dos dados remotos da API do tempo

O que msgvocê está mostrando na sua pergunta é basicamente o resultado da API do tempo. E diz que não há dados disponíveis para sua localização.

A primeira coisa que você deseja fazer é pesquisar no Codex e na "API HTTP do WP" .

A maneira correta / WP de capturar dados remotos

Depois de aprender sobre a API HTTP do WP, você verá que a maneira mais comum de fazer isso é (simplificada desta maneira):

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

Se houver um erro (como mostrado no seu exemplo), você poderá detectá-lo usando a 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()
);

Então é hora de obter os dados apropriados. Isso será exibido 200e OK, se tudo do lado remoto der certo. IMPORTANTE: Os dados remotos provavelmente não seguirão nenhum padrão que o interno. Portanto, pode haver erros, mas você ainda receberá a 200/OKmensagem positiva deles.

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

Obter o resultado

Finalmente, é hora de inspecionar o resultado. Primeiro, nos livramos dos espaços em branco à esquerda / à direita. No exemplo a seguir, você vê como usar a API HTTP do WP para verificar o cabeçalho. Se pegamos JSON, seguimos json_decode()e, se conseguimos XML, seguimos com a SimpleXMLclasse nativa do 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...

No caso de um arquivo CSV, você terá que encontrar uma solução personalizada ou procurar uma classe PHP nas interwebs. Mas, honestamente: se eles estiverem usando CSV, é mais fácil procurar outro serviço.

Armazenar em cache os dados com um Transient

A API transitória oferece uma maneira bastante legal de fazer isso:

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

Você deve conseguir pegar o transitório com get_transient().

Erros comuns

Um erro frequentemente encontrado é que a verificação SSL não funciona. Felizmente, você pode ativar / desativar muito fácil:

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

Há uma coisa bem engraçada, como você descobrirá ao inspecionar o arquivo principal apropriado: o Core também possui um filtro para solicitações locais . Mas não se deixe enganar por este. Esse filtro serve apenas para ser usado no caso de você A) fornecer um serviço remoto a partir da instalação do WP e B) também consumi-lo! Sei que pode ser um #WTF?!momento em que isso não é uma opção para você usar diferentes configurações de verificação SSL entre a instalação local e o ambiente / servidor de produção, mas também tem uma ideia: é para testar os serviços que você forneça-se como também expliquei à comunidade WP G + aqui .

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

Depurando a solicitação e seus resultados

Sem aprofundar muito no processo de atualização, mas a API HTTP do WP usa a classe WP_HTTP. Ele também oferece uma coisa interessante: um gancho de depuração.

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

Onde $responsetambém pode ser um WP_Errorobjeto que talvez lhe conte mais.

Nota: A partir de um breve teste, esse filtro parece funcionar (por algum motivo) apenas se você o colocar o mais próximo de onde você está realmente fazendo a solicitação. Talvez você precise chamá-lo de dentro de um retorno de chamada em um dos filtros abaixo.

Y NÃO CURL?

Fácil. Todo o humor da "WP HTTP API", que mostrei acima, é basicamente um wrapper baseado em função para os WP_HTTPinternos da classe, que atua como classe base (e será estendido para diferentes cenários). Os que se estendem WP_HTTP_*classes são Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Se você ligar um retorno de chamada à 'http_api_debug'ação-, o terceiro argumento informará qual classe foi usada para sua solicitação. Você não precisa ligar diretamente para as aulas. Basta usar as funções.

Para a maioria das solicitações de API remota / HTTP, é a WP_HTTP_curlclasse, que é um wrapper para a curlbiblioteca nativa do PHP .

Dentro da WP_HTTP_curlclasse, você encontrará o request()método. Este método oferece dois filtros para interceptar o comportamento do SSL: um para solicitações locais 'https_local_ssl_verify'e outro para solicitações remotas 'https_ssl_verify'. WP provavelmente vai definir localcomo localhosteo que você entrar em returnpartir get_option( 'siteurl' );.

kaiser
fonte
Nota: Esta resposta pode ser lida como extensão desta resposta que dei .
Kaiser
Obrigado pelas entradas, não tenho certeza sobre a resposta da API waether, pois ela está sendo chamada apenas quando não temos dados, verifiquei o URL da API e retornou dados válidos. - Tentarei depurar mais
Umesh Awasthi
@UmeshAwasthi Por favor, tente o que escrevi acima - passo a passo. Primeiro, veja o que você recebe de volta wp_remote_request()com o seu URL e depois vá mais longe com a resposta. É um tutorial bastante completo e mostra o caminho certo para fazer solicitações HTTP no WP. Para esclarecer um pouco mais: você não precisa chamar a WP_HTTP_curlclasse, pois o WordPress já faz isso por você, quando você usa as funções mostradas acima.
Kaiser
Estou no caminho para teste this.will atualizado uma vez eu concluí-lo :)
Umesh Awasthi
1
Embora o problema fosse outra coisa, mas marquei sua resposta como aceita, pois fornece uma maneira melhor de fazer o mesmo trabalho e sou de opinião que se a plataforma estiver fornecendo alguma API, é melhor usá-la. Obrigado !!
Umesh Awasthi
3

O problema não está na função 'transitórios'. Parece uma mensagem de erro retornada da sua API de terceiros. Você provavelmente precisa verificar isso antes de usar set_transient. set_transientirá inserir o que for fornecido e get_transientrecuperará o que estiver no DB. Em outras palavras, tenho certeza de que o problema não está onde você pensa que está.

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

Eu estou adivinhando sobre alguns dos resultados da sua API do tempo, então você pode precisar ajustá-los para obter os resultados desejados.

Nota: Sua API está retornando JSON. Seu exemplo decodifica para:

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
fonte
Obrigado pela contribuição, mas parece um pouco estranho para mim, como única chamada para API é dada apenas dentro if (false === $weather)statement.I não estava ciente de WP_HTTP_curlclasse vai tentar usar esse
Umesh Awasthi
@UmeshAwasthi, não há nada de estranho nisso condicional. Se você possui dados atuais no cache de transientes, não deseja recuperá-los da API. Somente se o cache de transientes estiver desatualizado, você obterá novas informações.
s_ha_dum