login  Naam:   Wachtwoord: 
Registreer je!
 Tutorials

Tutorials > PHP


Gegevens:
Geschreven door:
Maarten
Moeilijkheidsgraad:
Normaal
Hits:
25384
Punten:
Aantal punten:
 (5)
Aantal stemmen:
6
Stem:
Niet ingelogd
Nota's:
 Lees de nota's (33)
 


Tutorial:

IRC-bot in PHP (Sockets)

Tegenwoordig duiken er overal IRC-bots op in allerhande programmeertalen, zelfs PHP. Als je reeds de basis van PHP onder knie hebt, en je kan datastromen van IRC-servers ontvangen, is het kinderspel om deze te gaan analyseren en zo je eigen bot te ontwikkelen, al dan niet gekoppeld aan een MySQL database.
1. Instellingen
Als je reeds rondhangt op IRC-kanalen dan weet je dat je jezelf moet identificeren, al dan niet met je echte gegevens. De bot moet dit ook doen.
In deze tutorial zullen we er vanuitgaan dat we op het Sitemasters-kanaal en een testkanaal willen met onze bot.
De bot die we hier zullen maken is zeer simpel. Hij zal slechts 1 nickname proberen aan te nemen. Als je een workaround wilt in geval van een bezette nickname, zul je hier zelf wat aan moeten sleutelen. Daar een IRC-bot niet voor PHP beginners is zal dit dus wel geen probleem vormen.
De instellingen die we zullen vastleggen zijn:
  • Nickname
  • Ware naam
  • Ident
  • Hostname
  • Server
  • Poort
  • Kanaal
De simpelste manier om dit te doen en je gegevens samen te houden is een configuratie-array.

<?php 
$config 
= array(); 
$config['nickname'] = 'AppelBot'
$config['realname'] = 'Appel plukker'
$config['ident']    = 'appel'
$config['hostname'] = 0
$config['server']   = 'irc.quakenet.org'
$config['poort']    = 6667
$config['kanaal']   = array('#sitemasters','#test');
?>


Je ziet dat we als hostname 0 geven. Normaal gezien moet je hier je eigen IP ingeven, maar dit is niet altijd evident als je een dynamisch IP hebt. In de meeste gevallen werkt 0. Als dit niet werkt, geef dan je netwerk-ip in als je in een netwerk zit, en je normaal IP als je pc rechtsreeks aan het internet hangt.
2. Connecteren
Nu wordt het intressant: de connectie met de IRC-server. Dit doen we aan de hand van sockets:

<?php 
if(!$socket socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) { 
    die(
'Fatale fout tijdens socket_create'); 
    
// Mochten hier fouten optreden, dat is dit meestal te wijten aan je server installatie 
    // Raadpleeg Google en php.net voor meer info 

 
if(!
socket_bind($socket,$config['hostname'])) { 
    die(
'Fatale fout tijdens binden van socket'); 
    
// Mochten hier fouten optreden, probeer dan je hostname te wijzigen in een IP-adres 
    // Als dit het probleem niet verhelpt, contacteer dan wederom Google en php.net 

 
if(!
socket_connect($socket,$config['server'],$config['poort'])) { 
    die(
'Fatale fout tijdens connecteren met server'); 
    
// In dit geval is er mogelijks een probleem met de server (bestaat niet, downtime,...) 

?>

Eens dit gelukt is zijn we verbonden met de IRC-server. Nu is het kwestie van data te gaan ontvangen en verzenden.
3. Data ontvangen en verzenden
Om een commando naar de IRC-server te versturen gebruiken we constant dezelfde socket. Om ons wat tijd en moeite te besparen kunnen we hiervoor een aantal functies gebruiken:
<?php 
// Schrijf data naar de socket 
function schrijf($data) { 
    global 
$socket
    
socket_write($socket,$data." "); 
}

// Zeg iets tegen een kanaal of persoon
function zeg($bericht,$ontvanger) {
    
schrijf('PRIVMSG '.$ontvanger.' :'.$bericht);
}
?>
Nu moet je eerst en vooral jezelf bekend maken aan de server. Dit doe je op volgende manier:

<?php
schrijf
('USER '.$config['ident'].' '.$config['hostname'].' '.$config['server'].' :'.$config['realname']);
schrijf('NICK '.$config['nickname']);
?>


De gebruikte commando's hebben in principe niks te maken met PHP maar met IRC en kan ik dus ook niet uitleggen. De commando's kan je afleiden door te kijken welke commando's een IRC-client verstuurd bij het verbinden, en dan behoren deze 2 commando's daartoe. Vandaar :)
Nu we verbonden zijn kunnen we beginnen. Een elementair feit aan een bot is dat hij niet disconnect. Dit kunnen we dus bekomen door een oneindige while-loop te gebruiken. Het spreekt vanzelf dat de bot niet gemaakt is om in een browservenster aangeroepen te worden, maar in een console:
  • Onder Windows kan dit zo: "C:Program filesxampphtdocsot.php" "C:Documents and settingsMurfyBureaubadot.php"
  • Onder Linux kan dit zo: php /home/murfy/bot.php
De oneindige while loop berust op het uitlezen van de connectie:

<?php 
$inKanaal 
false
while(
$data = @socket_read($socket,65000,PHP_NORMAL_READ)) { 
    if(
$data == " ") continue; 
     
    
// Als $inKanaal nog false is dienen we het kanaal nog binnen te gaan
    // We kunnen echter pas joinen als er MOTD in de datastream zit
    
if($inKanaal == false && strstr($data,'MOTD') { 
        for(
$i 0; isset($config['kanaal'][$i]); $i++) { 
            
schrijf('JOIN '.$config['kanaal'][$i]); 
            
zeg('Ik ben een Ã¼berbot!',$config['kanaal'][$i]); 
        } 
        
$inKanaal true
    } 
 
    
// De IRC-server zal regelmatig een PING sturen. Deze dien je dus met PONG te beantwoorden! 
    
$eData explode(' ',$data); 
    if(
$eData[0] == 'PING') { 
        
schrijf('PONG '.$eData[1]); 
    } 
 
    
// En hier doe je dan wat je wilt! :D 

?>


Om nu zelf functies voor je bot te gaan maken ga je als volgt te werk:
  • $data is een binnenkomende stream
  • $eData is diezelfde stream gesplitst met de spaties
Je kan dus BINNEN je while loop $data gaan wegschrijven in een bestand, altijd achteraan. Zo maak je een soort 'raw log', waar je de pure binnenkomende data ziet.
Zo kan je afleiden dat, wanneer iemand !google typt in een kanaal:
  • $eData[0] is de persoon die het zei
  • $eData[3] is gelijk aan ':!google'
  • $eData[4] en volgende is hetgeen achter !google kwam
Dus een Google-functie is snel gemaakt:
<?php 
if(isset($eData[3]) && $eData[3] == ':!google' && isset($eData[4])) {  
    
// Google command en minstens 1 trefwoord  
    // http://www.google.be/search?q=trefwoord  
    
$zoekstring    trim(array_pop(explode('!google',$data)));  
    
$u             'Google zoeken: http://www.google.be/search?q='.urlencode($zoekstring);
    
schrijf('NOTICE '.nickname($eData[0]).' : '.$u);
}  
?>


Je ziet dat ik gebruik maak van de functie nickname(). Ik heb deze nog nergens gedefiniëerd, maar wat de functie doet is simpel:

<?php
function nickname($str) {
    return 
substr(array_shift(explode('!',$str)),1);
}
?>


Dit is vereist omdat in $eData[0] niet de pure nickname zit, maar ook de hostname. Om een bericht te sturen met NOTICE of PRIVMSG, moet je de gewone nickname gebruiken, die je dus kan bekomen door nickname() over $eData[0] te gooien.
4. Voorbeeld werkende code
<?php
$config    
= array();
$config['nickname'] = 'MurfBot';
$config['realname'] = 'Murf The Bot';
$config['ident']    = 'murfbot';
$config['hostname'] = 0;
$config['server']   = 'irc.quakenet.org';
$config['poort']    = 6667;
$config['kanalen']  = array('#sitemasters');

if(!
$socket socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) {
    die(
'Fatale fout: socket kon niet worden aangemaakt.');
}
echo 
'Socket aangemaakt'." ";

if(!
socket_bind($socket,$config['hostname'])) {
    die(
'Fatale fout: verbinding kon niet worden gekoppeld aan hostname '.$config['hostname'].'.');
}
echo 
'Verbinding gekoppeld aan hostname'." ";

if(!
socket_connect($socket,$config['server'],$config['poort'])) {
    die(
'Fatale fout: verbinding met server kon niet tot stand worden gebracht.');
}
echo 
'Verbinden...'." ";

function 
schrijf($data) {
    global 
$socket;
    
socket_write($socket,$data." ");
}

schrijf('USER '.$config['ident'].' '.$config['hostname'].' '.$config['server'].' :'.$config['realname']);
schrijf('NICK '.$config['nickname']);

$inKanaal false;
while(
$data socket_read($socket,65000,PHP_NORMAL_READ)) {
    if(
$data == " ") continue;
    
    
$eData    explode(" ",$data);
    for(
$i 0; isset($eData[$i]); $i++) {
        
$eData[$i]    = trim($eData[$i]);
    }

    echo 
$data." ";

    if(
$inKanaal == false && strstr($data,'MOTD')) {
        
// Eerst kanalen binnengaan
        
for($i 0; isset($config['kanalen'][$i]); $i++) {
            
schrijf('JOIN '.$config['kanalen'][$i]);
        }
        
$inKanaal true;
    }
    
    if(
$eData[0] == 'PING') {
        
schrijf('PONG '.$eData[1]);
    }
}
?>

Nawoord
Ziezo, het is al weer een eindje geleden sinds mijn laatste tutorial, ik hoop dat jullie er iets aan hebben.
Mochten jullie een gelijkenis vinden met bestaande tutorials is dit goed mogelijk: er is slechts 1 manier om via sockets een connectie te maken met IRC, dus het spreekt vanzelf dat alle methodes die je zult vinden op het internet dezelfde zijn.
Deze tutorial mag enkel op Sitemasters gepubliceerd worden, indien je deze op je eigen website wenst te plaatsen, contacteer me dan.
Een score is altijd welkom, zolang je maar commentaar geeft.
Ik geef GEEN support op IRC, dus vraag me niet hoe je bepaalde interacties met gebruikers moet gaan doen, je kan heel veel afleiden uit $data (als je zelf op een kanaal gaat met je IRC-client (mIRC, xChat, Konversation,...) kan je interacties doen met je bot en dan analyseren hoe dit binnenkomt).
Veel succes en plezier!

« Vorige tutorial : Wees voorbereid op een php5 migratie Volgende tutorial : Zend Framework deel 2 »

© 2002-2024 Sitemasters.be - Regels - Laadtijd: 0.017s