Logo classes.scriptsphp.org PHP

go to nav bar

Construire un bot IRC

Date :: 2004-10-19
Last Updated :: 2004-11-04

Introduction

Dans cet article, qui sort un peu du cadre d'utilisation habituelle de PHP (générer des pages pour le web), nous allons voir comment faire communiquer PHP et un serveur IRC grâce aux sockets. Pour se faire, nous allons créer un bot (robot, c'est à dire un programme fonctionnant de façon autonome) doté de fonctionnalités minimales telles que la connexion, la reconnexion et le CTCP, ainsi qu'un sytème de plugin qui vous permettra d'étendre facilement ces dernières. Comme démonstration, nous y ajouterons quelques plugins plus ou moins utiles, je vous laisse en juger ...
Le bot est codé en PHP5 et s'utilise uniquement en ligne de commande (PHP en mode CLI).
Cet article n'entrera pas dans les détails du protocole IRC, je vous invite néanmoins à le lire pour une meilleure compréhension générale.

Principe de fonctionnement

Connexion au serveur IRC

Le script se connectera au serveur IRC grâce à une socket (qu'est-ce qu'une socket, les sockets en PHP). Il vous faudra connaître l'adresse de ce serveur ainsi que le port de communication qu'il utilise et voir la fonction fsockopen().

<?php
$LaSocket 
fsockopen'irc.truc.net' 6667 );
?>

Une fois la socket de connexion établie, un dialogue s'instaure entre le script et le serveur. Nous lui envoyons une commande (via la fonction fput()) et il nous répond (récupération via la fonction fget()).

S'identifier auprès du serveur IRC

Une fois connecté au serveur IRC, il nous faut nous identifier et choisir un nickname (pseudonyme). Cela se fait en envoyant certaines commandes spécifiques :

  • USER : votre nom d'utilisateur,
  • NICK : Votre pseudonyme sur le serveur.
<?php
fputs
$LaSocket 'USER moi moi@169.80.81.12 scriptsphp.org :monBOT' );
fputs$LaSocket 'NICK monBOT' );
?>

Bien sûr, entre chaque envoi de commande, il nous faut attendre la réponse du serveur IRC et agir en conséquence. Votre nom d'utilisateur ou votre pseudonyme peuvent être déjà pris par un autre utilisateur, contenir des caractères interdits, etc...

Rejoindre un canal de discussion

Une fois toutes les étapes précédentes passées avec succès, il nous reste à rejoindre un canal de discussion. Ceci se fait grâce à la commande JOIN :

<?php
fputs
$LaSocket 'JOIN #lecanal' );

?>

Le ping pong

La dernière étape essentielle consiste à répondre au serveur, qui vérifie pérodiquement que vous êtes encore connecté, en vous envoyant un signal de test. Cela s'appelle le ping/pong :). Le serveur vous envoie un ping auquel vous devez répondre par le pong adéquat.

<?php
// admettons que le serveur vous ait envoyé un : PING blabla
fputs$LaSocket 'PONG blabla' );
?>

Description des classes utilisées

Le bot se compose de deux classes principales, d'un plugin de base et d'une interface indispensable à son fonctionnement :

  • La classe IRCMain : le coeur du bot. C'est la classe de plus haut niveau qui contient la boucle infinie faisant tourner le bot, ainsi que les méthodes de chargement et de déchargement des plugins,
  • La classe IRCConn : cette classe gère la connexion au serveur IRC, et en assure l'unicité, grâce à un Singleton,
  • L'interface plugin : Une interface que tous les plugins devront implémenter,
  • Le plugin plug_base : cette classe est un plugin indispensable qui permet d'assurer les fonctionnalités de base IRC. Elle gère notamment le ping/pong, les déconnexions, les CTCP, le nickname, ...

Le bot dispose également de différents plugins optionnels (nous en créerons deux à titre d'exemple), qui permettent de lui rajouter des fonctionnalités.

La classe principale : IRCMain

La classe IRCMain est la seule que vous devez utiliser directement dans vos scripts. Elle se compose des méthodes membres publiques suivantes :

  • __construct() : constructeur de la classe. Il prend six paramètres comme arguments : le serveur auquel se connecter, le port de ce serveur, le salon de discussion (channel) à rejoindre, le nom du bot , son IP et son domaine,
  • run() : cette méthode lance le bot,
  • AddPlug() : cette méthode charge un plugin,
  • UnloadPlug() : cette méthode décharge un plugin (non utilisée dans cette article).
<?php

class IRCMain {

    public 
$MyConn;
    public 
$Plist = array();
    public 
$msg;

    
// Constructeur  de la classe
    
public function __construct($server$port$channel$name$myip$mydomain) {
        
// Récupération d'une connexion unique
        
IRCConn::Init($server$port$channel$name$myip$mydomain);
        
$this->MyConn IRCConn::GetInstance();
        
// On charge le plugin de base indispensable
        
$this->AddPlug('plug_base');
    }

    public function 
run() {
        while (
true) {
            
$this->msg $this->MyConn->get();
            foreach (
$this->Plist as $Plug) {
                
$Plug->start($this->msg);
            }
        }
    }

    public function 
AddPlug($Pname) {
        if ( !
array_key_exists $Pname$this->Plist ) ) {
            
$this->Plist[$Pname] = new $Pname($this);
        }
    }

    public function 
UnloadPlug($Pname) {
        if ( 
array_key_exists $Pname$this->Plist ) ) {
            unset( 
$this->Plist[$Pname] );
        }
    }

}

?>

La classe IRCConn

Cette classe gère la connexion au serveur IRC et en assure l'unicité afin d'éviter d'avoir plusieurs connexion simultanées. L'unicité de cette connexion est assurée par l'implémentation d'un Singleton que PHP5 nous permet de réaliser simplement, grâce à ses nouvelles fonctionnalités objet. Vous pouvez régler le temps maximum, après lequel le bot se considère comme déconnecté, via la variable membre publique socketTimeout, reglée à 280 secondes par défaut. Passé ce délai, le bot sera tué. Vous trouverez plus loin dans l'article, un script shell lui permettant de se reconnecter automatiquement.

<?PHP

Class IRCConn {

    
// Timeout avant une reconnexion
    
public $socketTimeout 280;

    
// Variables privées
    
static public $instance FALSE;
    protected 
$C;
    static 
$botVersion 0.2;
    static 
$server;
    static 
$port;
    static 
$channel;
    static 
$myBotName;
    static 
$ip;
    static 
$domain;


    private function 
__construct() {
        
$this->connect(self::$serverself::$port);
    }

    static function 
Init($server$port$channel$myBotName='XboT'$ip='127.0.0.1'$domain='scriptsphp.org') {
        
self::$server $server;
        
self::$port $port;
        
self::$channel $channel;
        
self::$myBotName preg_replace('`[^_[:alnum:]\`\\\\[\]^-]`'''$myBotName);
        
self::$ip $ip;
        
self::$domain $domain;
    }

    static function 
GetInstance() {
        if(!
IRCConn::$instance) { 
            
IRCConn::$instance = new IRCConn(); 
        }
        return 
IRCConn::$instance;
    }


    public function 
__destruct() {
        if(
is_resource($this->C)) {
            @
fclose($this->C);
        }
    }

    protected function 
connect() {
        
$this->= @fsockopen(self::$serverself::$port$errno$errstr10);
        if(!
$this->C) {
            die(
'Impossible de se connecter au server IRC !'."\n");
        }
        
// User
        
$this->put('USER '.self::$myBotName.' '.self::$myBotName.'@'.self::$ip.' '.self::$domain.' :XBOT');
        
// Nick
        
$this->put('NICK  '.self::$myBotName);
    }

    public function 
joinChannel($channel) {
        
$this->put('JOIN '.$channel);
    }

    public function 
newNick() {
        
self::$myBotName .= '_';
    }

    public function 
put($command) {
        
#    echo '[-> ' . $command . "\n";
        
fputs($this->C$command "\n");
    }

    public function 
get() {
        
// Stream Timeout
        
stream_set_timeout($this->C$this->socketTimeout);
        
$tmp1 time();
        
$content fgets($this->C1024);
        
#echo "<-]$content\n";
        
if($content != ''){
            return 
$content;
        }
        
// TIMEOUT
        
if(time()-$tmp1 >= $this->socketTimeout) {
            die(
'TIMEOUT'."\n");
        }
    }

}

?>

L'interface des plugins

Tous les plugins doivent implémenter cette interface. Ceci est valable aussi bien pour le plugin de base (plug_base) que pour les plugins optionnels de l'article (ainsi que pour ceux que vous créerez ultérieurement).
Le fait que tous les plugins implémentent cette interface assure l'uniformité de leur utilisation, et permet donc d'étendre très facilement les fonctionnalités du bot.
Cette interface oblige tous les plugins à implémenter au moins trois méthodes minimales :

  • __construct() : constructeur du plugin,
  • start() : cette méthode est appellée pour chaque plugin, avec en paramètre le texte renvoyé par le serveur IRC. Elle vous permet donc de parser les messages du serveur, et ainsi faire faire au bot les actions que vous souhaitez,
  • help() : cette méthode construit l'aide pour chaque plugin.
<?php 

interface plugin {

    
    public function 
__construct($main);
    public function 
start($IRCtxt);    
    public function 
help();
    
}

?>

La classe plug_base

Le plugin de base contient un certain nombre de commandes plus ou moins essentielles pour dialoguer avec le serveur IRC. Comme tous les autres plugins, il contient les méthodes start() et help() declarées dans l'interface plugin. Pour comprendre la finalité de ces méthodes vous devez avoir assimilé le protocole IRC, en voici la description :

  • start() : méthode de l'interface. Elle prend en paramètre le texte renvoyé par le serveur IRC,
  • help() : méthode de l'interface. Elle ne renvoie aucune aide pour ce plugin,
  • doHelp() : cette méthode renvoie l'aide definie dans chaque plugin par la méthode help(),
  • Ok() : méthode privée qui permet de joindre un salon de discussion lorsque le serveur IRC donne son accord,
  • Deco() : méthode privée qui permet de détecter une déconnexion due au serveur IRC,
  • Pong() : méthode privée qui répond au ping du serveur par un pong,
  • Kick() : méthode privée qui permet de détecter si le bot a été kické et donc de se reconnecter le cas échéant,
  • IllegalChNick() : méthode privée qui permet de détecter si un caractère illégal est présent dans le nick du bot,
  • NickUsed() : méthode privée qui permet de détecter si le nick du bot est déjà utilisé sur le serveur,
  • CTCP() : méthode privée qui renvoie une réponse à des requètes CTCP.
<?php
class plug_base implements plugin {

    private 
$main;

    public function 
__construct($main) {
        
$this->main $main;
    }

    public function 
start($IRCtext) {
        
$this->Deco($IRCtext);
        
$this->Ok($IRCtext);
        
$this->Pong($IRCtext);
        
$this->kick($IRCtext);
        
$this->NickUsed($IRCtext);
        
$this->IllegalChNick($IRCtext);
        
$this->CTCP($IRCtext);
        
$this->doHelp($IRCtext);
    }

    public function 
help() {
    }

    private function 
doHelp($IRCtxt) {
        if(
preg_match('`^:(.*?)!.*?@.*? PRIVMSG '.preg_quote(IRCConn::$channel'`').'(.*?)(!help)`'$IRCtxt$T)) {
            
$msg  '!help : cette aide'."\n";
            
$this->main->MyConn->put('NOTICE '.$T[1].' '.$msg);
            foreach(
$this->main->Plist as $key => $val) {
                
$msg $this->main->Plist[$key]->help();
                if(
is_array($msg)) {
                    foreach(
$msg as $m) {
                        
$this->main->MyConn->put('NOTICE '.$T[1].' '.$m);
                    }
                } else {
                    
$this->main->MyConn->put('NOTICE '.$T[1].' '.$msg);
                }
            }
        }
    }
    
    
// DECO
    
private function Deco($IRCtext) {
        if(
preg_match("`^ERROR :(Closing Link: )?(.*)\r?$`i"$IRCtext)) {
            @
fclose($this->main->MyConn->C);
            
sleep(3);
            die(
'Closing Link'."\n");
        }
    }

    
// OK
    
private function Ok($IRCtext) {
        if(
preg_match("`^:[^ ]+ 001 .*?\r?\n`"$IRCtext)) {
            
$this->main->MyConn->joinChannel(IRCConn::$channel);
        }
    }

    
// PONG
    
private function Pong($IRCtext) {
        if(
preg_match("`^PING :(.*)\r?\n`"$IRCtext$T)) {
            
$this->main->MyConn->put('PONG '.$T[1]);
        }
    }

    
// KICK
    
private function kick($IRCtext) {
        if(
preg_match('`^:(.*?)!.*?@.*? KICK '.IRCConn::$channel.' ([^ ]+)`'$IRCtext$T)) {
            if(
$T[2] == IRCConn::$myBotName) {
                
sleep(1);
                
$this->main->MyConn->joinChannel(IRCConn::$channel);
                
$this->main->MyConn->put('PRIVMSG '.IRCConn::$channel.' :Merci '.$T[1].' !');
            }
        }
    }

    
// Illegals characters in Nickname
    
private function IllegalChNick ($IRCtext) {
        if(
preg_match('`^:[^ ]+ 432 (.*?)\r?\n`'$IRCtext)){
            
IRCConn::$myBotName 'XboT';
            
$this->main->MyConn->put('NICK :'.IRCConn::$myBotName);
        }
    }

    
// Nick already in use
    
private function NickUsed($IRCtext) {
        if(
preg_match('`^:[^ ]+ 433 (.*?)\r?\n`'$IRCtext)){
            
$this->main->MyConn->newNick();
            
$this->main->MyConn->put('NICK :'.IRCConn::$myBotName);
        }
    }

    
// CTCP
    
private function CTCP($IRCtext) {
        if(
preg_match('`^:(.*?)!.*?@.*? PRIVMSG '.preg_quote(IRCConn::$myBotName'`').'(.*?)(VERSION|USERINFO|CLIENTINFO)`'$IRCtext$T)) {
            
$this->main->MyConn->put('NOTICE '.$T[1].' XboT version '.IRCConn::$botVersion.' - PHP  '.phpversion().' -- par CSP ( http://classes.scriptsphp.fr/ )');
        }
        if(
preg_match('`^:(.*?)!.*?@.*? PRIVMSG '.preg_quote(IRCConn::$myBotName'`').'(.*?)PING (.*?)\r?\n`'$IRCtext$T)) {
            
$this->main->MyConn->put('NOTICE '.$T[1]." PING\1".time()."\1");
        }
        if(
preg_match('`^:(.*?)!.*?@.*? PRIVMSG '.preg_quote(IRCConn::$myBotName,'`').'(.*?)(TIME)`'$IRCtext$T)) {
            
$this->main->MyConn->put('NOTICE '.$T[1].' '.date('Y-m-d H:i:s'));
        }
    }
}
?>

Ajoutons quelques plugins

Dans cette section, nous allons ajouter deux plugins au bot, et ainsi étendre ses fonctionnalités, assez minimes pour l'instant.

  • un plugin de recherche sur php.net,
  • un petit jeu du pendu.

Pour se faire, nous allons créer deux classes qui implémenteront l'interface plugin.

Un plugin de recherche sur PHP.net

Ce plugin va permettre aux utilisateurs du salon de discussion d'interroger le bot, en lui envoyant une commande spécifique, pour qu'il leur renvoie l'URL correspondante à leur recherche sur php.net.
Pour les fonctions PHP, le bot utilise un fichier XML récapitulatif des fonctions. Nous avons volontairement rendu ce fichier optionnel pour cet article. Si vous le souhaitez, vous trouverez une version plus à jour de ce fichier sur le CVS de php.net.
Les méthodes et variables membre :

  • plug_help::XMLFunctionsList : cette variable membre contient l'URL vers le fichier XML récapitulatif des fonctions PHP,
  • plug_help::__construct($main) : constructeur de la classe, il attend en unique paramètre l'instance unique de connexion au serveur IRC. Il charge également le fichier XML et construit un tableau à partir des résultats (utilisation de l'extension simpleXML),
  • plug_help::start($IRCtext) : comme pour chaque plugin, cette méthode reçoit en paramètre le texte du serveur IRC, et permet donc de le parser,
  • plug_help::help() : méthode renvoyant l'aide pour ce plugin, lorsque un utilisateur du salon de discussion en fait la demande, via la commande !help,
  • plug_help::PHPDoc() : cette méthode parse le texte du serveur IRC et renvoie l'URL vers la documentation sur php.net lorsque il croise la commande adéquate (!php ...),
  • plug_help::LoadPHPDoc() : cette méthode charge le fichier XML récapitulatif des fonctions en mémoire.
<?php 

class plug_help implements plugin {

    private 
$main;
    
// le fichier XML qui contient la liste des fonctions
    
private $XMLFunctionsList 'phpfunctions.xml';
    private 
$funcArray = array();

    public function 
__construct($main) {
        
$this->main $main;
        
$this->loadPHPDoc();
    }

    public function 
start($IRCtxt) {
        
$this->PHPDoc($IRCtxt);
    }
    
    public function 
help() {
        
$msg '!php fonction : recherche de la fonction sur php.net'."\n";
        return 
$msg;
    }

    
// Help PHP
    
private function PHPDoc($IRCtxt) {
        if(
preg_match('`!php +(\w+)( *)`i'$IRCtxt$T)) {
            
$T[1] = str_replace(array('::' '->''__'), array('-''-'''), $T[1]);
            if(
in_array($T[1], $this->funcArray)) {
                
$this->main->MyConn->put('PRIVMSG '.IRCConn::$channel.'  http://php.net/'.$T[1]);
            } else {
                
$this->main->MyConn->put('PRIVMSG '.IRCConn::$channel.'  http://php.net/'.$T[1].' (?)');
            }
        }
    }

    private function 
loadPHPDoc() {
        if(
$FL= @simplexml_load_file($this->XMLFunctionsList)) {
            foreach(
$FL->index->indexdiv as $func) {
                foreach(
$func->indexentry as $function) {
                    
$this->funcArray[] = str_replace(array('::' '->''__'), array('-''-'''), (string)$function->primaryie->function);
                }
            }
        }
    }
}

?>

Exemple d'utilisation dans le salon de discussion :

!php str_replace
!php xml

Le bot vous renverra L'URL vers la documentation correspondante sur php.net.

Un jeu du pendu

Voilà un plugin pour s'amuser un peu, un petit jeu du pendu, que vous connaissez surement.
Dans l'exemple ci-dessous, le dictionnaire ne comporte qu'un seul mot : phpdebutant. Je vous laisse le soin d'en mettre d'autres, en vous basant par exemple sur un dictionnaire que vous stockerez dans une base de données.

<?php 

class plug_pendu implements plugin {

    private 
$main;
    private 
$game = array();

    public function 
__construct($main) {
        
$this->main $main;
    }

    public function 
start($IRCtxt) {
        
$this->pendu($IRCtxt);
    }
    
    public function 
help() {
        
$msg[] = '!pendu newword : Démarrer un nouveau pendu'."\n";
        
$msg[] = '!pendu try lettre ou mot : Essaye une lettre ou un mot'."\n";
        return 
$msg;
    }

    private function 
pendu($IRCtext) {
        
$replyto IRCConn::$channel;
        
$from '';
        if(
preg_match('`!pendu help`i'$IRCtext)) {
            
$this->penduHelp($from);
            return 
TRUE;
        }
        if(
preg_match('`!pendu newword`i'$IRCtext)) {
            
$this->newword($IRCtext,$replyto);
            return 
TRUE;
        }
        if(
preg_match('`!pendu try ([a-z]+)`i'$IRCtext$T)) {
            
$letter $T[1];
            
$this->tryletter($IRCtext,$replyto,$letter);
            return 
TRUE;
        }
        if(
preg_match('`!pendu display`i'$IRCtext)) {
            
$this->display($from,$replyto);
            return 
TRUE;
        }
    }
    
    function 
newword($from,$rt) {    
        
        
// le seul mot que contient ce jeu du pendu
        // ------------------------------
        
$newword "phpdebutant";
        
// ------------------------------
        
        
$fl $newword{0};
        
$ll $newword{strlen($newword)-1};
        
$mask preg_replace('`[^'.$fl.$ll.']`i''_'$newword);
        
$this->game[$rt] = array (     'word' => $newword,
                                        
'mask' => $mask,
                                        
'letters' =>$fl.$ll,
                                        
'try' => );
        
$msg sprintf('nouveau jeu: %s',$this->game[$rt]['mask'] );
        
$this->main->MyConn->put('PRIVMSG '.$rt.' '.$msg);
    }
    
    function 
tryletter($from$rt$letter) {
        if (!isset(
$this->game[$rt])) return FALSE;
        if (
strlen($letter)>1) {
            if (
0==strcasecmp$this->game[$rt]['word'],$letter)) {
                
$msg sprintf('GAGNE %s : erreur(s) %s',$this->game[$rt]['word'],$this->game[$rt]['try']);
                unset(
$this->game[$rt]);
            } else {
                
$this->game[$rt]['try']++;
                
$msg sprintf('ERREUR %s : erreur(s) %s',$this->game[$rt]['mask'],$this->game[$rt]['try']);
            }
        } else {
            if (
strpos($this->game[$rt]['letters'],$letter) !== FALSE ) return FALSE;
            
$this->game[$rt]['letters'] .= $letter;
            
$oldmask $this->game[$rt]['mask'];
            
$this->game[$rt]['mask'] = preg_replace('`[^'.$this->game[$rt]['letters'].']`i','_'$this->game[$rt]['word']);
            if ( 
$this->game[$rt]['mask'] == $oldmask $this->game[$rt]['try']++;
            if (
$this->game[$rt]['mask']===$this->game[$rt]['word']) {
                
$msg sprintf('GAGNE %s : erreur(s) %s',$this->game[$rt]['mask'],$this->game[$rt]['try']);
                unset(
$this->game[$rt]);
            } else {
                
$msg sprintf(' %s : erreur(s) %s',$this->game[$rt]['mask'],$this->game[$rt]['try']);
            }
        }
        
$this->main->MyConn->put('PRIVMSG '.$rt.' '.$msg);
    }
    
    function 
display($from$rt) {
        if(!isset(
$this->game[$rt])) {
            return 
FALSE;
        }
        if (
$this->game[$rt]['mask']===$this->game[$rt]['word']) {
            
$msg sprintf('FINI %s : essai %s',$this->game[$rt]['mask'],$this->game[$rt]['try']);
        } else {
            
$msg sprintf(' %s : erreur(1) %s',$this->game[$rt]['mask'],$this->game[$rt]['try']);
        }
        
$this->main->MyConn->put('PRIVMSG '.$rt.' '.$msg);
    }
}

?>

Utilisation

A ce stade, vous devez disposez d'un certain nombre de fichiers. Il est important que le nom de chaque fichier contienne le nom de la classe, en tenant compte de la casse et que le nommage soit uniforme afin de pouvoir utiliser le mécanisme de chargement automatique des classes : la fonction __autoload().
Voici la liste des fichiers que vous devez posseder :

  • IRCMain.php
  • IRCConn.php
  • plugin.php
  • plug_base.php
  • plug_help.php
  • phpfunctions.xml (optionnel)
  • plug_pendu.php

Comme indiqué précédemment, ce bot s'utilise uniquement en ligne de commande, il n'a aucune raison d'être sur un serveur web. Le script suivant, utilisation.php, attend quatre arguments :

  • $server : le serveur IRC auquel se connecter,
  • $port : le port de ce serveur IRC,
  • $channel : le salon de discussion à rejoindre,
  • $name : le nom de votre robot.

Voici, par exemple, comment le lancer depuis une console :

$ php -f utilisation.php irc.chat.net 6667 salon MonRobot

Voici le contenu du fichier utilisation.php :

<?php 

// Mécanisme de chargement automatique des classes selon leur nom
function __autoload($class) {
    if(
is_readable($class.'.php')) {
        require_once 
$class.'.php';
    }
}

// Arguments passés à la ligne de commande
if(isset($argv[1], $argv[2], $argv[3], $argv[4])) {
    
$server $argv[1];
    
$port = (int)$argv[2];
    
$chan '#'.$argv[3];
    
$name $argv[4];
} else {
    die(
'Ce script attend 4 parametres !!');
}


// Nouvelle instance de la classe IRCMain
$MainProc = new IRCMain($server$port$chan$name'80.170.128.89','xxx.com');

// On charge les plugins que l'on souhaite
// il n'est pas nécéssaire de charger le plugin de base, plug_base
$MainProc -> AddPlug('plug_help');
$MainProc -> AddPlug('plug_pendu');

// On lance le bot
$MainProc -> run();

?>

Problèmes et solutions

Il se peut, pour une raison ou une autre, que le bot s'arrête, notamment pour cause d'indisponibilité du serveur IRC. Dans ce cas, le bot est tué (fonction die() de PHP), il lui faut donc un moyen autonome pour tenter de se reconnecter au serveur. A cet effet, il est possible d'utiliser un script shell, que nous nommerons bot.sh, qui permet de faire tourner le script PHP en boucle, en voici un exemple :

#!/bin/sh

echo -n "Entrez le serveur : "
read server
echo -n "Entrez le port : "
read port
echo -n "Entrez le canal à rejoindre : "
read channel
echo -n "Entrez le nom du bot : "
read name

# boucle infinie qui relance le script si il est tué
while [ 1 ] ; do
    php -f utilisation.php $server $port $channel $name
done

Utilisation, dans une console, lancez simplement et laissez vous guider :

$ sh bot.sh

Mise en garde

N'utilisez-pas ce bot sur un hébergement mutualisé, au mieux il ne marcherait simplement pas, au pire vous seriez renvoyé par votre hébergeur. Ce bot doit tourner grâce à PHP en ligne de commande, afin qu'il tourne comme un daemon.

Testez votre bot

Il est assez mal vu de tester votre bot sur des canaux IRC déjà existants. A cet effet, vous pouvez vous servir d'un canal spécialement dédié :

  • Hôte : irc.planespells.net,
  • Port : 6670,
  • Canal : #csp.

Vous remarquerez sur ce canal, qu'une évolution de ce bot tourne, vous pourrez ainsi voir les possibilités d'extension, avec les nombreux modules que nous lui avons ajouté.

Conclusion

Malgré sa relative compléxité de prime abord, cet article montre un large éventail des possibilités de PHP. Pour construire ce bot, nous avons notamment utilisé massivement la POO et les nouvelles fonctionnalités objet apportées par PHP5, les expressions régulières pour parser les messages du serveur IRC, les sockets pour communiquer avec le serveur IRC, l'extension simpleXML pour le chargement et la lecture des fonctions PHP, ...
Grâce au système de plugin, vous pouvez aisément étendre les fonctionnalités du bot.

Liens utiles

Fabrice Lezoray < fabrice AT scriptsphp.org >, Tetsuo Shima < tetsuo AT scriptsphp.org >. Merci à Microtom pour la relecture et les tests.

Trackback

Il n'y a pas de trackback recensé pour cet article.

Faire un trackback sur cet article http://classes.scriptsphp.org/Trackbackserver.Un-bot-IRC, récupérer les trackback sur cet article

Merci de ne pas suivre ce lien emails.

0.1837s | «»
PHP powered