PHP IRC Bot v2

By killwithme on Apr 18, 2009

inspired by this one:
http://www.hawkee.com/snippet/5330/

i think it's obvious what it does

there are some bugs so dont expect it to work perfectly,
actions, status messages and notices are not recognized

maybe someone could help

<?php

/************************************
 here you can add your own triggers!
*************************************/
$script_start = time();
$mchan = "#lobby";
$server = "irc.euirc.eu";
$port = 6667;
$nick = "phpbot1";
$owner = "yournick";
$logging = true;    //enable logging?

/*********************
 color codes 
 0 = black 1 = white 2 = blue 3 = green
 4 = red 5 = brown 6 = purple 7 = orange
 8 = yellow 9 = limegreen 10 = turquise
 11 = cyan 12 = lightblue 13 = pink
 14 = grey 15 = lightgrey
*********************/

function on_text($nick, $message, $chan) {
    global $owner, $script_start;

    //  add your triggers here
    $word = explode(" ",$message);
    $i = false;
    foreach($word as $oneword)
    {
        if($i)
            $wordsafterfirst .= $oneword.' ';
        $i = true;
    }

    //  add your triggers here
    if($message == "!online") { 
        $now = time();
        if($now - $tmronline >= 30) {
            $script_dauer = duration($script_start, time());
            send("PRIVMSG",$chan,"[b][c]7,0i'm online now for about [u]$script_dauer");
            $tmronline = time();
        }
    }

    return;
}

function on_query($nick,$message) {
    global $owner;

    //  add your triggers here
    $word = explode(" ",$message);
    $i = false;
    foreach($word as $oneword)
    {
        if($i)
            $wordsafterfirst .= $oneword.' ';
        $i = true;
    }

    if($nick == $owner) {
        if($word[0] == '!quit') {
            sendsimple("QUIT",$wordsafterfirst);
            exit();
        }
        elseif($word[0] == "!nick") {
            sendsimple("NICK",$word[1]);
        }
        elseif($word[0] == "!join") {
            sendsimple("JOIN",$word[1]);
        }
    }

    return; 
}

function on_action($nick,$message,$chan) {
    global $owner;

    //  add your triggers here

    return; 
}

function on_notice($nick,$message,$chan) {
    global $owner;

    //  add your triggers here

    return; 
}

function on_mode($nick,$message,$chan) {
    global $owner;

    //  add your triggers here

    return; 
}

function on_join($nick,$message,$chan) {
    global $owner;

    //  add your triggers here

    return; 
}

function duration($start, $end){
    /* Find out the seconds between each dates */
    $timestamp = $end - $start;

    /* Cleaver Maths! */
    $years = floor($timestamp / (60 * 60 * 24 * 360));
    $timestamp %= (60 * 60 * 24 * 360);

    $months = floor($timestamp / (60 * 60 * 24 * 30));
    $timestamp %= (60 * 60 * 24 * 30);

    $weeks = floor($timestamp / (60 * 60 * 24 * 7));
    $timestamp %= (60 * 60 * 24 * 7);

    $days = floor($timestamp / (60 * 60 * 24));
    $timestamp %= (60 * 60 * 24);

    $hours = floor($timestamp / (60 * 60));
    $timestamp %= (60 * 60);

    $mins = floor($timestamp / 60);
    $secs = $timestamp % 60;

    /* display */

    if($years >= 6)
        return "$years years";
    elseif($years >= 1)
        return "$years years, $months months";
    elseif($months >= 7)
        return "$months months";
    elseif($months >= 1)
        return "$months months, $days days";
    elseif($weeks >= 3)
        return "$weeks weeks";
    elseif($weeks >= 1)
        return "$weeks weeks, $days days";
    elseif($days >= 4)
        return "$days days";
    elseif($days >= 1)
        return "$days days, $hours hours";
    elseif($hours >= 7)
        return "$hours hours";
    elseif($hours >= 1)
        return "$hours hours and $mins minutes";
    elseif($mins >= 16)
        return "$mins minutes";
    elseif($mins >= 1)
        return "$mins minutes, $secs seconds";
    else
        return "$secs seconds";
} 

/************************************
 no need to edit things beyond here!
   script does everything right ;)
*************************************/

echo "\n-----------------\nPHP IRC bot start\n-----------------\n\n";
// Prevent PHP from stopping the script after 30 sec
set_time_limit(0);
error_reporting(E_ALL ^ E_NOTICE);

$socket = fsockopen($server, $port);
fputs($socket,"NICK $nick\n");
fputs($socket,"USER $nick $nick $nick $nick :$nick\n");
echo "Everything seems ok so far...\n";

// colors
$font = array(
    '[c]'   =>  "\x03",
    '[n]'   =>  "\x0f",
    '[b]'   =>  "\x02",
    '[u]'   =>  "\x1f",
    '[r]'   =>  "\x16"
);

// sends messages like "JOIN #mychannel" or "QUIT byebye"
function sendsimple($what,$val) {
    global $socket;
    fputs($socket, "$what $val\n");
    echo "--> $what $val\n";
    return;
}
// sends messages to channels, users etc like "PRIVMSG #mychannel :this is a test"
function send($what,$where,$message,$color = true) {
    global $socket, $font;

    if($color) {
        $message = strtr($message,$font);
    }

    fputs($socket, "$what $where :$message\n");
    echo "--> $what @ $where :$message\n";
    return;
}

if($logging) {  // yes, it logs the complete irc messages
    $date = date("n-j-y");
    $time = date("H:i:s");
    $logfile = fopen("$date-phpbot-log.txt","a");
    fwrite($logfile," \n *************************** session start: $date - $time *************************** \n");
    fclose($logfile);
}

// infinite loop
while(1) {
    while($data = fgets($socket)) {
        flush();
        /*  IRC Protocol Syntax:
        **  :NICK!USER@HOST TYPE #CHAN MESSAGE
        */
        /* Seperate All Data */
        preg_match("/^:(.*?)!(.*?)@(.*?)[\s](.*?)[\s](.*?)[\s]:(.*?)$/",$data, $rawdata);
        $nick = $rawdata[1];
        $ident = $rawdata[2];
        $host = $rawdata[3];
        $event = $rawdata[4];
        $channel = $rawdata[5];
        $message = rtrim($rawdata[6]);
        $ex = explode(' ', $data);

        if($logging) {  // yes, it logs the complete irc messages
            $date = date("n-j-y");
            $logfile = fopen("$date-phpbot-log.txt","a");
            fwrite($logfile,$data);
            fclose($logfile);
        }

        if($ex[0] == "PING") {
            echo "<-- PING?\n";
            fputs($socket, "PONG ".$ex[1]."\n");
            echo "--> PONG!\n";
        }

        //  get the message 
        if ($event == 'PRIVMSG' && $channel[0] != '#') {
            $event = 'QUERY';
            // don't know how to separate normal querys from status messages yet...
        }

        if($message[0] == chr(1))
        {
            $message = strtr($message,array(chr(1) => '', 'ACTION' => ''));
            $event = 'ACTION';
        }

        //echo incoming message
        echo "<-- $nick @ $channel - $event: $message\n";
        switch ($event) {
            case 'PRIVMSG':
                on_text($nick,$message,$channel);
                break;
            case 'QUERY':
                on_query($nick,$message);
                break;
            case 'NOTICE':
                on_notice($nick,$message,$channel);
                break;
            case 'MODE':
                on_mode($nick,$message,$channel);
                break;
            case 'JOIN':
                on_join($nick,$message,$channel);
                break;
            case 'ACTION':
                on_action($nick,$message,$channel);
                break;
            default:
                break;
        }

    }
}

?>

Comments

Sign in to comment.
console   -  Nov 16, 2013

I get This error:

PHP Warning: date(): It is not safe to rely on the system's timezone settings. You are required to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'Europe/Berlin' for 'CET/1.0/no DST' instead in /BLAH/ircbot/bot.php on line 236

 Respond  
_Ice_   -  Sep 24, 2009

first of all, great bot easy to understand and modify
but i do have a questionhow to recognise a certain person joining a certain channel? if i understood correctly you have to use $ex for that one but how?

thank you :)

 Respond  
killwithme   -  Apr 20, 2009

whatever you like,
i liked it more that way, but anyone is free to change

alepatino  -  Feb 10, 2017

There is no channel entry how do I do it?

:redhispana.org 372 Mauroul3k6 :- 12 (*) Para ver las reglas del servidor usa STX/RULES
:redhispana.org 376 Mauroul3k6 :Fin de /MOTD
redhispana.org 4Mauroul3k6 ETX5 PARA INGRESAR A LOS CANALES ESCRIBA : ETX4/QUOTE AUTH 589E0340
:Mauroul3k6 MODE Mauroul3k6 :+ix

Sign in to comment

bone282   -  Apr 20, 2009

so you didn't like the array_shift idea then? I think its so much easier for users to add stuff if a switch already is made.

$message = explode(" ", $message);
$trigger = array_shift($message);
$message = implode(" ", $message);

switch(strtolower($trigger)){
case "!blah":
do blah blah;
break;

 Respond  
killwithme   -  Apr 20, 2009

like this:

    //  split the message
    $word = explode(" ",$message);

    // the first word is the trigger, usually
    if($word[0] == "!trigger") {    
            send("PRIVMSG",$chan,"this is a test");
        }
    }

send($what,$to,$text) is to send usually PRIVMSGs, which are, in IRC Protocol the normal messages and formats it for IRC

sendsimple($what,$value) is to send messages like QUIT, where $value can be a quit message

alepatino  -  Feb 11, 2017

I love it thanks dude its my first php bot but how do i make him join a channel?

Sign in to comment

bone282   -  Apr 20, 2009

Its for user events only. Like i said use the "$ex ARRAY" for other events.

Can you give an example of how to implement triggers?

 Respond  
killwithme   -  Apr 19, 2009

your preg_match does not recognize modes and status messages,
know why?

/update

 Respond  
bone282   -  Apr 19, 2009

I also noticed a problem with mIRC colours in unicode. If a sentence starts with a number, the first number of that sentence is incorporated in the unicode. thus, resulting in a normal coloured sentence with the first char missing.

But after some exploring i discovered "chr(3) is the mIRC equivalent on CTRL+K".
Just prefix any mIRC colour with a value < 10 with a zero to prevent the same crap happening
chr(3).'08,04hello'; <-- yellow foreground and red background.
chr(3).'14blah blah'; <-- gray text..

Hope it helps someone.

 Respond  
bone282   -  Apr 19, 2009

you could try this it may be slower than explode but you're only talking milliseconds..

/ Create An Infinite Loop.
while(1) {
    while($data = fgets($socket)) {

        /* Seperate All Data */
        preg_match("/^:(.*?)!(.*?)@(.*?)[\s](.*?)[\s](.*?)[\s]:(.*?)$/",$data, $rawdata);
        $nick = $rawdata[1];
        $ident = $rawdata[2];
        $host = $rawdata[3];
        $msg_type = $rawdata[4];
        $channel = $rawdata[5]; 
        $message = rtrim($rawdata[6]);
        $ex = explode(' ', $data);

        /* Create the Commands Trigger */
        $message = explode(" ", trim($message));
        $trigger = array_shift($message);
        $message = implode(" ", $message);

        /* Send PONG Back To The Server. */
        if($ex[0] == "PING"){ fputs($socket, "PONG ".$ex[1]."\n"); }
        ...
        ...

But keep using the $ex array for IRC events other than user events.

 Respond  
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.