Twitter IRC bots:
Twirc is a Twitter client written in PHP and using IRC (Freenode) to connect. Due to flooding policies, it actually serves only one client.
You can add this in your crontab:
*/2 * * * * [ `/usr/bin/pgrep -cfx "/usr/bin/php /SCRIPT_FILENAME"` -eq 0 ] && /usr/bin/php /SCRIPT_FILENAME
Just replace SCRIPT_FILENAME by the full path to the script...
Note that you'll have to create an app in your Twitter account: the app must have read and update permissions. No callback URL is needed, you must use the PIN method for authentification (mobile / desktop apps).
<?php
/*
Get the twitteroauth lib here : http://github.com/abraham/twitteroauth
To avoid bugs, I recommend to replace "return json_decode($response)" in methods "get", "post" and "delete" by :
return @json_decode(trim(preg_replace('#((id)|(cursor))":(\d+)#','\1":"\4"',$response)));
Also replace "$http_status" by "$http_code" in method "lastStatusCode()"
*/
require_once dirname(__FILE__) . '/OAuth.php';
require_once dirname(__FILE__) . '/twitteroauth.php';
class Twirc {
const DEBUG = false;
const NICK = 'CHOOSE_A_NICKNAME_FOR_YOUR_BOT';
const PASSWORD = ''; // Optionnal, set the nickserv password if needed
const TWITTER_INTERVAL = 60; // in seconds
const TWITTER_UNDO_DELAY = 60; // in seconds
const EXPAND_URLS = true;
// You need to register a new app here: https://twitter.com/apps/new
const CONSUMER_KEY = '';
const CONSUMER_SECRET = '';
const SHARED_SECRET = ''; // Optionnal, if set you'll have to enter this to connect
// OK, done ! No need to change anything else
protected $conn = null;
protected $backupFile = '';
protected $twitterStatus = false;
protected $twitterLastId = '';
protected $twitterLastChecked = 0;
protected $twitterLastUpdated = 0;
protected $twitterLastMentionId = '';
protected $twitterLastDM = '';
protected $twitterUndo = '';
protected $owner = '';
protected $ownerNick = '';
protected $ownerScreenName = '';
protected $token = null;
protected $oAuth = null;
protected $candidate = '';
function __construct() {
if (self::EXPAND_URLS) ini_set('user_agent','Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4');
$this->backupFile = sprintf('%s.data.inc',__FILE__);
$this->restore_data();
$this->run();
}
protected function output($msg,$forceOutput=false) {
if (self::DEBUG || $forceOutput) echo "$msg\n";
}
protected function restore_data() {
if (file_exists($this->backupFile)) {
list($this->twitterLastId,$this->twitterLastMentionId,$this->twitterLastDM,$this->ownerNick,$this->token,$this->ownerScreenName,$this->owner) = @unserialize(file_get_contents($this->backupFile));
if ($this->token) {
$this->oAuth = new TwitterOAuth(self::CONSUMER_KEY,self::CONSUMER_SECRET,$this->token['oauth_token'],$this->token['oauth_token_secret']);
}
}
}
protected function backup_data() {
file_put_contents($this->backupFile,serialize(array($this->twitterLastId,$this->twitterLastMentionId,$this->twitterLastDM,$this->ownerNick,$this->token,$this->ownerScreenName,$this->owner)));
}
protected function read() {
if ($this->conn) {
$line = trim(fgets($this->conn));
if ($line) $this->output($line);
else sleep(1);
return $line;
}
return false;
}
protected function write($cmd) {
if ($this->conn) {
$this->output($cmd);
fputs($this->conn,"$cmd\r\n");
}
}
protected function expand_urls($text) {
$text = html_entity_decode($text,ENT_QUOTES,'UTF-8');
if (self::EXPAND_URLS) {
return preg_replace_callback('#https?://[^ <>"()\'\[\]]+#si',create_function('$m','$url = $m[0]; $h = @array_reverse(get_headers($url)); if (@count($h)) foreach ($h as $header) if (preg_match("#^Location: (.*)$#si",$header,$matches)) { $url = trim($matches[1]); break; } return $url;'),$text);
}
return $text;
}
protected function twitter_update($text) {
if (!$this->ownerScreenName) return false;
$text = mb_check_encoding($text,'UTF-8') ? $text : utf8_encode($text);
$json = $this->oAuth->post('statuses/update',array('status'=>$text));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error updating status: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error updating status ($i)");
} elseif (!@$json->id) $this->write("PRIVMSG $this->ownerNick :Error sending status: Twitter API not responding...");
else {
$this->twitterUndo = $json->id;
$this->twitterLastUpdated = time();
}
}
protected function twitter_check() {
if ($this->twitterUndo && (time() - $this->twitterLastUpdated > self::TWITTER_UNDO_DELAY)) {
$this->twitterUndo = '';
}
if (!$this->ownerScreenName) return false;
if ($this->twitterStatus && (time() - $this->twitterLastChecked >= self::TWITTER_INTERVAL)) {
$this->twitterLastChecked = time();
$json = $this->oAuth->get('statuses/home_timeline',$this->twitterLastId ? array('since_id'=>$this->twitterLastId) : array());
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving timeline: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving timeline ($i)");
} else {
$json = array_reverse($json);
foreach ($json as $k=>$s) {
$this->twitterLastId = (string) $s->id;
$screenName = (string) $s->user->screen_name;
if ($screenName != $this->ownerScreenName) {
$text = $this->expand_urls((string) $s->text);
$this->write("PRIVMSG $this->ownerNick :<$screenName> $text");
sleep(1);
}
}
$this->backup_data();
}
}
}
protected function twitter_mentions() {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->get('statuses/mentions',$this->twitterLastMentionId ? array('since_id'=>$this->twitterLastMentionId) : array());
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving mentions: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving mentions ($i)");
} else {
$json = array_reverse($json);
foreach ($json as $k=>$s) {
$this->twitterLastMentionId = (string) $s->id;
$screenName = (string) $s->user->screen_name;
$text = $this->expand_urls((string) $s->text);
$this->write("PRIVMSG $this->ownerNick :[Mention] <$screenName> $text");
sleep(1);
}
$this->backup_data();
}
}
protected function twitter_dm($to=null,$text=null) {
if (!$this->ownerScreenName) return false;
if ($to && $text) {
$text = mb_check_encoding($text,'UTF-8') ? $text : utf8_encode($text);
$json = $this->oAuth->post('direct_messages/new',array('screen_name'=>$to,'text'=>$text));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error sending direct message: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error sending direct message ($i)");
} elseif (!@$json->id) $this->write("PRIVMSG $this->ownerNick :Error sending direct message: Twitter API not responding...");
} else {
$json = $this->oAuth->get('direct_messages',$this->twitterLastDM ? array('since_id'=>$this->twitterLastDM) : array());
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving direct messages: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving direct messages ($i)");
} else {
$json = array_reverse($json);
foreach ($json as $k=>$s) {
$this->twitterLastDM = (string) $s->id;
$screenName = (string) $s->sender->screen_name;
$text = $this->expand_urls((string) $s->text);
$this->write("PRIVMSG $this->ownerNick :[DM] <$screenName> $text");
sleep(1);
}
$this->backup_data();
}
}
}
protected function twitter_timeline($user) {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->get('statuses/user_timeline',array('screen_name'=>$user));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving user timeline: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving user timeline ($i)");
} else {
$json = array_reverse($json);
foreach ($json as $k=>$s) {
$screenName = (string) $s->user->screen_name;
$text = $this->expand_urls((string) $s->text);
$this->write("PRIVMSG $this->ownerNick :[User] <$screenName> $text");
sleep(1);
}
}
}
protected function twitter_info($user) {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->get('users/show',array('screen_name'=>$user));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving user info: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving user info ($i)");
} else {
$this->write(sprintf('PRIVMSG %s :%s (location: %s, followers: %s, followings: %s, statuses: %s, protected: %s, verified: %s, following: %s)',$this->ownerNick,(string)(string)$json->name,$json->location,(string)$json->followers_count,(string)$json->friends_count,(string)$json->statuses_count,$json->protected ? 'yes' : 'no',$json->verified ? 'yes' : 'no',$json->following ? 'yes' : 'no'));
$this->write(sprintf('PRIVMSG %s :Description: %s',$this->ownerNick,(string)$json->description));
$this->write(sprintf('PRIVMSG %s :Web site: %s',$this->ownerNick,(string)$json->url));
$this->write(sprintf('PRIVMSG %s :Profile image: %s',$this->ownerNick,preg_replace('#_normal(\.[a-z]+)$#si','\1',(string)$json->profile_image_url)));
$this->write(sprintf('PRIVMSG %s :Last status: %s',$this->ownerNick,$this->expand_urls((string)$json->status->text)));
}
}
protected function twitter_show($id) {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->get('statuses/show',array('id'=>$id));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving a status: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving a status ($i)");
} else {
$screenName = (string) $json->user->screen_name;
$text = $this->expand_urls((string) $json->text);
$this->write("PRIVMSG $this->ownerNick :[SHOW] <$screenName> $text");
sleep(1);
}
}
protected function twitter_follow($user) {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->post('friendships/create',array('screen_name'=>$user));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error following user: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error following user ($i)");
} elseif (!@$json->id) $this->write("PRIVMSG $this->ownerNick :Maybe an error following user (API not responding)");
}
protected function twitter_unfollow($user) {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->delete('friendships/destroy',array('screen_name'=>$user));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error unfollowing user: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error unfollowing user ($i)");
} elseif (!@$json->id) $this->write("PRIVMSG $this->ownerNick :Maybe an error unfollowing user (API not responding)");
}
protected function twitter_undo() {
if (!$this->twitterUndo) {
$this->write("PRIVMSG $this->ownerNick :No tweet to undo !");
} else {
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->delete('statuses/destroy',array('id'=>$this->twitterUndo));
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error deleting status: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error deleting status ($i)");
} elseif ($this->twitterUndo != @$json->id) $this->write("PRIVMSG $this->ownerNick :Maybe an error deleting status (API not responding)");
else {
$this->twitterUndo = '';
}
}
}
protected function twitter_status() {
$status = $this->twitterStatus ? 'running' : 'stopped';
$this->write("PRIVMSG $this->ownerNick :Service is $status");
if (!$this->ownerScreenName) return false;
$json = $this->oAuth->get('account/rate_limit_status');
$i = $this->oAuth->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error retrieving rate limit status: %s',$this->ownerNick,(string) $json->error));
else $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving rate limit status ($i)");
} elseif (!@$json) $this->write("PRIVMSG $this->ownerNick :Maybe an error retrieving rate limit status (API not responding)");
else {
$this->write("PRIVMSG $this->ownerNick :API Remaining Hits: $json->remaining_hits");
}
}
protected function twitter_search($q,$lang=null) {
if (!$this->ownerNick) return false;
$data = array('q'=>$q);
if ($lang) $data['lang'] = $lang;
if (!$response = @file_get_contents(sprintf('http://search.twitter.com/search.json?%s',http_build_query($data)))) {
$this->write("PRIVMSG $this->ownerNick :No response from Twitter Search API");
return false;
}
$json = @json_decode(trim(preg_replace('#((id)|(cursor))":(\d+)#','\1":"\4"',$response)));
if ($json->error) {
$this->write("PRIVMSG $this->ownerNick :$json->error");
return false;
}
if (@count($json->results)) {
$results = array_reverse($json->results);
foreach ($results as $s) {
$screenName = (string) $s->from_user;
$text = $this->expand_urls((string) $s->text);
$this->write("PRIVMSG $this->ownerNick :[SEARCH] <$screenName> $text");
sleep(1);
}
}
}
protected function run() {
if (!$this->conn = @fsockopen('irc.freenode.net','6667',$errno,$errstr,10)) {
$this->output($errmsg,true);
exit;
}
$this->write(sprintf('NICK %s',self::NICK));
$this->write(sprintf('USER %1$s localhost irc_server :%1$s',self::NICK));
if (self::PASSWORD) {
$this->write(sprintf('PRIVMSG nickserv :IDENTIFY %s %s',self::NICK,self::PASSWORD));
$this->write(sprintf('PRIVMSG nickserv :GHOST %s',self::NICK));
$this->write(sprintf('NICK %s',self::NICK));
}
if ($this->ownerNick) {
$this->write("PRIVMSG $this->ownerNick :I'm online !");
}
while ($this->conn) {
$line = $this->read();
if ($line === false) break;
if (strpos($line,'PING ') === 0) $this->write(str_replace('PING','PONG',$line));
elseif (preg_match('#^:([^!]+![^ ]+) PRIVMSG ([^ ]+) :(.*)$#s',$line,$m) && ($m[2] == self::NICK)) {
$from = $m[1];
$text = $m[3];
list($user,$mask) = explode('!',$from,2);
if (!$this->owner || ($from == $this->owner)) {
if (preg_match('#^!quit(.*)$#s',$text,$m) && (ltrim($m[1]) == self::SHARED_SECRET)) break;
elseif (preg_match('#^!connect(.*)$#s',$text,$m) && (ltrim($m[1]) == self::SHARED_SECRET)) {
$this->oAuth = new TwitterOAuth(self::CONSUMER_KEY,self::CONSUMER_SECRET);
$request_token = $this->oAuth->getRequestToken();
$url = $this->oAuth->getAuthorizeURL($request_token['oauth_token']);
$this->write("PRIVMSG $user :Please retrieve a PIN here : $url");
$this->write("PRIVMSG $user :Once you have the PIN code, type: !pin THE_PIN_CODE");
$this->candidate = $this->owner = $from;
$this->ownerNick = $user;
} elseif (($from == $this->candidate) && !$this->token && preg_match('#^!pin (.*)$#s',$text,$m)) {
$this->token = $this->oAuth->getAccessToken($m[1]);
$this->candidate = '';
if (self::DEBUG) print_r($this->token);
if (!@$this->token['screen_name']) {
$this->token = null;
$this->oAuth = null;
$this->write("PRIVMSG $user :Incorrect PIN code, please recall !connect to authentificate");
} else {
$this->ownerScreenName = $this->token['screen_name'];
$this->write(sprintf('PRIVMSG %s :Welcome %s !',$user,$this->ownerScreenName));
$this->backup_data();
}
} elseif ($this->candidate && !$this->token) {
$this->write("PRIVMSG $user :I'm still waiting for your PIN code !");
} elseif (!$this->candidate && !$this->token) {
$this->write("PRIVMSG $user :Type \"!connect [PASSWORD]\" to start");
} else {
if (strpos($text,'!') === 0) {
switch (substr($text,1)) {
case 'start':
$this->twitterStatus = true;
$this->twitter_check();
break;
case 'stop':
$this->twitterStatus = false;
break;
case 'status':
$this->twitter_status();
break;
case 'mentions':
case 'mention':
$this->twitter_mentions();
break;
case 'exit':
case 'bye':
case 'quit':
break 2;
case 'dm':
$this->twitter_dm();
break;
case 'undo':
$this->twitter_undo();
break;
default:
if (preg_match('#^!last ([a-z0-9_]+)$#si',$text,$m)) {
$this->twitter_timeline($m[1]);
} elseif (preg_match('#^!info ([a-z0-9_]+)$#si',$text,$m)) {
$this->twitter_info($m[1]);
} elseif (preg_match('#^!show ([0-9]+)$#si',$text,$m)) {
$this->twitter_show($m[1]);
} elseif (preg_match('#^!follow ([a-z0-9_]+)$#si',$text,$m)) {
$this->twitter_follow($m[1]);
} elseif (preg_match('#^!unfollow ([a-z0-9_]+)$#si',$text,$m)) {
$this->twitter_unfollow($m[1]);
} elseif (preg_match('#^!dm ([a-z0-9_]+) (.*)$#si',$text,$m)) {
$this->twitter_dm($m[1],$m[2]);
} elseif (preg_match('#^!search (.*)$#si',$text,$m)) {
$this->twitter_search($m[1]);
} elseif (preg_match('#^!search_([a-z]{2}) (.*)$#si',$text,$m)) {
$this->twitter_search($m[2],$m[1]);
} else {
$this->write("PRIVMSG $user :Basic commands are: !start | !stop | !status | !mentions | !quit | !dm[ USER MESSAGE] | !undo | !last USER | !info USER | !show STATUS_ID | !follow USER | !unfollow USER | !search QUERY | !search_xx QUERY (xx=lang code)");
}
}
}
else $this->twitter_update($text);
}
} else {
$this->write("PRIVMSG $user :Sorry, I don't know you");
}
} else $this->twitter_check();
}
if ($this->ownerNick) {
$this->write("PRIVMSG $this->ownerNick :I'm leaving !");
}
$this->write("QUIT");
@fclose($this->conn);
}
}
$X = new Twirc;
?>
TwittServ is a Twitter IRC bot written in PHP. Just help yourself to use it :)
<?php
/*
Get the twitteroauth lib here : http://github.com/abraham/twitteroauth
To avoid bugs, I recommend to replace "return json_decode($response)" in methods "get", "post" and "delete" by :
return @json_decode(trim(preg_replace('#((id)|(cursor))":(\d+)#','\1":"\4"',$response)));
Also replace "$http_status" by "$http_code" in method "lastStatusCode()"
*/
require_once dirname(__FILE__) . '/OAuth.php';
require_once dirname(__FILE__) . '/twitteroauth.php';
class TwittServ {
const DEBUG = false;
const NICK = 'CHOOSE_A_NICKNAME_FOR_YOUR_BOT';
const PASSWORD = ''; // Optionnal, set the nickserv password if needed
const VHOST =''; // Optionnal, format: VHOST = 'user:password', if set it will send a "/VHOST user password" on connection
const IRC_NETWORK = 'HOST:PORT'; // set your irc network here
// You need to register a new app here (read/update permissions and PIN method): https://twitter.com/apps/new
const CONSUMER_KEY = '';
const CONSUMER_SECRET = '';
const SHARED_SECRET = ''; // A secret password to run admin commands: !join CHANNEL SHARED_SECRET, !leave CHANNEL SHARED SECRET, !quit SHARED_SECRET
protected $conn = null;
protected $channels = array();
protected $clients = array();
protected $backupFile = '';
function __construct() {
$this->backupFile = sprintf('%s.data.inc',__FILE__);
$this->restore_data();
$this->run();
}
protected function output($msg,$forceOutput=false) {
if (self::DEBUG || $forceOutput) echo "$msg\n";
}
protected function restore_data() {
if (file_exists($this->backupFile)) {
list($this->channels,$this->clients) = @unserialize(file_get_contents($this->backupFile));
}
}
protected function backup_data() {
file_put_contents($this->backupFile,serialize(array($this->channels,$this->clients)));
}
protected function read() {
if ($this->conn) {
$line = trim(fgets($this->conn));
if ($line) $this->output($line);
else sleep(1);
return $line;
}
return false;
}
protected function write($cmd) {
if ($this->conn) {
$this->output($cmd);
fputs($this->conn,"$cmd\r\n");
}
}
protected function irc_join($channel) {
if (!$this->conn) return false;
$channel = strtolower($channel);
if (!array_key_exists($channel,$this->channels)) {
$this->channels[$channel] = true;
$this->backup_data();
$this->write("JOIN #$channel");
}
}
protected function irc_part($channel) {
if (!$this->conn) return false;
$channel = strtolower($channel);
if (array_key_exists($channel,$this->channels)) {
$c = $this->channels;
unset($c[$channel]);
$this->channels = $c;
$this->backup_data();
$this->write("PART #$channel");
}
}
protected function add_client($client,$text) {
list($nick,$mask) = explode('!',$client,2);
$this->clients[$client] = array('nick'=>$nick,'confirmed'=>false,'text'=>$text,'oAuth'=>new TwitterOAuth(self::CONSUMER_KEY,self::CONSUMER_SECRET));
$request_token = $this->clients[$client]['oAuth']->getRequestToken();
$url = $this->clients[$client]['oAuth']->getAuthorizeURL($request_token['oauth_token']);
$this->write("PRIVMSG $nick :Please retrieve a PIN here : $url");
$this->write(sprintf('PRIVMSG %s :Once you have the PIN code, type: /msg %s !pin THE_PIN_CODE',$nick,self::NICK));
$this->backup_data();
}
protected function confirm_client($client,$pin) {
if (!array_key_exists($client,$this->clients) || $this->clients[$client]['confirmed']) return false;
$token = $this->clients[$client]['oAuth']->getAccessToken($pin);
if (self::DEBUG) print_r($token);
if (!@$token['screen_name']) {
$this->write(sprintf('PRIVMSG %s :Incorrect PIN code',$this->clients[$client]['nick']));
return $this->remove_client($client);
} else {
$this->clients[$client]['confirmed'] = true;
$this->write(sprintf('PRIVMSG %s :Welcome %s, your message has been tweeted. Type "!tweet MESSAGE" to tweet, type "/msg %s !signout" to end twitter session',$this->clients[$client]['nick'],$token['screen_name'],self::NICK));
$this->tweet($client,$this->clients[$client]['text']);
$c = $this->clients[$client];
unset($c['text']);
$this->clients[$client] = $c;
$this->backup_data();
}
}
protected function remove_client($client) {
if (!array_key_exists($client,$this->clients)) return false;
$c = $this->clients;
unset($c[$client]);
$this->clients = $c;
$this->backup_data();
}
protected function tweet($client,$text) {
if (!array_key_exists($client,$this->clients) || !$this->clients[$client]['confirmed']) return false;
$text = mb_check_encoding($text,'UTF-8') ? $text : utf8_encode($text);
$json = $this->clients[$client]['oAuth']->post('statuses/update',array('status'=>$text));
$i = $this->clients[$client]['oAuth']->lastStatusCode();
if (self::DEBUG) {
print_r($json);
}
if ($i != 200) {
if (@$json->error) $this->write(sprintf('PRIVMSG %s :Error updating status: %s',$this->clients[$client]['nick'],(string) $json->error));
else $this->write(sprintf('PRIVMSG %s :Maybe an error updating status (%s)',$this->clients[$client]['nick'],$i));
} elseif (!@$json->id) $this->write(sprintf('PRIVMSG %s :Error sending status: Twitter API not responding...',$this->clients[$client]['nick']));
}
protected function run() {
list($ircServer,$ircPort) = explode(':',self::IRC_NETWORK,2);
if (!$this->conn = @fsockopen($ircServer,$ircPort,$errno,$errstr,10)) {
$this->output($errmsg,true);
exit;
}
$this->write(sprintf('NICK %s',self::NICK));
$this->write(sprintf('USER %1$s localhost irc_server :%1$s',self::NICK));
if (self::PASSWORD) {
$this->write(sprintf('PRIVMSG NickServ :IDENTIFY %s',self::PASSWORD));
$this->write(sprintf('PRIVMSG NickServ :GHOST %s',self::NICK));
$this->write(sprintf('NICK %s',self::NICK));
}
if (self::VHOST) {
list($vhostUser,$vhostPassword) = explode(':',self::VHOST,2);
$this->write(sprintf('VHOST %s %s',$vhostUser,$vhostPassword));
sleep(5);
}
if (count($this->channels)) {
foreach (array_keys($this->channels) as $channel) $this->write("JOIN #$channel");
}
while ($this->conn) {
$line = $this->read();
if ($line === false) break;
if (strpos($line,'PING ') === 0) $this->write(str_replace('PING','PONG',$line));
elseif (preg_match('#^:([^!]+![^ ]+) PRIVMSG ([^ ]+) :!tweet (.+)$#s',$line,$m)) {
$from = $m[1];
$text = $m[3];
if (!array_key_exists($from,$this->clients)) $this->add_client($from,$text);
elseif (@$this->clients[$from]['confirmed']) $this->tweet($from,$text);
}
elseif (preg_match('#^:([^!]+![^ ]+) PRIVMSG ([^ ]+) :(.*)$#s',$line,$m) && ($m[2] == self::NICK)) {
$from = $m[1];
$text = $m[3];
if (preg_match('#^!quit(.*)$#s',$text,$m) && (ltrim($m[1]) == self::SHARED_SECRET)) break;
elseif (preg_match('#^!join \#?([^ ]+)(.*)$#s',$text,$m) && (ltrim($m[2]) == self::SHARED_SECRET)) $this->irc_join($m[1]);
elseif (preg_match('#^!part \#?([^ ]+)(.*)$#s',$text,$m) && (ltrim($m[2]) == self::SHARED_SECRET)) $this->irc_part($m[1]);
elseif (preg_match('#^!pin ([0-9]+)$#s',$text,$m)) $this->confirm_client($from,$m[1]);
elseif (($text == '!signout') || ($text == '!logout')) $this->remove_client($from);
else {
list($nick,$mask) = explode('!',$from,2);
$this->write("PRIVMSG $nick :Type \"!tweet MESSAGE\" to tweet \"MESSAGE\" with your Twitter account");
}
}
}
$this->write("QUIT");
@fclose($this->conn);
}
}
$X = new Twittserv;
?>