
Этот пост является вторым из серии из трех статей об использовании Twitter API. Если вы пропустили первую часть, вы можете прочитать ее здесь .
Аутентификация с помощью Twitter через OAuth
Birdcage использует расширение Yii под названием Yii Twitter от Will Wharton , которое использует открытую библиотеку PHP OAuth Twitter от Abraham Williams .
 Я /app/protected/extensions/yiitwitteroauth расширение в дерево Yii в /app/protected/extensions/yiitwitteroauth .  В Yii вы настраиваете свойства расширения в main.php конфигурации main.php следующим образом: 
| 1 2 3 4 5 6 7 8 | // application components    ‘components’=>array(      ‘twitter’ => array(                    ‘class’ => ‘ext.yiitwitteroauth.YiiTwitter’,                    ‘consumer_key’ => »,                    ‘consumer_secret’ => »,                    ‘callback’ => »,                ), | 
  Обычно я загружаю эти настройки из моего файла Yii .ini, но чтобы упростить настройку Birdcage, я настраиваю ключи приложения из модели UserSettings .  Я расширил YiiTwitter.php для загрузки ключей приложения пользователя по умолчанию во время инициализации: 
| 1 2 3 4 5 6 7 8 9 | public function init() {      // load twitter app keys from UserSetting table    $result = UserSetting::model()->loadPrimarySettings();    $this->consumer_key = $result[‘twitter_key’];    $this->consumer_secret = $result[‘twitter_secret’];    $this->callback = $result[‘twitter_url’];        $this->registerScripts();        parent::init();    } | 
После того, как вы установили и настроили параметры приложения, вам нужно зайти в меню « Учетные записи» и нажать « Добавить учетную запись Twitter» .

  Когда вы нажимаете на значок Twitter, он выполняет метод Connect контроллера Twitter Birdcage: 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | public function actionConnect()       {        unset(Yii::app()->session[‘account_id’]);        Yii::app()->session[‘account_id’]=$_GET[‘id’];       $twitter = Yii::app()->twitter->getTwitter();       $request_token = $twitter->getRequestToken();       //set some session info       Yii::app()->session[‘oauth_token’] = $token =$request_token[‘oauth_token’];       Yii::app()->session[‘oauth_token_secret’] = $request_token[‘oauth_token_secret’];          if ($twitter->http_code == 200) {              //get twitter connect url              $url = $twitter->getAuthorizeURL($token);              //send them              Yii::app()->request->redirect($url);          }else{              //error here              $this->redirect(Yii::app()->homeUrl);          }      } | 
Это вернет вас в Twitter через OAuth для аутентификации вашей учетной записи в Twitter:

После того, как вы вошли в систему, Twitter попросит вас авторизовать приложение Birdcage:

Twitter вернет браузер на ваш URL обратного вызова, наш метод обратного вызова контроллера Twitter. Это сохранит ваш токен пользователя OAuth и секретный ключ в таблице учетных записей:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public function actionCallback() {     /* If the oauth_token is old redirect to the connect page.             if (isset($_REQUEST[‘oauth_token’]) && Yii::app()->session[‘oauth_token’] !== $_REQUEST[‘oauth_token’]) {                 Yii::app()->session[‘oauth_status’] = ‘oldtoken’;             } /* Create TwitteroAuth object with app key/secret and token key/secret from default phase */             $twitter = Yii::app()->twitter->getTwitterTokened(Yii::app()->session[‘oauth_token’], Yii::app()->session[‘oauth_token_secret’]);             /* Request access tokens from twitter */             $access_token = $twitter->getAccessToken($_REQUEST[‘oauth_verifier’]);       /* Save the access tokens.             Yii::app()->session[‘access_token’] = $access_token;             $account = Account::model()->findByAttributes(array(‘user_id’=>Yii::app()->user->id,’id’=>Yii::app()->session[‘account_id’]));             $account[‘oauth_token’] = $access_token[‘oauth_token’];             $account[‘oauth_token_secret’] = $access_token[‘oauth_token_secret’]; $account->save();                         /* Remove no longer needed request tokens */             unset(Yii::app()->session[‘oauth_token’]);             unset(Yii::app()->session[‘oauth_token_secret’]);             if (200 == $twitter->http_code) {           /* The user has been verified and the access tokens can be saved for future use */                 Yii::app()->session[‘status’] = ‘verified’;                 $this->redirect(array(‘account/admin’));             } else {                 /* Save HTTP status for error dialog on connnect page.*/                 //header(‘Location: /clearsessions.php’);                 $this->redirect(Yii::app()->homeUrl);             }        } | 
Теперь Birdcage готов начать отправлять запросы на данные Twitter через API от имени вашей учетной записи.
Как вы увидите дальше, простой вызов с токенами предоставляет доступ к API:
| 1 | $twitter = Yii::app()->twitter->getTwitterTokened($account[‘oauth_token’], $account[‘oauth_token_secret’]); | 
Обработка твитов в фоновом режиме
Для второй части нашего руководства мы используем API REST для Twitter. Третья часть будет посвящена потоковому API в реальном времени:

Получение временных шкал Twitter
Временные рамки Twitter — это постоянно расширяющийся стек твитов, поэтому мониторинг активности немного сложнее, чем в среднем по API REST. Вы можете узнать больше об уникальных проблемных графиках Twitter, представленных здесь . По сути, когда вы пытаетесь читать историю временной шкалы, все больше и больше добавляются твиты:

  Twitter предоставляет относительно простой способ управления этим.  Вы можете следовать коду, который выполняет это в модели Tweet Birdcage, getRecentTweets() . 
  Сначала мы ищем самый высокий (самый последний) tweet_id в нашей базе данных и возвращаем увеличенное значение: 
| 01 02 03 04 05 06 07 08 09 10 11 | public function getLastTweet($account_id) {    // get highest tweet_it where account_id = $account_id    $criteria=new CDbCriteria;    $criteria->select=’max(tweet_id) AS max_tweet_id’;    $criteria->condition=»account_id = «.$account_id;    $row = Tweet::model()->find($criteria);    if ($row[‘max_tweet_id’] ==0)      return 1;    else      return $row[‘max_tweet_id’]+1;  } | 
  Затем мы запрашиваем некоторое количество (например, 100) твитов, начиная с самого высокого из ранее обработанных.  API Twitter распознает since_id как указатель на место на временной шкале, с которой вы хотите начать поиск.  Он вернет все твиты, более свежие, чем since_id .  В приведенном ниже примере мы запрашиваем метод REST API statuses / home_timeline .  Домашняя временная шкала — это то, что пользователь видит на своем главном экране Twitter. 
| 1 2 3 4 5 | $since_id = $this->getLastTweet($account->id);    echo ‘since: ‘.$since_id;lb();    // retrieve tweets up until that last stored one    $tweets= $twitter->get(«statuses/home_timeline»,array(‘count’=>100,’since_id’=>$since_id));    if (count($tweets)==0) return false; | 
Также важно проверить, ограничен ли наш рейтинг Twitter . Каждому запросу пользователя приложения разрешено 180 запросов на домашнюю временную шкалу пользователя за 15-минутное окно, но ограничения скорости зависят от активности , поэтому пробег программы может варьироваться.
  Для каждого полученного твита мы вызываем наш метод Parse() чтобы обработать данные и сохранить их в различных таблицах базы данных.  Во время этого процесса мы отслеживаем самый старый / самый низкий tweet_id который мы получили из Twitter: 
| 1 2 3 4 5 6 7 | foreach ($tweets as $i) {      if ($low_id==0)        $low_id = intval($i->id_str);      else        $low_id = min(intval($i->id_str),$low_id);      Tweet::model()->parse($account->id,$i);    } | 
  Метод parse добавляет информацию о пользователе Twitter, на которую ссылаются, а затем сам твит.  В модели Parse.php есть больше деталей. 
| 1 2 3 4 5 | public function parse($account_id,$tweet) {      // add user      $tu = TwitterUser::model()->add($tweet->user);      // add tweet      $tweet_obj = $this->add($account_id,$tweet); | 
  Затем мы продолжаем запрашивать блоки твитов, используя самый низкий идентификатор из последнего запроса в качестве параметра max_id который мы отправляем в Twitter.  Мы делаем эти последующие запросы, используя since_id твита, с которого мы начали, и max_id из последнего самого старого max_id мы max_id . 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | // retrieve next block until our code limit reached    while ($count_tweets <= $limit) {      lb(2);      $max_id = $low_id-1;      $tweets= $twitter->get(«statuses/home_timeline»,array(‘count’=>100,’max_id’=>$max_id,’since_id’=>$since_id));      if (count($tweets)==0) break;      if ($this->isRateLimited($tweets)) return false;      echo ‘count’.count($tweets);lb();      $count_tweets+=count($tweets);      foreach ($tweets as $i) {        $low_id = min(intval($i->id_str),$low_id);        Tweet::model()->parse($account->id,$i);      }    } | 
  Так, например, когда поступают новые твиты, мы их не видим — потому что Твиттер отправляет нам твиты только начиная с самого высокого значения tweet_id ( since_id ) из нашей базы данных.  Мы должны будем вернуться позже, чтобы получить новые твиты, которые выше, чем наш начальный since_id . 
  Важно отметить, что мы не получаем бесконечное количество старых твитов.  Twitter возвращает нам только количество запрашиваемых твитов, которые старше предыдущего низкого идентификатора или ( max_id в нашем следующем вызове). 
Как только вы привыкнете к модели и номенклатуре, все довольно просто.
  Хотя есть команда меню Fetch которая будет запускать эту операцию, мы также настраиваем задание cron для вызова нашего метода DaemonController каждые пять минут: 
| 01 02 03 04 05 06 07 08 09 10 11 12 | # To define the time you can provide concrete values for # minute (m), hour (h), day of month (dom), month (mon), # and day of week (dow) or use ‘*’ in these fields (for ‘any’).# # Notice that tasks will be started based on the cron’s system # daemon’s notion of time and timezones. # # For example, you can run a backup of all your user accounts # at 5 am every week with: # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ # # mh dom mon dow command */5 * * * * wget -O /dev/null http://birdcage.yourdomain.com/daemon/index | 
  Это, в свою очередь, вызывает наш метод getStreams который выполняет операции, описанные выше (обратите внимание, функциональность потоков будет описана в третьей части этой серии): 
| 1 2 3 4 5 6 7 8 | public function actionIndex() {      // if not using twitter streams, we’ll process tweets by REST API      if (!Yii::app()->params[‘twitter_stream’]) {        Tweet::model()->getStreams();      } else {        Stream::model()->process();      }  } | 
Конечный результат выглядит примерно так:

Однажды я столкнулся с некоторыми проблемами надежности API Twitter. Вы можете проверить статус сервисов Twitter API здесь .
Опубликовать твит
Публикация твитов на вашем аккаунте в Twitter довольно проста. Нам просто нужно использовать метод REST statuses / update . Требуется немного больше работы для точного подсчета символов.
Twitter разрешает все URL-адреса в ярлыки http://t.co , поэтому все URL-адреса считаются 20 символами. Мне нужен был JavaScript, который бы подсчитывал символы и корректировал любой URL на 20 символов независимо от длины URL. Я остановился на комбинации решений jQuery и JavaScript, о которых я расскажу ниже.
  Я решил создать модель специально для написания твитов с именем Status.php .  Это упростило работу с Yii для создания форм для публикации в API. 
  Когда вы нажимаете Compose в меню Birdcage, вы StatusController к методу Compose StatusController : 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public function actionCompose($id=0)    {      if (!UserSetting::model()->checkConfiguration(Yii::app()->user->id)) {      Yii::app()->user->setFlash(‘warning’,’Please configure your Twitter settings.’);            $this->redirect(array(‘/usersetting/update’));      }               $model=new Status;        $model->account_id = $id;        // Uncomment the following line if AJAX validation is needed        // $this->performAjaxValidation($model);        if(isset($_POST[‘Status’]))        {            $model->attributes=$_POST[‘Status’];            if ($model->account_id==» or $model->account_id==0) {            Yii::app()->user->setFlash(‘no_account’,’You must select an account before tweeting.’);              $this->redirect(array(‘status/compose’));            }      $model->created_at =new CDbExpression(‘NOW()’);      $model->modified_at =new CDbExpression(‘NOW()’);            if($model->save()) {              $account = Account::model()->findByPK($model->account_id);              $twitter = Yii::app()->twitter->getTwitterTokened($account[‘oauth_token’], $account[‘oauth_token_secret’]);        // retrieve tweets up until that last stored one        $tweets= $twitter->post(«statuses/update»,array(‘status’=>$model->tweet_text));                $this->redirect(array(‘view’,’id’=>$model->id));                   }        }        $this->render(‘compose’,array(            ‘model’=>$model,        ));    } | 
  Это загрузит HTML-форму для создания элемента Status.  Проверьте _form.php в /app/protected/views/status/ . 
Сначала я загружу несколько библиотек jQuery и JavaScript для подсчета символов:
| 1 2 3 4 5 | $baseUrl = Yii::app()->baseUrl; $cs = Yii::app()->getClientScript(); $cs->registerScriptFile($baseUrl.’/js/jquery.simplyCountable.js’); $cs->registerScriptFile($baseUrl.’/js/twitter-text.js’); $cs->registerScriptFile($baseUrl.’/js/twitter_count.js’); | 
Я использовал комбинацию плагина jQuery simplyCountable , twitter-text.js (сценарий обработки текста Twitter на основе JavaScript) и сценарий, который выполнял тяжелую работу по корректировке URL-адресов: twitter_count.js.
Следующий код затем создает оставшуюся часть составной формы и активирует сценарии подсчета символов:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <?php $form=$this->beginWidget(‘bootstrap.widgets.TbActiveForm’,array(     ‘id’=>’status-form’,     ‘enableAjaxValidation’=>false, )); <?php   if(Yii::app()->user->hasFlash(‘no_account’)     ) {   $this->widget(‘bootstrap.widgets.TbAlert’, array(       ‘alerts’=>array( // configurations per alert type         ‘no_account’=>array(‘block’=>true, ‘fade’=>true, ‘closeText’=>’×’),       ),   )); } ?>     <p class=»help-block»>Fields with <span class=»required»>*     <?php echo $form->errorSummary($model);   <?php     if ($model->account_id == 0 ) {       echo CHtml::activeLabel($model,’account_id’,array(‘label’=>’Tweet with Account:’));       $model->account_id = 1;       echo CHtml::activeDropDownList($model,’account_id’,Account::model()->getList(),array(’empty’=>’Select an Account’));     } else {       echo CHtml::hiddenField(‘account_id’,$model->account_id);         }   ?>   <br />     <?php     echo $form->textAreaRow($model,’tweet_text’,array(‘id’=>’tweet_text’,’rows’=>6, ‘cols’=>50, ‘class’=>’span8’));    ?>    <p class=»right»>Remaining: <span id=»counter2″>0     <div class=»form-actions»>         <?php $this->widget(‘bootstrap.widgets.TbButton’, array(             ‘buttonType’=>’submit’,             ‘type’=>’primary’,             ‘label’=>$model->isNewRecord ?         ));     </div> <?php $this->endWidget(); <script type=»text/javascript» charset=»utf-8″>     $(document).ready(function()     {       $(‘#tweet_text’).simplyCountable({         counter: ‘#counter2’,       maxCount: 140,       countDirection: ‘down’       });     }); </script> | 
Результат выглядит так:

  Когда твит сохраняется, он выполняет этот код в контроллере StatusController, который tweet_text полученный tweet_text в Twitter через OAuth: 
| 1 2 3 4 5 6 7 | if($model->save()) {              $account = Account::model()->findByPK($model->account_id);              $twitter = Yii::app()->twitter->getTwitterTokened($account[‘oauth_token’], $account[‘oauth_token_secret’]);        // retrieve tweets up until that last stored one        $tweets= $twitter->post(«statuses/update»,array(‘status’=>$model->tweet_text));                $this->redirect(array(‘view’,’id’=>$model->id));            } | 
Следующие шаги
В этой части серии мы рассмотрели, как проходить аутентификацию с помощью API Twitter через OAuth, как запрашивать диапазоны твитов на временной шкале пользователя, а также как считать символы и публиковать твиты через API. Я надеюсь, что вы нашли это полезным.
Третья часть будет посвящена использованию Twitter Streaming API и реализации потоковой передачи с открытым исходным кодом Phirehose.
Пожалуйста, оставьте любые комментарии, исправления или дополнительные идеи ниже. Вы можете просмотреть мои другие учебники Tuts + на моей странице автора или подписаться на меня в Twitter @reifman .