quinta-feira, 7 de outubro de 2010

Oauth Twitter


Seguindo a mesma lógica do ultimo post, irei dividir o conteúdo em algumas partes e vou atualizando o post a medida que o tempo me permite. O tema dessa vez é o twitter e sua api. Vou utilizar o zend oauth pra autenticar no twitter e fazer algumas operações bem básicas que podem ser aproveitadas em qualquer site.
Os passos que vamos seguir serão: o registro de uma app no site do twitter, a implementação do oauth, a implementação de alguns métodos básicos (como listar timeline e tweetar) e derrepente uma interface pra completar tudo. Espero ao final disponibilizar o fonte completo que foi gerado.

Criando App

Para utilizar o protocolo oauth precisa de uma chave de aplicativo. Essa chave serve para identificar quem é o responsável pela aplicação e limitar a quantidade de acessos. Essa chave é independente de que usa a app.
Para obter esse registro basta acessar o side http://dev.twitter.com fazer o login com o seu usuário de twitter (ou um usuário especial para a app, se preferir) e acessar "Your apps". Então em "Register a app", vc vai preencher um cadastro onde duas informações são importantes para o funcionamento do app. Callback Url, que deve ser a url que o twitter vai chamar quando completar o login do usuário (http://{url}/index/callback é o que eu usei) e o Application type que deve ser browser.
O callback tem uma questão importante. ele não pode ser localhost. Então se vc estiver testando na sua maquina, coloque um endereço qualquer (eu coloquei "twitter.cesarscur.com") e adicione ele no host apontando pra 127.0.0.1. Se vc tiver duvida nessa parte, não hesitarem perguntar.

Colocando isso no código

Eu resolvi deixar tudo em um controller apesar disso ser altamente desencorajado. Optei essa forma pois eu acho que didáticamente essa maneira é muito melhor. Então lembre-se de encapsular as coisa certas usando classes genéricas para poder reaproveitar o código depois. É possível que muito seja resolvido usando Zend_Rest, mas eu não cheguei a estudar essa possibilidade.
<?php

class IndexController extends Zend_Controller_Action
{
   public $consumer;
   public $config;

   public function init()
   {
      $config = array(
     'callbackUrl' => 'http://twitter.cesarscur.com/index/callback',
     'requestTokenUrl' => 'http://twitter.com/oauth/request_token',
           'authorizeUrl' => 'https://api.twitter.com/oauth/authorize',
           'accessTokenUrl' => 'https://api.twitter.com/oauth/access_token',
           'consumerKey' => '',
           'consumerSecret' => '',
    );
    $this->config = $config;
    $this->consumer = new Zend_Oauth_Consumer($config);
   
    die('Você lembrou de settar a sua Key e Secret?
        Procure no indexController::init()em application/controller/indexController.php');
   
   }

   public function indexAction()
   {
    $params = $this->getRequest()->getParams();
    if (isset($_SESSION['TWITTER_ACCESS_TOKEN'])) {
        if ($this->getRequest()->isPost()) {
            $token = unserialize($_SESSION['TWITTER_ACCESS_TOKEN']);
            $client = $token->getHttpClient($this->config);
            $client->setUri('http://api.twitter.com/1/statuses/update.xml');
            $client->setMethod(Zend_Http_Client::POST);
            $client->setParameterPost('status', $params['tweetText']);
            $response = $client->request();
            
            $data = simplexml_load_string($response->getBody());
           
        }
    } else {
        $this->_forward('login');
        return ;
    }
   
    $token = unserialize($_SESSION['TWITTER_ACCESS_TOKEN']);

    $client = $token->getHttpClient($this->config);
    $client->setUri("http://api.twitter.com/1/users/show/{$token->user_id}.xml");
    $response = $client->request();
    $client->setMethod(Zend_Http_Client::GET);
    $userData =  simplexml_load_string($response->getBody());
    $this->view->bgImg = $userData->profile_background_image_url;
   
   
   
    $client->setUri('http://api.twitter.com/1/statuses/home_timeline.xml');
    $response = $client->request();

    $timeline =  simplexml_load_string($response->getBody());
    $this->view->timeline = $timeline;
  
   }
  
   public function loginAction()
   {
  
  
   }
  
   public function oauthAction()
   {
       if(!isset($_SESSION['TWITTER_REQUEST_TOKEN'])) {
        $token = $this->consumer->getRequestToken();
        // persist the token to storage
        $_SESSION['TWITTER_REQUEST_TOKEN'] = serialize($token);
        // redirect the user
        $this->consumer->redirect();
       }
   }   
  
   public function logoutAction()
   {
       $_SESSION['TWITTER_REQUEST_TOKEN'] = null;
       $_SESSION['TWITTER_ACCESS_TOKEN'] = null;
       $this->_redirect('');
   }
  
  
   public function callbackAction()
   {
    if (!empty($_GET) && isset($_SESSION['TWITTER_REQUEST_TOKEN'])) {
        $token = $this->consumer
                      ->getAccessToken($_GET,
                                       unserialize($_SESSION['TWITTER_REQUEST_TOKEN']));
        $_SESSION['TWITTER_ACCESS_TOKEN'] = serialize($token);
        $_SESSION['TWITTER_REQUEST_TOKEN'] = null;
    }
    $this->_redirect('');
   }
}
Certo, é um monte de código. Vamos entender o fluxo das coisas.
1 - O usuário acessa a index sem estar autenticado e é redirecionado para uma pagina para efetuar o login. A interface apenas apresenta um link para oauthAction;
2 - A action pega a requestToken com o twitter e redireciona o usuário para a pagina de login do twitter;
3 - O twitter redireciona o usuário de volta a action callback passando a acessToken. acessToken é nossa chave de entrada para os serviços da api. Então o callback redireciona o usuário para index onde ele agora pode ver a sua timeline.
4 - A index dessa vez faz uma consulta para /statuses/home_timeline e lista a timeline do usuário logado. Também usei a /users/show para pegar o papel de parede do usuário e deixar a interface um pouco mais "twitter" de ser.
5 - Na index ainda temos o handler de tweets, onde usamos o /statuses/update para postar um tweet.
Perdão pela indentação que esta um lixo. Eu estou trocando meus tabs por 4 espaços e essa faze de transição é bem complicada.
Por fim, o fonte de tudo isso, e novamente, o código precisa ser refatorado pesadamente e vários pontos, pois o propósito dele não é ser um modelo de sistemas, apenas uma demonstração de como o Zend_Oauth e a api do twitter funcionam. Não me crucifiquem pela bagunça nos css =).
Se vc não tem o zend framework configurado no seu php pode baixar e colocar ele na pasta library.
[Via ZendFramework e Maugrim's blog]