Давно хотел выложить свой простенький набор функций для отправки твитов в Twitter. Может кому полезно будет, т.к. мне не сразу всё далось, особенно формирование подписи. Плюс это моя попытка закрепить в голове то, что было познано и закодено. По-моему нет лучше способа это сделать, чем попытаться кому-то это объяснить :) Под катом описание и код.
В сети есть прилично скриптов для отправки сообщений в Twitter, но когда встала задача сделать автоматическую отправку твитов (по работе) - все они чем-то не устраивали - или излишней сложностью, или откровенным говнокодом. К тому же в процессе осваивания Twitter API полезно было написать этот велосипед для себя.
Общение с Twitter API происходит посредством авторизации через OAuth (именно OAuth, а не OAuth 2.0, хотя может уже и 2.0 можно). Для отправки запросов их необходимо будет формировать определенным образом и прилагать специально сформированную подпись.
Для начала нужно зарегистрировать приложение на dev.twitter.com, после чего вам выдадут Consumer key и Consumer secret. Также лично вам выдадут Access token и Access token secret, чтобы приложение могло сразу писать от имени вашего пользователя.
Зададим настройки доступа для скрипта:
# settings
$oauth_token = 'Your access token';
$oauth_token_secret = 'Your access token secret';
$oauth_consumer_key = 'Your consumer key';
$oauth_consumer_secret = 'Your consumer secret';
$url = 'http://api.twitter.com/1/statuses/update.json';
Отправка твита состоит в моём случае из 4 этапов:
- Формирование текста твита (строка в 140 символов с текстом, возможно ссылкой).
- Формирование параметров запроса и подписи.
- Формирование заголовков запроса.
- Отправка запроса.
Сам набор состоит из 3-х функций. Главная функция - функция postTweet(). Получает в качестве параметра текст твита. Он должен быть предварительно подготовлен - то есть иметь длину 140 символов. Обычно у меня это делается где-то вне этой функции. Внутри postTweet вызывается 2 остальные функции - функция формирования подписи (makeSignature), и собственно функция отправки твита в Twitter (postTweet).
Пойдем по порядку. Функция создания подписи makeSignature:
/**
* Создаёт подпись к данным
* @global array $oauth_consumer_secret
* @global string $oauth_token_secret
* @param string $url
* @param Array $data
* @return string
*/
function makeSignature( $url, $data ){
global $oauth_consumer_secret, $oauth_token_secret;
$txt = 'POST&' . rawurlencode( $url ) . '&';
$tmp = array();
foreach( $data as $key => $value )
$tmp[] = rawurlencode( $key ) . "%3D" . rawurlencode( $value );
$txt .= implode( "%26", $tmp );
$key = $oauth_consumer_secret . '&' . $oauth_token_secret ;
return base64_encode( hash_hmac( 'sha1', $txt, $key, true ) ) ;
}
На входе функция получает необходимые данные для формирования подписи ($data) и $url, на который будет идти запрос. В двух словах - мы формируем строку. Сначала в ней мы пишем POST, что означает, что мы будем использовать POST-запрос. Входные параметры собираются в нужном виде в строку, параметры должны идти в алфавитном порядке, затем всё это безобразие кодируется по алгоритму HMAC-SHA1, ключом для кодирования является строка:
$key = $oauth_consumer_secret . '&' . $oauth_token_secret;
Закодированная строка и является нашей подписью (signature). На эту простую функцию было потрачено прилично времени и нервов =(
Теперь главная функция - postTweet:
/**
* Отправка сообщения в Твиттер
* @global string $url
* @param string $oauth_consumer_key
* @param string $oauth_token
* @param string $statusText
*/
function postTweet( $statusText ){
global $url, $oauth_consumer_key, $oauth_token;
$nonce = md5( microtime() . mt_rand() );
$time = time();
$date = date( 'r' );
$data = array(
'oauth_consumer_key' => $oauth_consumer_key,
'oauth_nonce' => $nonce,
'oauth_signature_method' => "HMAC-SHA1",
'oauth_timestamp' => $time,
'oauth_token' => $oauth_token,
'oauth_version' => '1.0',
'status' => rawurlencode( $statusText )
);
$signature = makeSignature( $url, $data );
$data['status'] = $statusText;
$data['oauth_signature'] = $signature;
$header = 'OAuth oauth_nonce="' . rawurlencode( $nonce ) . '", ';
$header .= 'oauth_signature_method="HMAC-SHA1", ';
$header .= 'oauth_timestamp="' . rawurlencode( $time ) . '", ';
$header .= 'oauth_consumer_key="' . rawurlencode( $oauth_consumer_key ) . '", ';
$header .= 'oauth_token="' . rawurlencode( $oauth_token ) . '", ';
$header .= 'oauth_signature="' . rawurlencode( $signature ) . '", ';
$header .= 'oauth_version="1.0"';
return curlPostTweet( $url, $header, $date, $data );
}
В эту функцию передаётся уже подготовленная строка нового твита (140 символов), в массив $data формируются данные для запроса. Затем из этих же данных формируется подпись к запросу (вызывается функция makeSignature, описанная выше). Подпись добавляется к данным. Формируются заголовки для HTTP-запроса - по сути это текст "OAuth" + все те же данные массива $data. Всё это дальше передается функции curlPostTweet(), которая собственно уже и постит в Twitter. Делает она это через CURL.
function curlPostTweet( $url, $header, $date, $postData ){
$ci = curl_init();
curl_setopt( $ci, CURLOPT_URL, $url );
curl_setopt( $ci, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ci, CURLOPT_HTTPHEADER, array( 'Authorization', $header, 'Date: ' . $date ) );
curl_setopt( $ci, CURLOPT_POST, 1 );
curl_setopt( $ci, CURLOPT_POSTFIELDS, http_build_query( $postData ) );
return curl_exec( $ci );
}
Думаю в ней нечего пояснять. Можно также посмотреть результат, который вернет запрос. Если что-то не так - в нём будет ошибка и её описание. В противном случае запрос вернет свежедобавленный твит и информацию о нём. А в вашей ленте у свежедобавленного твита будет гордо красоваться в качестве клиента название вашего приложения, которое вы зарегистрировали.
В качестве бонуса прилагаю функцию для получение сокращённой ссылки. В данном случае используется сокращатель ссылок clck.ru от @bobuk
function curlGetShortLink( $url ){
$link = "http://clck.ru/--?url=" . $url;
$ci = curl_init();
curl_setopt( $ci, CURLOPT_URL, $link );
curl_setopt( $ci, CURLOPT_RETURNTRANSFER, true );
while ( true ) {
$returned = curl_exec( $ci );
$status = curl_getinfo( $ci, CURLINFO_HTTP_CODE );
# если сервис недоступен или превышен лимит:
if ( $status == "200" ) {
break;
}
sleep( 2 );
}
return $returned;
}
На этих функциях работают пока 4 бота, которые успешно справляются со своей задачей уже несколько месяцев. Если интересно - @funkysouls и @rutracker_ios, которые парсят rss и постят в Twitter, ну и ещё пара наших ботов по работе.
Спасибо @stay_positive за своевременную помощь, плюс часть кода тут его. Ах да