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

8

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

Eu preciso mostrar o tempo no meu site e estou usando uma API de terceiros que é atualizada a cada 6 horas.

Estamos criando um cache local de previsão do tempo para que a API só seja chamada após o tempo de expiração. (Outro motivo: limite de 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 o clima ( say delhi ) e se ele não está lá no cache, esperava que ele retornasse false enquanto me retornava após a sequência

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

Eu usei var_dump($weather); para verificar o valor de $weather

Alguém pode me corrigir onde estou errado?

    
por Umesh Awasthi 22.11.2012 / 18:14

2 respostas

11

Captura dos dados remotos da API do clima

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

A primeira coisa que você quer fazer é alguma pesquisa em o Codex e a "API HTTP do WP" .

A maneira certa / WP de pegar dados remotos

Depois de aprender sobre a API HTTP do WP, você verá que o modo comum de fazer isso é (simplificado assim):

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

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

Então é hora de obter os dados apropriados. Isso mostrará 200 e OK , se tudo no lado remoto funcionou. IMPORTANTE: Os dados remotos provavelmente não seguem um padrão além do interno. Portanto, pode ser erros, mas você ainda receberá a mensagem 200/OK positiva de volta 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 iniciais / finais. No exemplo a seguir, você vê como usar a API HTTP do WP para verificar o cabeçalho. Se pegarmos JSON , então vamos com json_decode() e se tivermos XML , então vamos com PHP nativo SimpleXML class.

// 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 por uma classe PHP nas interwebs. Mas honestamente: se eles estão usando o CSV, é mais fácil procurar outro serviço.

Armazenar os dados em cache com um transiente

A API de transientes oferece uma maneira muito boa de fazer isso:

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

Você deve conseguir capturar o transiente com get_transient() .

Erros comuns

Um erro frequentemente encontrado é que a verificação SSL não funciona. Com prazer, você pode ligar / desligar facilmente:

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

Há uma coisa muito engraçada, como você descobrirá ao inspecionar o arquivo principal apropriado: o Core também tem um filtro para solicitações locais . Mas não se deixe enganar por este aqui. Este filtro destina-se apenas a ser usado caso você esteja A) fornecendo um serviço remoto a partir de sua instalação do WP e B) também o consumindo! Eu sei, isso pode ser um bom #WTF?! momento em que isso não é uma opção para você usar diferentes configurações de verificação SSL entre sua instalação local e seu ambiente de produção / servidor, mas também tem uma idéia por trás disso: serviços que você fornece a si mesmo enquanto eu também são explicados à comunidade do WP G + .

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

Depurando o pedido & seus resultados

Sem cavar muito fundo no processo de atualização, mas a API HTTP do WP usa a classe WP_HTTP. Também oferece uma coisa legal: um gancho de depuração.

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

Onde $response também pode ser um objeto WP_Error que talvez lhe diga mais.

Observação: A partir de um breve teste, este filtro parece funcionar (por algum motivo) apenas se você colocá-lo perto de onde você está realmente fazendo a solicitação. Então, talvez você precise chamá-lo de dentro de um retorno de chamada em um dos filtros abaixo.

Y NO CURL?

Fácil. Todo o funkiness do "WP HTTP API", que eu mostrei acima, é basicamente um wrapper baseado em função para os internos da classe WP_HTTP , que atua como classe base (e será estendido para diferentes cenários). As classes WP_HTTP_* de extensão são Fsockopen , Streams , Curl , Proxy , Cookie , Encoding . Se você ligar um retorno de chamada ao 'http_api_debug' -action, o terceiro argumento informará qual classe foi usada para sua solicitação. Você não precisa chamar as aulas diretamente. Apenas use as funções.

  

Para a maioria das solicitações da API remota / HTTP, é a classe WP_HTTP_curl , que é um wrapper para a biblioteca curl do PHP nativo.

Dentro da classe WP_HTTP_curl , você encontrará o método request() . Esse método oferece dois filtros para interceptar o comportamento do SSL: um para solicitações locais 'https_local_ssl_verify' e um para solicitações remotas 'https_ssl_verify' . O WP provavelmente definirá local como localhost e o que você recebe em return de get_option( 'siteurl' ); .

    
por kaiser 22.11.2012 / 18:33
3

O problema não é com a função 'transientes'. Parece uma mensagem de erro retornada da sua API de terceiros. Você provavelmente precisará verificar isso antes de usar set_transient . set_transient irá inserir o que for dado e get_transient irá recuperar o que estiver no banco de dados. Em outras palavras, tenho quase certeza de que o problema não é 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 supondo sobre algumas das saídas da sua API do tempo, então você pode precisar ajustar isso para obter os resultados desejados.

Observação: sua API está retornando o 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!',
      )),
    ),
  )),
))
    
por s_ha_dum 22.11.2012 / 18:31