In the last few months i figured out that a lot of people out there, have huge problems when it comes to code an IRC bot non-blocking.
In fact… the solution is pretty simple:
$socket = fsockopen( $server, $port);
stream_set_blocking( $socket , 0 );
php.net/manual/en/function.stream-set-blocking.php
Here is a example of a simple bot class:
IrcBotTemplate Class (948.0 B)
Without an nonblocking stream our bot would freeze as long there is no response from the server. All the timebased stuff happens in the time_things() method:
An instance of this class would look something like this:
#!/usr/bin/php -q
require_once(IrcBotTemplate.php);
$bot = new IrcBotTemplate('www.example.com','nickname','#channel');
And the whole class for download muffles:
/*
* IrcBotTemplate
* autor: Markus Ritberger
* email: contact@ritberger.at
* date: 16.11.2011
* desription:
* IrcBotTemplate is a exampleclass of a small
* non-blocking php-cli IRC-bot
*
*/
class IrcBotTemplate{
private $server = NULL;
private $port = NULL;
private $nick = NULL;
private $user = NULL;
private $channel = NULL;
private $start = NULL;
private $last_action = NULL;
private $socket = NULL;
private $alive = FALSE;
private $line_limit = 8192;
private $time_format = 'H:i:s';
public function __construct($server,$nick,$channel,$port='6667',
$user='username hostname servername realname') {
$this->server = $server;
$this->nick = $nick;
$this->channel = $channel;
$this->port = $port;
$this->user = $user;
$this->start = time();
$this->last_action = $this->start;
$this->connect();
sleep(1);
$this->set_user($this->user);
sleep(1);
$this->set_nick($this->nick);
sleep(1);
$this->join($channel);
$this->process();
}
private function connect(){
$this->socket = fsockopen($this->server, $this->port);
stream_set_blocking( $this->socket , 0 );
$this->alive = TRUE;
}
private function set_user($userline){
fputs($this->socket,"USER {$userline}".PHP_EOL);
}
private function set_nick($nick){
fputs($this->socket,"NICK {$nick}".PHP_EOL);
}
private function join($channel){
fputs($this->socket,"JOIN {$channel}".PHP_EOL);
}
private function process(){
while($this->alive) {
while($data = fread($this->socket,$this->line_limit)) {
$this->response($data);
}
$this->time_things();
}
}
private function response($data){
echo $data;
if(preg_match('~^PINGs*(.*)~', $data, $matches)){
$this->pong($matches[1]);
}
}
private function pong($ping){
fputs($this->socket,"PONG {$ping}".PHP_EOL);
}
/*
* put your time based code here.
* for example the current time every second
*/
private function time_things(){
if(time() > $this->last_action){
$this->last_action = time();
fputs($this->socket,"PRIVMSG {$this->channel} :"
.date($this->time_format,time()).PHP_EOL);
echo date($this->time_format,time()).PHP_EOL;
}
}
}