Этот пост является вторым из серии из трех статей об использовании 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 .