site/_site/tmp/var/www/chaospott.de/example-hooks/post_twitter.php
2014-10-26 19:35:05 +01:00

234 lines
9.0 KiB
PHP

<?php
// Create an "app" from the Twitter account you want to post to:
// https://dev.twitter.com/
//
// From your app's Details page, request an Access Token (bottom).
// Reload periodically until you have it.
// Paste in your values for these strings:
class TwitterPostHookCredentials
{
public static $consumer_key = '';
public static $consumer_secret = '';
public static $access_token = '';
public static $access_token_secret = '';
}
// Test your credentials by executing this file alone from the command line:
// php -f post_twitter.php
// Edit this function to customize the formatting of the posted tweets.
// The $post array is just like the $content['post'] arrays in the templates.
// You can even change the posted URL by overwriting $url_to_use.
//
// The string returned by this function will have a space and URL appended.
// $max_characters accounts for this, and is the most UTF-8 characters YOU can
// return from this function.
//
// The twitter_summarize($text, $max_characters) function is available. It
// will trim a string at the nearest word boundary and append an ellipsis to
// fit within the number of characters if it's too long.
//
function tweet_text_before_url_for_post(array $post, $max_characters, &$url_to_use)
{
$title = $post['post-title'];
if (isset($post['link'])) $title = "\xE2\x86\x92 " . $title; // right arrow
return twitter_summarize($title, $max_characters);
}
// ======== You probably don't want to edit anything below this line =========
class ExtremelyBasicSelfContainedOAuthConsumer
{
public $consumer_key;
public $consumer_secret;
public $token = '';
public $token_secret = '';
public $request_timeout_seconds = 10;
public static function hmac_sha1($data, $key)
{
if (strlen($key) > 64) $key = pack('H40', sha1($key));
if (strlen($key) < 64) $key = str_pad($key, 64, chr(0));
$ipad = (substr($key, 0, 64) ^ str_repeat(chr(0x36), 64));
$opad = (substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64));
return sha1($opad . pack('H40', sha1($ipad . $data)), true);
}
public function signature($request_method, $target_url, $post_params = array())
{
if ( ($qs = @parse_url($target_url, PHP_URL_QUERY)) ) {
parse_str($qs, $get_params);
$post_params = array_merge($get_params, $post_params);
}
if (isset($post_params['oauth_signature'])) unset($post_params['oauth_signature']);
ksort($post_params);
if (false !== ($cutpos = strpos($target_url, '?')) ) $target_url = substr($target_url, 0, $cutpos);
$parts = array($request_method, rawurlencode($target_url));
$vars = array();
foreach ($post_params as $name => $val) $vars[] = rawurlencode($name) . '=' . rawurlencode($val);
$parts[] = rawurlencode(implode('&', $vars));
$signature_base_string = implode('&', $parts);
return base64_encode(self::hmac_sha1($signature_base_string, $this->consumer_secret . '&' . ($this->token_secret ? $this->token_secret : '')));
}
public function request_parameters($request_method, $target_url, $post_params = array())
{
$params = array(
'oauth_consumer_key' => $this->consumer_key,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_nonce' => sha1($this->consumer_secret . microtime(true) . $this->token_secret),
'oauth_version' => '1.0'
);
if (strlen($this->token)) $params['oauth_token'] = $this->token;
$post_params = array_merge($post_params, $params);
$sig = $this->signature($request_method, $target_url, $post_params);
$params['oauth_signature'] = $sig;
return $params;
}
public function authorization_header_value($oauth_request_parameters)
{
$value = 'OAuth ';
foreach ($oauth_request_parameters as $key => $val) {
$value .= $key . '="' . rawurlencode($val) . '", ';
}
$value = rtrim($value, ', ');
return $value;
}
public function http_build_query_raw(array $arr)
{
$out = array();
foreach ($arr as $name => $val) $out[] = rawurlencode($name) . '=' . rawurlencode($val);
return implode('&', $out);
}
public function request($method, $endpoint, $params = array())
{
$oauth_parameters = $this->request_parameters($method, $endpoint, $params);
$auth = $this->authorization_header_value($oauth_parameters);
$curl = curl_init($endpoint);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $this->request_timeout_seconds);
curl_setopt($curl, CURLOPT_TIMEOUT, $this->request_timeout_seconds);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_FAILONERROR, 0);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: ' . $auth, 'Expect:'));
if ($method == 'POST') {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, self::http_build_query_raw($params));
}
$data = curl_exec($curl);
curl_close($curl);
return $data;
}
}
function twitter_summarize($text, $length, $ellipsis = "\xE2\x80\xA6" /* UTF-8 &hellip; */)
{
if ($length == 0) return $text;
if (mb_strlen($text, 'UTF-8') <= $length) return $text;
$word_delimiter = ' ';
$word_delimiter_mblen = 1;
$length -= mb_strlen($ellipsis, 'UTF-8');
$cut_str = mb_substr($text, 0, $length + $word_delimiter_mblen, 'UTF-8');
if (mb_substr($cut_str, 0 - $word_delimiter_mblen) != $word_delimiter) {
$cut_str = mb_substr($cut_str, 0, 0 - $word_delimiter_mblen);
}
$split_pos = $cut_str ? mb_strrpos($cut_str, $word_delimiter, 'UTF-8') : false;
if ($split_pos) {
return mb_substr($text, 0, $split_pos, 'UTF-8') . $ellipsis;
} else {
return $cut_str . $ellipsis;
}
}
function tweet_link_to_post(array $post_array_for_template)
{
$oauth = new ExtremelyBasicSelfContainedOAuthConsumer();
$oauth->consumer_key = TwitterPostHookCredentials::$consumer_key;
$oauth->consumer_secret = TwitterPostHookCredentials::$consumer_secret;
$oauth->token = TwitterPostHookCredentials::$access_token;
$oauth->token_secret = TwitterPostHookCredentials::$access_token_secret;
$short_url_length = 24; // Big, safe default (at time of writing, Twitter's value is actually 20)
try {
$config = json_decode($oauth->request('GET', 'http://api.twitter.com/1/help/configuration.json'), true);
if (isset($config['short_url_length'])) $short_url_length = intval($config['short_url_length']);
if ($short_url_length < 16) $short_url_length = 24; // sanity check
} catch (Exception $e) { }
$url_to_use = $post_array_for_template['post-absolute-permalink'];
$tweet_text = tweet_text_before_url_for_post(
$post_array_for_template,
140 - ($short_url_length + 1 /* the space before the URL */),
$url_to_use
);
$tweet_text .= ' ' . $url_to_use;
$response = $oauth->request(
'POST', 'https://api.twitter.com/1/statuses/update.json',
array('trim_user' => 'true', 'status' => $tweet_text)
);
$post = @json_decode($response, true);
if ($post && isset($post['id_str']) && isset($post['text'])) {
error_log("Posted to Twitter: [{$post['text']}]");
} else {
error_log("Posting to Twitter failed: $response");
}
}
$command_line_test_mode = isset($_SERVER['argv'][0]) && substr($_SERVER['argv'][0], -16) == 'post_twitter.php';
if ($command_line_test_mode) {
$oauth = new ExtremelyBasicSelfContainedOAuthConsumer();
$oauth->consumer_key = TwitterPostHookCredentials::$consumer_key;
$oauth->consumer_secret = TwitterPostHookCredentials::$consumer_secret;
$oauth->token = TwitterPostHookCredentials::$access_token;
$oauth->token_secret = TwitterPostHookCredentials::$access_token_secret;
$response = $oauth->request('GET', 'https://api.twitter.com/1/account/verify_credentials.json');
$user = @json_decode($response, true);
if ($user && isset($user['error'])) {
echo "\nTwitter returned an error: {$user['error']}\n\n";
exit(1);
} else if ($user && isset($user['name']) && isset($user['screen_name'])) {
echo "\nSuccessfully authenticated as @{$user['screen_name']} ({$user['name']})\n";
} else {
echo "\nGot unrecognized response from Twitter:\n$response\n\n";
exit(1);
}
if (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == 'post') {
tweet_link_to_post(array(
'post-title' => 'Test post title',
'post-absolute-permalink' => 'http://twitter.com/',
));
echo "\n";
} else {
echo "Re-run with argument 'post' to create a test post on Twitter.\n\n";
}
} else {
class Twitter extends Hook
{
public function doHook(Post $post)
{
tweet_link_to_post($post->array_for_template());
}
}
}