Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

Этот пост является вторым из трех частей серии по использованию API Twitter. Если вы пропустили первую часть, вы можете прочитать ее здесь.
Аутентификация с помощью Twitter через OAuth
Birdcage использует расширение Yii под названием Yii Twitter от Will Wharton, в котором используется библиотека PHP OAuth Twitter с открытым исходным кодом Авраама Уильямса.
Я размещаю расширение в дереве Yii в папке /app/protected/extensions/yiitwitteroauth
. В Yii вы настраиваете свойства расширения в файле конфигурации main.php
следующим образом:
// application components 'components'=>array( 'twitter' => array( 'class' => 'ext.yiitwitteroauth.YiiTwitter', 'consumer_key' => '', 'consumer_secret' => '', 'callback' => '', ),
Обычно я загружал эти настройки из моего Yii .ini-файла, но чтобы упростить настройку Birdcage, я настраиваю ключи приложений из модели UserSettings
. Я расширил YiiTwitter.php
, чтобы загрузить ключи приложения по умолчанию во время инициализации:
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
для контроллера Birdcage Twitter:
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. Он сохранит ваш токен и секретный токен пользователя Twitter в таблице учетных записей:
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. Normally these would be saved in a database for future use. */ 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:
$twitter = Yii::app()->twitter->getTwitterTokened($account['oauth_token'], $account['oauth_token_secret']);
Обработка твитов в фоновом режиме
Во второй части нашего урока мы используем REST API Twitter. Часть третья будет об API реального времени на Streaming API:

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

Twitter предоставляет относительно простой способ управления этим. Вы можете просмотреть код, который выполняет это в модели Twitter Birdcage, getRecentTweets()
.
Сначала мы просматриваем самый высокий (самый последний) tweet_id
в нашей базе данных и возвращаем увеличенное значение:
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 распознает значение from_id
как указатель на место на временной шкале, с которой вы хотите начать извлечение. Он вернет все твиты более поздние, чем from_id
. В приведенном ниже примере мы запрашиваем метод REST API statuses/home_timeline. Домашняя временная шкала - это то, что пользователь видит на своем основном экране Twitter.
$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; // nothing returned
Также важно проверить, рейт лимиты Twitter'а. Каждому пользовательскому приложению разрешено 180 запросов к домашней временной шкале пользователя за 15-минутное окно, но ограничения по скорости варьируются в зависимости от активности.
Для каждого полученного твита мы вызываем наш метод Parse()
для обработки данных и сохранения их в наших различных таблицах базы данных. Во время обработки мы отслеживаем самый старый/самый низкий tweet_id
, который мы получили от Twitter:
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 добавляет информацию о пользователе на основе ссылки, а затем сам твит. В модели Parse.php
можно увидеть это более подробно.
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. Мы делаем эти последующие запросы, используя first_id
из твита, с которого мы начали, и max_id
из последнего самого старого твита, который мы получили.
// 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); } }
Так, например, когда появляются новые твиты, мы их не видим, потому что Twitter только отправляет нам твиты с самого раннего наивысшего tweet_id
(from_id
) из нашей базы данных. Нам придется вернуться позже, чтобы получить более новые твиты, которые выше, чем наш начальный from_id
.
Важно отметить, что мы не получаем бесконечное количество старых твитов. Twitter возвращает нам только количество твитов, которые мы запрашиваем, которые старше предыдущего низкого ID или (max_id
в нашем следующем вызове).
Как только вы привыкнете к этой модели, всё станет довольно просто.
Пока есть команда меню Fetch
, которая будет запускать эту операцию, мы также настраиваем задание cron
для вызова нашего метода DaemonController
каждые пять минут:
# 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 a.m every week with: # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ # # m h dom mon dow command */5 * * * * wget -O /dev/null http://birdcage.yourdomain.com/daemon/index
Это, в свою очередь, вызывает наш метод getStreams
, который выполняет описанные выше операции (обратите внимание, что функции потоков будут описаны в третьей части этой серии):
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. Здесь вы можете проверить статус услуг API Twitter.
Постинг Tweet
Постинг твитов в ваш аккаунт Twitter на самом деле довольно прост. Нам просто нужно использовать метод REST statuses/update . Для выполнения точных подсчетов символов требуется немного больше работы.
Twitter разрешает все URL-адреса в http://t.co ярлыки, поэтому все URL-адреса считаются 20 символами. Мне нужен JavaScript, который бы подсчитывал символы и любой URL-адрес приводил бы к 20 символам, независимо от длины URL-адреса. Я остановился на сочетании решений jQuery и JavaScript, о которых я расскажу ниже.
Я решил создать модель специально для составления твитов под названием Status.php
. Это упростило работу с Yii для создания форм для публикации в API.
Когда вы нажимаете Compose в меню Birdcage, он перейдет к методу Compose
StatusController
:
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 для создания элемента статуса. Проверьте _form.php
в /app/protected/views/status/
.
Во-первых, я загружу несколько библиотек jQuery и JavaScript-для подсчета количества символов:
$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 simpleCountable, twitter-text.js (скрипт для текстовой обработки Twitter на основе JavaScript) и скрипт, который значительно облегчил настройку URL: twitter_count.js.
Следующий код затем создает остаток формы компоновки и активирует скрипты подсчета символов:
<?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">*</span> are required.</p> <?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</span></p> <div class="form-actions"> <?php $this->widget('bootstrap.widgets.TbButton', array( 'buttonType'=>'submit', 'type'=>'primary', 'label'=>$model->isNewRecord ? 'Create' : 'Save', )); ?> </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 в Twitter через OAuth:
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.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post