IRC bot v PHP - 6. časť

Michal Pirchala  /  21. 12. 2010, 00:00

Ukladanie do súboru je vhodné pre ručné vyhľadávanie správ. Ale ak chceme aby nám bot vybral správy z určitého dňa, hodiny a podobne, vhodnejšie bude logy ukladať do databázy.

Pri výbere logov z databázy určíme podmienku, z akého času nám ich má databáza vybrať, názov kanála, prípadne aj meno užívateľa. Na vyjadrenie času použijeme unixový časový formát. Tento modul bude vedieť vypísať príchod, odchod,  poslednú správu alebo počet správ určitého užívateľa. V programovaní týchto funkcií máme 2 možnosti. Každú funkciu môžeme dať ako samostatný príkaz alebo dať všetko do skriptu modulu. Ak by sme použili druhú možnosť, skript modulu by sa o dosť zväčšil a keďže sa modul vykonáva pri každom cykle, tak by nám to zbytočne spomalilo vykonávanie každého cyklu. Preto bude vhodnejšie dať každú funkciu ako samostatný príkaz, ktorý sa spustí iba keď ho zavoláme.

Najprv si vytvoríme mysql tabuľku do ktorej budeme ukladať logy. Tabuľka bude mať päť stĺpcov (typ záznamu, čas, kanál, meno užívateľa a správu). Všetky stĺpce, okrem typu záznamu sú jasné. Typ záznamu budeme používať na rozlíšenie medzi obyčajnou správou, zmenou nicku a podobne. Budeme to využívať pri exportovaní správ z databázy.

CREATE TABLE `logs` (
`type` VARCHAR( 5 ) NOT NULL ,
`time` INT( 20 ) NOT NULL ,
`channel` VARCHAR( 30 ) NOT NULL ,
`nick` VARCHAR( 30 ) NOT NULL ,
`msg` VARCHAR( 500 ) NOT NULL
)

<?php
if (preg_match("/^:.* 353 $nick . (#.*) :(.*)$/", $msg, $matches)){
    $nick_list[$matches[1]] = "";
    $names = explode(" ", $matches[2]);
    foreach ($names as $name){
        if ($name[0]=="@" || $name[0]=="+") $nick_list[$matches[1]] .= (empty($nick_list[$matches[1]])) ? substr($name, 1) : ",".substr($name, 1);
        else $nick_list[$matches[1]] .= (empty($nick_list[$matches[1]])) ? $name : ",".$name;
    }
}

if (preg_match("/^:([^ ]*)!([^ ]*) (.*)$/", $msg, $matches)){
    $sender = $matches[1];
    $host = $matches[2];
    $irc_prikaz = $matches[3];
     
    if (preg_match("/^JOIN :(.*)$/", $irc_prikaz, $matches)){
        mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('JOIN', '".time()."', '".mysql_real_escape_string($matches[1])."', '".mysql_real_escape_string($sender)."', ".mysql_real_escape_string($sender).")");
        Send("NAMES {$matches[1]}");
    }
     
    if (preg_match("/^PART (.*)$/", $irc_prikaz, $matches)){
        mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('PART', '".time()."', '".mysql_real_escape_string($matches[1])."', '".mysql_real_escape_string($sender)."', '".mysql_real_escape_string()."')");
        Send("NAMES {$matches[1]}");
    }
     
    if (preg_match("/^PRIVMSG ([^ ]*) :(.*)$/", $irc_prikaz, $matches)){
        if ($matches[1][0]!="#") $matches[1] = $sender;
        if (preg_match("/^#ACTION (.*)#$/", $matches[2], $matches_)) mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('ME', '".time()."', '".mysql_real_escape_string($matches[1])."', '".mysql_real_escape_string($sender)."', '".mysql_real_escape_string($matches_[1])."')");
        else mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('MSG', '".time()."', '".mysql_real_escape_string($matches[1])."', '".mysql_real_escape_string($sender)."', '".mysql_real_escape_string($matches[2])."')");
    }

    if (preg_match("/^NICK :(.*)$/", $irc_prikaz, $matches)){
        foreach ($nick_list as $kanal=>$nicky){
            $nicky = explode(",", $nicky);
            foreach ($nicky as $uzivatel){
                if ($uzivatel==$sender){
                    mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('NICK', '".time()."', '".mysql_real_escape_string($kanal)."', '".mysql_real_escape_string($sender)."', '".mysql_real_escape_string($matches[1])."')");
                }
            }
            Send("NAMES $kanal");
        }
    }
     
    if (preg_match("/^QUIT :(.*)$/", $irc_prikaz, $matches)){
        foreach ($nick_list as $kanal=>$nicky){
            $nicky = explode(",", $nicky);
            foreach ($nicky as $uzivatel){
                if ($uzivatel==$sender){
                    mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('QUIT', '".time()."', '".mysql_real_escape_string($kanal)."', '".mysql_real_escape_string($sender)."', '".mysql_real_escape_string($matches[1])."')");
                }
            }
            Send("NAMES $kanal");
        }
    }
}

?>

Všetko okrem troch riadkov v každej sekcii na logovanie osobitného príkazu, ktoré sú nahradené jedným príkazom na vloženie dát do databázy, je rovnaké ako v module na ukladanie logov do súboru. Upraviť ešte potrebujeme funkciu na odosielanie správ, v ktorej sú príkazy na ukladanie správ poslaných naším botom.

function sendmsg($channel, $msg){
    global $nick;
    $msg = explode("n", $msg);
    foreach ($msg as $msg1){
        $msg1 = explode("r", $msg1);
        foreach ($msg1 as $row){
            if (empty($row)) continue;
            Send('PRIVMSG '.$channel.' :'.$row);
            if ($channel[0]!="#") $channel = $sender;
            mysql_query("INSERT INTO `logs` (`type`, `time`, `channel`, `nick`, `msg`) VALUES ('MSG', '".time()."', '".mysql_real_escape_string($channel)."', '".mysql_real_escape_string($nick)."', '".mysql_real_escape_string($row)."')");
            sleep(1);
        }
    }
}

Funkcie pre využívanie logov

 

Príchod užívateľa

Keďže každú funkciu programujeme ako samostatný príkaz, vytvoríme si v zložke commands súbor prichod. Vyberieme si posledný záznam s typom JOIN, aktuálnym kanálom a užívateľom, ktorého dostaneme v parametri.

if (preg_match("/^!prichod (.*)$/", $message, $match)){
    $query = mysql_query("SELECT `time` FROM `logs` WHERE `type`='JOIN' AND `channel`='".mysql_real_escape_string($act_chan)."' AND `nick`='".mysql_real_escape_string($match[1])."' order by `time` DESC limit 0, 1");
    $data = mysql_fetch_array($query);
    if (mysql_num_rows($query)>0) sendmsg($act_chan, date("d.m.Y H:i:s", $data['time']));
    else sendmsg($act_chan, "Neexistuje záznam o príchode tohto užívateľa");
}
?>

Odchod užívateľa

Vytvoríme script odchod v commands s týmto obsahom:

if (preg_match("/^!odchod (.*)$/", $message, $match)){
    $query = mysql_query("SELECT `time` FROM `logs` WHERE (`type`='QUIT' OR `type`='PART') AND `channel`='".mysql_real_escape_string($act_chan)."' AND `nick`='".mysql_real_escape_string($match[1])."' order by `time` DESC limit 0, 1");
    $data = mysql_fetch_array($query);
    if (mysql_num_rows($query)>0) sendmsg($act_chan, date("d.m.Y H:i:s", $data['time']));
    else sendmsg($act_chan, "Neexistuje záznam o odchode tohto užívateľa");
}
?>

Posledná správa

Vytvoríme súbor poslednasprava (názov programu si samozrejme môžete vymyslieť vlastný) v commands s týmto obsahom:

if (preg_match("/^!poslednasprava (.*)$/", $message, $match)){
    $query = mysql_query("SELECT `msg` FROM `logs` WHERE (`type`='MSG' OR `type`='ME') AND `channel`='".mysql_real_escape_string($act_chan)."' AND `nick`='".mysql_real_escape_string($match[1])."' order by `time` DESC limit 0, 1");
    $data = mysql_fetch_array($query);
    if (mysql_num_rows($query)>0) sendmsg($act_chan, stripslashes($data['msg']));
    else sendmsg($act_chan, "Neexistuje záznam o poslednej správe tohto užívateľa");
}
?>

Počet správ

Vytvoríme súbor pocetsprav v commands s týmto obsahom:

if (preg_match("/^!pocetsprav (.*)$/", $message, $match)){
    $query = mysql_query("SELECT count(*) as `pocet` FROM `logs` WHERE (`type`='MSG' OR `type`='ME') AND `channel`='".mysql_real_escape_string($act_chan)."' AND `nick`='".mysql_real_escape_string($match[1])."' order by `time` DESC limit 0, 1");
    $data = mysql_fetch_array($query);
    sendmsg($act_chan, $data['pocet']);
}
?>

Záver

Nabudúce doplníme poslednú funkciu spojenú s logovaním (exportovanie logov z databázy) a ukážeme si spúšťanie príkazu v určitý čas.

Neprehliadnite: