Arm1.ru

Отправка сообщений в Twitter через php

Давно хотел выложить свой простенький набор функций для отправки твитов в 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 этапов:

  1. Формирование текста твита (строка в 140 символов с текстом, возможно ссылкой).
  2. Формирование параметров запроса и подписи.
  3. Формирование заголовков запроса.
  4. Отправка запроса.

Сам набор состоит из 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 за своевременную помощь, плюс часть кода тут его. Ах да

отправка сообщений в twitter через php

keyboard_return back