Статьи

Создание с помощью API Twitter: OAuth, чтение и публикация

Конечный продукт
Что вы будете создавать

Этот пост является вторым из серии из трех статей об использовании Twitter API. Если вы пропустили первую часть, вы можете прочитать ее здесь .

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» .

Управление учетными записями в приложении Birdcage

Когда вы нажимаете на значок 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 OAuth Challenge Screen

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

Авторизовать приложение для Twitter API

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 REST API

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

Вечно расширяющаяся временная шкала 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();
     }
 }

Конечный результат выглядит примерно так:

Статус птичьей клетки home_timeline через Twitter API

Однажды я столкнулся с некоторыми проблемами надежности 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>

Результат выглядит так:

Птичья клетка Составьте твит-пример PHP Twitter API

Когда твит сохраняется, он выполняет этот код в контроллере 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 .