PHP IRC Bot Class

Small, short code snippets that other people may find useful. Do you have a good regex that you would like to share? Share it! Even better, the code can be commented on, and improved.

Moderator: General Moderators

kettle_drum
DevNet Resident
Posts: 1150
Joined: Sun Jul 20, 2003 9:25 pm
Location: West Yorkshire, England

PHP IRC Bot Class

Post by kettle_drum »

Heres a class to deal with an IRC bot. It can do quite a lot of things, such as:

-op/deop/voice/devoice/kick users
-set channel topic/mode
-google searches
-weather checks for US zip codes
-magic 8ball
-get bash.org quotes
-add/view user submitted quotes
-give current time of a given time zone
-read a file to a channel in the style of a lecture
-various encryption - base64/rot13/md5
-Controls user control by names in a database

I know its a bit bigger than just a code snippet - but i thought some people may find it useful or simply just interesting. Hope you enjoy!!

Also maybe some people could give me some types on refining my code, or faster methods to do things etc etc. just general "heres how you can improve you coding" types of comments. Thanks :)

The class - ak_bot.php

Code: Select all

 
<?php
###################################################################################################
##
##                  Ak-Bot Class
##                  A class to control an IRC bot
##
###################################################################################################
 
class AK_Bot {
 
   var $fp;
   var $lfp;
   var $rfp;
 
   var $rawdata;
   var $data;
 
   var $log;
 
   var $lecture;
   var $lecture_pause;
 
   var $botnick;
   var $botpassword;
   var $botident;
   var $botrealname;
   var $localhost;
   var $quit_message;
 
   var $serveraddress;
   var $serverport;
   var $serverchannel;
 
   var $database_host;
   var $database_user;
   var $database_password;
   var $database_name;
 
   ##--------------------------------------------
   ##CLASS CONSTRUCTOR
   ##--------------------------------------------
   function AK_Bot($bot){
      $this->log = $bot[log];
 
      $this->rfp = NULL;
 
      $this->botnick = $bot[botnick];
      $this->botpassword = $bot[botpassword];
      $this->botident = $bot[botident];
      $this->botrealname = $bot[botrealname];
      $this->localhost = $bot[localhost];
 
      $this->serveraddress = $bot[serveraddress];
      $this->serverport = $bot[serverport];
      $this->serverchannel = $bot[serverchannel];
 
      $this->database_host = $bot[database_host];
      $this->database_user = $bot[database_user];
      $this->database_password = $bot[database_password];
      $this->database_name = $bot[database_name];
 
      $this->version_message = "Ak-Bot Version 1.0 - Written by greybird - 2004 - startx@aknetwork.org";
 
      set_time_limit(0); #sets the timeout limit of the script
 
      #connects to the database
      $this->database_connect();
 
      #handles the connection
      $this->connect();
   }
 
   ##--------------------------------------------
   ##DATABASE CONNECT FUNCTION
   ##Connects the bot to the database
   ##--------------------------------------------
   function database_connect(){
      $db = mysql_connect($this->database_host, $this->database_user, $this->database_password);
      mysql_select_db($this->database_name, $db);
   }
 
   ##--------------------------------------------
   ##CONNECT FUNCTION
   ##Connects the bot to the server
   ##--------------------------------------------
   function connect(){
      $this->fp = fsockopen($this->serveraddress,$this->serverport, &$err_num, &$err_msg, 30);
 
      if (!$this->fp){
         echo "There was an error in connecting to ".$this->serveraddress;
         exit;
      }else{
         $this->send("PASS ".$this->botpassword);
         $this->send("NICK ".$this->botnick);
         $this->send("USER ".$this->botident.' '.$this->localhost.' '.$this->serveraddress.' :'.$this->botrealname);
         $this->send("JOIN ".$this->serverchannel);
         echo "Connected to ".$this->serveraddress." as ".$this->botnick."<br>";
 
         $this->receive();
      }
   }
 
   ##--------------------------------------------
   ##DISCONNECT FUNCTION
   ##Disconnects the bot from the server
   ##--------------------------------------------
   function disconnect(){
      $this->send("QUIT :".$this->version_message);
      fclose($this->fp);
      fclose($this->lfp);
      exit();
   }
 
   ##--------------------------------------------
   ##RECEIVE FUNCTION
   ##Receives all data from connection
   ##--------------------------------------------
   function receive(){
      while (!feof($this->fp)){
         $this->rawdata = fgets($this->fp, 1024);
         $this->rawdata = str_replace("\r", "", str_replace("\n", "", $this->rawdata));
         #process the data just sent
         $this->process_data();
         #parse the data just sent
         $this->parse_data();
         #logs the data if needed
         if($this->log){
            $this->logging();
         }
 
         if($this->rfp AND $this->lecture_pause<>1){
            $this->lecture();
         }
      }
      $this->disconnect();
   }
 
   ##--------------------------------------------
   ##PROCESS DATA FUNCTION
   ##Processes the data sent into an array or useful items
   ##--------------------------------------------
   function process_data(){
      #Splits the data into what we want
      $params = explode(" ", $this->rawdata);
      $user = str_replace(":", "", $from[0]);
      $details = explode ("@", $from[1]);
      $message = str_replace("$params[0]", "", $this->rawdata);
      $message = str_replace("$params[1]", "", $message);
      $message = str_replace("$params[2]", "", $message);
      $from = explode ("!", $params[0]);
 
      #stores the data in an array
      $this->data[from] = str_replace(":", "", $from[0]);
      $this->data[ident] = $details[0];
      $this->data[host] = $details[1];
      $this->data[action] = $params[1];
      $this->data[sent_to] = $params[2];
      $this->data[message] = substr($message, 4);
      $this->data[ping] = $params[0];
 
      if($this->data[message][0] == "!"){
         $maction = explode(" ", $this->data[message]);
         $mfullaction = str_replace($maction[0], "", $this->data[message]);
 
         $this->data[action] = "TRUE";
         $this->data[message_action] = $maction[0];
         $this->data[message_target] = $maction[1];
         $this->data[message_target2] = $maction[2];
         $this->data[message_action_text] = str_replace(" ", "%20", substr($mfullaction, 1));
         $this->data[message_action_text_plain] = str_replace("%20", " ", $this->data[message_action_text]);
         $this->data[message_action_text_plain_with_params] = substr(str_replace($maction[0], "", str_replace($maction[1], "", $mfullaction)), 2);
      }
   }
 
   ##--------------------------------------------
   ##LOGGING FUNCTION
   ##Logs the data
   ##--------------------------------------------
   function logging(){
      if(!$this->lfp){ #file not open
         $this->lfp = fopen('log.txt', 'w');
      }
 
      $time = date('d/m/Y-H:i');
      fputs($this->lfp, $time." - ".$this->rawdata."\n");
   }
 
   ##--------------------------------------------
   ##PARSE DATA FUNCTION
   ##Parses the data that was just sent - i.e. checks for messages and does them
   ##--------------------------------------------
   function parse_data(){
      if($this->data[sent_to]==$this->serverchannel AND $this->data[action] == 'TRUE'){
         switch($this->data[message_action]){
            case '!addquote':
            case '!op':
            case '!deop':
            case '!voice':
            case '!devoice':
            case '!kick':
            case '!ban':
            case '!topic':
            case '!mode':
            case '!adduser':
            case '!lecture':
            case '!quit':
               $this->admin_option();
               break;
            case '!google':
               $this->google();
               break;
            case '!time':
               $this->time();
               break;
            case '!8ball':
               $this->ball8();
               break;
            case '!userlevel':
               $this->my_user_level();
               break;
            case '!quote':
               $this->quote();
               break;
            case '!base64':
               $this->base64();
               break;
            case '!md5':
               $this->md5();
               break;
            case '!rot13':
               $this->rot13();
               break;
            case '!weather':
               $this->weather();
               break;
            case '!version':
               $this->version();
               break;
            case '!help':
               $this->help();
               break;
         }
      }
 
      if($this->data[ping] == 'PING'){
         $this->send("PONG");
      }
   }
 
 
   ##--------------------------------------------
   ##USER LEVEL FUNCTION
   ##Checks to see if the user is logged in and returns their user level
   ##--------------------------------------------
   function user_level(){
      $codes = array('is a registered nick',
                     'is an identified user',
                     'is a registered and identified nick',
                     'has identified for this nick'
                    );
 
      $this->send("WHOIS ".$this->data[from]);
 
      #sees if user us registered
      for ($i=0; $i<5;$i++){
         $response = fgets($this->fp, 1024);
         foreach($codes as $code){
            if(substr_count($response, $code)){
               $registered = 1;
               $i=5;
            }
         }
      }
 
      #checks for user level in database
      if($registered){
         $result = mysql_query("SELECT level FROM access WHERE user = '".$this->data[from]."' AND channel = '".$this->serverchannel."' AND server = '".$this->serveraddress."'");
         while($row = mysql_fetch_assoc($result)){
            $level = $row['level'];
         }
         if(!$level){
            $level = 0;
         }
      }else{
         $level = 0;
      }
      return $level;
   }
 
   ##--------------------------------------------
   ##SEND FUNCTION
   ##Sends any data to the server
   ##--------------------------------------------
   function send($data){
      echo "<strong><font color="#FF0000">".$data."</font></strong><br>";
      fputs($this->fp, $data."\r\n");
   }
 
   ##--------------------------------------------
   ##NOT ALLOWED FUNCTION
   ##Sends notive to user saying they dont have the correcnt privs
   ##--------------------------------------------
   function not_allowed($level){
      $this->send("NOTICE ".$this->data[from]." :You must be a level ".$level." user to use this command.");
   }
 
   ##--------------------------------------------
   ##ADMIN OPTION FUNCTION
   ##Controls the admin options
   ##--------------------------------------------
   function admin_option(){
      $user_level = $this->user_level();
 
      if(!$this->data[message_target]){
         $user = $this->data[from];
      }else{
         $user = $this->data[message_target];
      }
 
      switch($this->data[message_action]){
         case '!addquote':
            if($user_level>=1){
               $time = time();
               mysql_query("INSERT INTO quote (added_by, quote, time_posted) VALUES ('".$this->data[from]."', '".$this->data[message_action_text_plain]."', '$time')");
               $this->send("NOTICE ".$this->data[from]." :Your quote was successfully added.");
            }else{
               $this->not_allowed('1');
            }
            break;
         case '!op':
            if($user_level>=5){
               $message = "MODE ".$this->data[sent_to]." +o $user";
            }else{
               $this->not_allowed('5');
            }
            break;
         case '!deop':
            if($user_level>=5){
               $message = "MODE ".$this->data[sent_to]." -o $user";
            }else{
               $this->not_allowed('5');
            }
            break;
         case '!voice':
            if($user_level>=3){
               $message = "MODE ".$this->data[sent_to]." +v $user";
            }else{
               $this->not_allowed('3');
            }
            break;
         case '!devoice':
            if($user_level>=3){
               $message = "MODE ".$this->data[sent_to]." -v $user";
            }else{
               $this->not_allowed('3');
            }
            break;
         case '!kick':
            if($user_level>=5){
               if($this->data[message_target]<>$this->botnick){
                  $message = "KICK ".$this->data[sent_to]." ".$this->data[message_target]." :".str_replace($this->data[message_target]." ", '', $this->data[message_action_text_plain]);
               }else{
                  $message = "KICK ".$this->data[sent_to]." ".$this->data[from]." :Now that was a mistake...wasnt it?";
               }
            }else{
               $this->not_allowed('5');
            }
            break;
         case '!topic':
            if($user_level>=5){
               $message = "TOPIC ".$this->data[sent_to]." :".$this->data[message_action_text_plain];
            }else{
               $this->not_allowed('5');
            }
            break;
         case '!mode':
            if($user_level>=5){
               $message = "MODE ".$this->data[sent_to]." ".$this->data[message_action_text_plain];
            }else{
               $this->not_allowed('5');
            }
            break;
         case '!adduser':
            if($user_level>=2){
               $this->add_user($user_level);
            }else{
               $this->not_allowed('2');
            }
            break;
         case '!lecture':
            if($user_level>=5){
               if(strtolower($this->data[message_target]) == 'pause'){
                  $this->lecture_pause = 1;
                  $this->send("NOTICE ".$this->data[from]." :Lecture Successfully Paused.");
               }else if(strtolower($this->data[message_target]) == 'stop'){
                  fclose($this->rfp);
                  $this->lecture_pause = 1;
                  $this->rfp = NULL;
                  $this->send("NOTICE ".$this->data[from]." :Lecture Successfully Stopped.");
               }else if(strtolower($this->data[message_target]) == 'start'){
                  $this->lecture_pause = 0;
                  $this->send("NOTICE ".$this->data[from]." :Lecture Successfully Started.");
               }else{
                  #opens the file if needed
                  if($this->rfp == NULL){
                     $this->lecture_pause = 0;
                     $this->rfp = fopen($this->data[message_target], 'r');
                     $this->send("NOTICE ".$this->data[from]." :Lecture Successfully Started.");
                  }else{
                     $this->send("NOTICE ".$this->data[from]." :An error occured when trying to start the lecture.");
                  }
               }
            }else{
               $this->not_allowed('5');
            }
            break;
         case '!quit':
            if($user_level>=9){
               $this->disconnect();
            }else{
               $this->not_allowed('9');
            }
            break;
      }
 
      $this->send($message);
   }
 
   ##--------------------------------------------
   ##ADD USER FUNCTION
   ##Adds a user to the bot access list
   ##--------------------------------------------
   function add_user($user_level){
      $result = mysql_query("SELECT count(user) FROM access WHERE user = '".$this->data[message_target]."' AND channel = '".$this->serverchannel."' AND server = '".$this->serveraddress."'");
      while($row = mysql_fetch_assoc($result)){
         $add = $row['count(user)'];
      }
 
      if($this->data[message_target2]>=$user_level){ #cant add a user level higher or equal to yours
         $this->send("NOTICE ".$this->data[from]." :You can only add a user to a lower access level than your own");
      }else{
         if($add){ #modify user level
            mysql_query("UPDATE access SET level = '".$this->data[message_target2]."' WHERE user = '".$this->data[message_target]."' AND channel = '".$this->serverchannel."' AND server = '".$this->serveraddress."'");
            $this->send("NOTICE ".$this->data[from]." :".$this->data[message_target]."'s user access level has been successfully changed to level ".$this->data[message_target2]);
         }else{ #add new user
            mysql_query("INSERT INTO access (user, level, channel, server) VALUES ('".$this->data[message_target]."', '".$this->data[message_target2]."', '".$this->serverchannel."', '".$this->serveraddress."')");
            $this->send("NOTICE ".$this->data[from]." :You have successfully added ".$this->data[message_target]." at level ".$this->data[message_target2]);
         }
      }
   }
 
   ##--------------------------------------------
   ##GOOGLE FUNCTION
   ##Controls the google search function
   ##--------------------------------------------
   function google(){
      if($this->data[message_action_text]){
         $address = "http://www.google.com/search?hl=en&ie=UTF-8&oe=UTF-8&q=".$this->data[message_action_text];
         $gfp = fopen($address, "r");
         while (!feof($gfp) AND $STOP<>'TRUE'){
            $gdata .= fgets($gfp, 1024);
            if(strstr($gdata, "<font color=#008000>")){
               $pos = strpos($gdata, "<font color=#008000>");
               $gdata = substr($gdata, $pos+20);
               $pos = strpos($gdata, " - ");
               $gdata = substr($gdata, 0, $pos);
               $STOP = 'TRUE';
            }
         }
         fclose($gfp);
 
         if($STOP<>'TRUE' OR $gdata == ""){
            $this->send("PRIVMSG ".$this->data[sent_to]." :".$this->data[from].": There were no results for: "".$this->data[message_action_text_plain].""");
         }else{
            if(!ereg("^(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?/?([a-zA-Z0-9\-\._\?\,''/\\\+&%\$#\=~])*$", $gdata)){
               $gdata = "http://".$gdata;
            }
            $this->send("PRIVMSG ".$this->data[sent_to]." :".$this->data[from].": Result For: "".$this->data[message_action_text_plain]."" - $gdata");
         }
      }else{
         $this->send("NOTICE ".$this->data[from]." :Usage: !google <search phrase/word>");
      }
   }
 
   ##--------------------------------------------
   ##TIME FUNCTION
   ##Shows the current time
   ##--------------------------------------------
   function time(){
      $time = time();
      $hour = substr($this->data[message_target], 1);
      if($this->data[message_target][0] == '+'){ #is a plus
         $time += $hour*60*60;
      }else if($this->data[message_target][0] == '-'){ #is a minus
         $time -= $hour*60*60;
      }else{
         $time += $this->data[message_target]*60*60;
      }
 
      if($hour>12 OR $this->data[message_target]>12 OR !is_numeric($this->data[message_target]) OR !is_numeric($hour)){
         $time = time();
      }
 
      $this->send("NOTICE ".$this->data[from]." :The current time is ".date('G:i', $time));
   }
 
   ##--------------------------------------------
   ##BALL8 FUNCTION
   ##A magic 8-ball function
   ##--------------------------------------------
   function ball8(){
      $words = array('Yes', 'No', 'Dont Count On It', 'For Sure', 'Of Course', 'Doubtful', 'Dont Be Stupid', 'Why You Asking Me...Just Leave Me Alone', 'Yes...Its In The Stars', 'Hmmmm', 'Sorry Im Away Right Now...Try Again Later', 'Dont Make Me Laugh you Muppit!!');
 
      if($this->data[message_target]){
         $num = rand(0, (count($words)-1));
         $this->send("PRIVMSG ".$this->data[sent_to]." :".$this->data[from]." - $words[$num]");
      }else{
         $this->send("NOTICE ".$this->data[from]." :Usage: !8ball <question>");
      }
   }
 
   ##--------------------------------------------
   ##MY USER LEVEL FUNCTION
   ##Sends you your user level
   ##--------------------------------------------
   function my_user_level(){
      $this->send("NOTICE ".$this->data[from]." :Your user level is: ".$this->user_level());
   }
 
   ##--------------------------------------------
   ##QUOTE FUNCTION
   ##Displays a quote to the user from the database
   ##--------------------------------------------
   function quote(){
      switch($this->data[message_target]){
         case 'bash':
            $address = "http://www.bash.org/?random";
            $bfp = fopen($address, "r");
            while (!feof($bfp) AND $STOP<>'TRUE'){
               $bdata .= fgets($bfp, 1024);
               if(strstr($bdata, '<p class="qt">')){
                  $pos = strpos($bdata, '<p class="qt">');
                  $STOP = 'TRUE';
               }
            }
            fseek($bfp, $pos);
            $data = fread($bfp, 5024);
            $data = ereg_replace("<br />", " ", $data);
            $data = ereg_replace("<", "<", $data);
            $data = ereg_replace(">", ">", $data);
            $data = ereg_replace("\n", "", $data);
            $data = ereg_replace("\r", "", $data);
            $data = html_entity_decode($data);
            $pos = strpos($data, '</p>');
            $quote = substr($data, 0, $pos);
            fclose($bfp);
            break;
         case 'user':
            $result = mysql_query("SELECT quote FROM quote WHERE quote LIKE '%".$this->data[message_target2]."%' ORDER BY rand() LIMIT 0,1");
            while($row = mysql_fetch_assoc($result)){
              $quote = $row[quote];
            }
            break;
         case 'from':
            $result = mysql_query("SELECT quote FROM quote WHERE added_by = '".$this->data[message_target2]."' ORDER BY rand() LIMIT 0,1");
            while($row = mysql_fetch_assoc($result)){
              $quote = $row[quote];
            }
            break;
         case 'last':
            $result = mysql_query("SELECT quote FROM quote ORDER BY time_posted DESC LIMIT 0,1");
            while($row = mysql_fetch_assoc($result)){
              $quote = $row[quote];
            }
            break;
         case 'number':
            $result = mysql_query("SELECT quote FROM quote WHERE id = '".$this->data[message_target2]."'");
            while($row = mysql_fetch_assoc($result)){
              $quote = $row[quote];
            }
            break;
         case 'random':
            $result = mysql_query("SELECT quote FROM quote ORDER BY rand() LIMIT 0,1");
            while($row = mysql_fetch_assoc($result)){
              $quote = $row[quote];
            }
            break;
         default:
            $quote = "Usage: !quote <bash|user|from|last|number|random> <value> (note bash, last and random require no <value>)";
      }
 
      if($quote == ''){
         $quote = "No Quote Found.";
      }
      $this->send("NOTICE ".$this->data[from]." :$quote");
   }
 
   ##--------------------------------------------
   ##LECTURE FUNCTION
   ##Reads a lecture file - special format file
   ##starts reading from <lecture> and stops at </lecture>
   ##--------------------------------------------
   function lecture(){
      $line = fgets($this->rfp, 1024);
      $this->send("PRIVMSG ".$this->serverchannel." :$line");
      sleep(4);
      if(feof($this->rfp)){
         $this->rfp = NULL;
      }
   }
 
   ##--------------------------------------------
   ##BASE64 FUNCTION
   ##Converts text to and from base64
   ##--------------------------------------------
   function base64(){
      if(strtolower($this->data[message_target]) == 'encode'){ #encode to base64
         $value = base64_encode($this->data[message_action_text_plain_with_params]);
      }else if(strtolower($this->data[message_target]) == 'decode'){ #decode
         $value = base64_decode($this->data[message_action_text_plain_with_params]);
      }else{ #send usage method
         $value = "Usage: !base64 <encode|decode> <message to encode/decode>";
      }
      $this->send("NOTICE ".$this->data[from]." :$value");
   }
 
   ##--------------------------------------------
   ##MD5 FUNCTION
   ##Converts text to md5 checksum - one way encryption
   ##--------------------------------------------
   function md5(){
      if($this->data[message_action_text_plain]){
         $value = md5($this->data[message_action_text_plain]);
      }else{
         $value = "Usage: !md5 <plaintext>";
      }
      $this->send("NOTICE ".$this->data[from]." :$value");
   }
 
   ##--------------------------------------------
   ##ROT13 FUNCTION
   ##Converts text to and from rot13
   ##--------------------------------------------
   function rot13(){
      if($this->data[message_action_text_plain]){
         $value = str_rot13($this->data[message_action_text_plain]);
      }else{
         $value = "Usage: !rot13 <message>";
      }
      $this->send("NOTICE ".$this->data[from]." :$value");
   }
 
   ##--------------------------------------------
   ##WEATHER FUNCTION
   ##Shows weather information for a certain zip code
   ##--------------------------------------------
   function weather(){
      if($this->data[message_target]){
         $address = "http://xoap.weather.com/weather/local/".$this->data[message_target]."?cc=*&prod=xoap&par=1004186241&key=954a7d234c6d5281";
         $wfp = fopen($address, "r");
         while (!feof($wfp)){
            $wdata .= fgets($wfp, 1024);
         }
 
         #xml parser stuff
         $p = xml_parser_create();
         xml_parse_into_struct($p, $wdata, $vals, $index);
         xml_parser_free($p);
 
         if($vals[1][value] == "Invalid location provided."){
            $value = "The zip code was invalid.";
         }else{
            $value = "Current weather for ".$vals[27][value]." - Local Time: ".$vals[30][value]." - Current Temperature: ".$vals[58][value]."°F, Feels Like: ".$vals[61][value]."°F - Condition: ".$vals[64][value]." - Pressure: ".$vals[71][value]." Inches - Wind: ".$vals[90][value]." ".$vals[81][value]."MPH - Humidity: ".$vals[96][value]."% - Visibility(miles): ".$vals[99][value]." - UV Index: ".$vals[103][value]."/".$vals[106][value]." - Dew Point: ".$vals[112][value]."°F";
         }
      }else{
         $value = "Usage: !weather <zip code>";
      }
      $this->send("NOTICE ".$this->data[from]." :$value");
   }
 
   ##--------------------------------------------
   ##VERSION FUNCTION
   ##Shows bot version info
   ##--------------------------------------------
   function version(){
      $this->send("NOTICE ".$this->data[from]." :".$this->version_message);
   }
 
   ##--------------------------------------------
   ##HELP FUNCTION
   ##Displays help messages
   ##--------------------------------------------
   function help(){
      if(!$this->data[message_target]){ #show main help
         $this->send("PRIVMSG ".$this->data[from]." :Help File For ".$this->botnick);
         $this->send("PRIVMSG ".$this->data[from]." :------------------------------");
         $this->send("PRIVMSG ".$this->data[from]." : ");
         $this->send("PRIVMSG ".$this->data[from]." : !op <nick>");
         $this->send("PRIVMSG ".$this->data[from]." : !deop <nick>");
         $this->send("PRIVMSG ".$this->data[from]." : !voice <nick>");
         $this->send("PRIVMSG ".$this->data[from]." : !devoice <nick>");
         $this->send("PRIVMSG ".$this->data[from]." : !kick <nick>");
         $this->send("PRIVMSG ".$this->data[from]." : !mode <+/- mode>");
         $this->send("PRIVMSG ".$this->data[from]." : !topic <topic>");
         $this->send("PRIVMSG ".$this->data[from]." : !addquote <quote>");
         $this->send("PRIVMSG ".$this->data[from]." : !adduser <nick> <userlevel>");
         $this->send("PRIVMSG ".$this->data[from]." : !lecture <filename/pause/stop/start>");
         $this->send("PRIVMSG ".$this->data[from]." : !quit");
         $this->send("PRIVMSG ".$this->data[from]." : !google <search word?");
         $this->send("PRIVMSG ".$this->data[from]." : !time <+/- time zone>");
         $this->send("PRIVMSG ".$this->data[from]." : !8ball <question>");
         $this->send("PRIVMSG ".$this->data[from]." : !userlevel");
         $this->send("PRIVMSG ".$this->data[from]." : !quote <bash|user|from|last|number|random> <value> (note bash, last and random require no <value>)");
         $this->send("PRIVMSG ".$this->data[from]." : !base64 <encode|decode> <message to encode/decode>");
         $this->send("PRIVMSG ".$this->data[from]." : !md5 <plaintext>");
         $this->send("PRIVMSG ".$this->data[from]." : !rot13 <message>");
         $this->send("PRIVMSG ".$this->data[from]." : !weather <zip code>");
         $this->send("PRIVMSG ".$this->data[from]." : !version");
         $this->send("PRIVMSG ".$this->data[from]." : !help");
      }else{
 
      }
   }
}
?>
 
 
Heres the code to call the bot class:
bot.php

Code: Select all

 
<?php
   include("ak_bot.php");
 
   $bot[log] = 1;
 
   $bot[botnick] = "Ak-Void";
   $bot[botpassword] = "password";
   $bot[botident] = "Ak-Void";
   $bot[botrealname] = "Advanced Knowledge Void";
   $bot[localhost] = "localhost";
 
   $bot[serveraddress] = "irc.server.com";
   $bot[serverport] = "6667";
   $bot[serverchannel] = "#macwhore";
 
   $bot[database_host] = "localhost";
   $bot[database_user] = "user";
   $bot[database_password] = "thisismypassword";
   $bot[database_name] = "akbot";
 
   $mybot = new AK_Bot($bot);
?>
 
Then you will need the following sql:

Code: Select all

 
#holds access details to the bots controls
CREATE TABLE access (
  user varchar(20) NOT NULL,
  level tinyint(1) NOT NULL DEFAULT '1',
  channel varchar(255) NOT NULL,
  server varchar(255) NOT NULL
);
 
#holds quotes
CREATE TABLE quote (
  id int(8) NOT NULL AUTO_INCREMENT,
  added_by varchar(20) NOT NULL,
  quote text NOT NULL,
  time_posted int(10) NOT NULL,
  PRIMARY KEY(id)
);
 
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post by McGruff »

That's interesting - not something I've ever tried to do before.

One comment: I wondered if it would be good to refactor it into a bunch of objects rather than one single class. Db conn, for example, probably shouldn't be in an IRC bot class.

Maybe it's a question of personal style to a certain extent but I always try to refactor methods & classes ruthlessly down to the bone. Lots of unexpected and pleasant surprises can come out of that.
kettle_drum
DevNet Resident
Posts: 1150
Joined: Sun Jul 20, 2003 9:25 pm
Location: West Yorkshire, England

Post by kettle_drum »

Yeah i guess dividing up the functions into more refined objects would be a good idea. I could then also remove the bot actions into a seperate class, and be left with a pure IRC class that would deal with connecting, disconnecting, sending and recieving data.
KrisH
Forum Newbie
Posts: 4
Joined: Thu Mar 18, 2004 3:33 pm

Post by KrisH »

nice code br0, one little question is this an example of makeing a bot go into a network and a specfic channel? if so.. it's pretty cool, i know alot of host that give free sql and php... this can be an exploit if i may say for using free host as a mirc bot? reply to me if i am wrong, i am not farmilur with your code, sorry for my bad english also :-)
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

Once you've called the bot, and its connected, what keeps it active? Ie, why does it remain on the channel, and keep the connection open?

I would have thought that the connection would timeout after some period of time if the calling program didnt continue to communicate with it.
User avatar
ol4pr0
Forum Regular
Posts: 926
Joined: Thu Jan 08, 2004 11:22 am
Location: ecuador

Post by ol4pr0 »

Havents looked at the complete script, however i am kinda a oldtimer on the networks of irc.

Regarding youre question on what keeps it alive. ( a ping )

when the nick / b0t gets ping timedout it will be kicked of the network of just simply disconnect itself.

However i do suggest you use a BNC for running b0ts. I do not know youre connection or the network youre on, however if you do have a pretty nice channel lets say over 400 p33ps youre b0t is bound to be attacked.
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

ol4pr0 wrote:Havents looked at the complete script, however i am kinda a oldtimer on the networks of irc.
Same here.
ol4pr0 wrote: Regarding youre question on what keeps it alive. ( a ping )
I don't see a persistent connection, nor a regularly-scheduled ping in the bot class posted. Did I miss it?
ol4pr0 wrote: when the nick / b0t gets ping timedout it will be kicked of the network of just simply disconnect itself.
Right - without constant reconnects/pings/activity it will lose connection. So what keeps this bot online?
ol4pr0 wrote: However i do suggest you use a BNC for running b0ts. I do not know youre connection or the network youre on, however if you do have a pretty nice channel lets say over 400 p33ps youre b0t is bound to be attacked.
Well sure - but the concept here is a php-written BOT, or is it? If it is, I am very unclear about how it STAYS online. I see the connect, the disconnect, and the "while-connected" functions, but not the method to remain online persistently.

At best, it looks like a "jump online, execute commands, jump offline" bot.

Did I miss something?
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

I've seen also some webbased IRC scripts written in php (script puts data in db, and javascripts makes sure the page gets reloaded every 10 Seconds) and they generate a <span style='color:blue' title='I&#39;m naughty, are you naughty?'>smurf</span> :P

Btw, screen and irssi are my alltime favorites :)
Kwah
Forum Newbie
Posts: 1
Joined: Sat Mar 27, 2004 7:48 am

Post by Kwah »

yo - ive made my own one but this one is more complex and has given me alot of ideas :P
User avatar
EvilWalrus
Site Admin
Posts: 209
Joined: Thu Apr 18, 2002 3:21 pm
Location: Springmont, PA USA

Post by EvilWalrus »

http://www.evilwalrus.com/viewcode.php?codeEx=380

IRC bots are indeed old news... you can learn from that as welll....
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

EvilWalrus wrote:http://www.evilwalrus.com/viewcode.php?codeEx=380

IRC bots are indeed old news... you can learn from that as welll....
Perhaps I wasnt clear enough.

I'm aware that they exist, and that they have for a considerable amount of time.


I don't understand from looking at the code what keeps them online and persistent beyond the lifetime of the script (seconds usually), and thus from timing out, and falling off of IRC.

Can someone share some insights about that?
User avatar
markl999
DevNet Resident
Posts: 1972
Joined: Thu Oct 16, 2003 5:49 pm
Location: Manchester (UK)

Post by markl999 »

The while (!feof($this->fp)){ ... } loop in the receive method keeps the script constantly looping. The
if($this->data[ping] == 'PING'){
$this->send("PONG");
}
in the parse_data method keeps the connection alive by responding to PING with a PONG, that stops the irc server 'dropping' the client.
malcolmboston
DevNet Resident
Posts: 1826
Joined: Tue Nov 18, 2003 1:09 pm
Location: Middlesbrough, UK

Post by malcolmboston »

this is a very interesting read.........
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

everything you ever wanted to know about irc http://www.faqs.org/rfcs/rfc1459.html :)
kettle_drum
DevNet Resident
Posts: 1150
Joined: Sun Jul 20, 2003 9:25 pm
Location: West Yorkshire, England

Post by kettle_drum »

As mark said whenever the irc server sends a ping to the bot - every 180 seconds or so, the bot replies with a pong command - which just tells the server "yes im still alive". In the class constructor set_time_limit(0); means that the script wont timeout by itself due to a maximum execution time (usually 30 seconds). Hope that answers whoevers question that was.

Umm yes a script like this could be used for the wrong uses - such as to flood a server etc, but then anything can. I just say dont do it as its lame.

The other thing is that the bot sometimes disconnects unexpectely if you run if from a browser - but works A LOT better if you run it from a shell/cli.

And finally, im currently updating this bot to make it bigger and better by using modules - so that a framework bot can be made to do whatever you like by adding other modules to it e.g. chanserv, nickserv, operserv, logging, newsserv, search etc - and by adding a "fake stack" to queue commands/processes so it runs like it uses threads and so speeds it up and keeps a constant flow of data coming in through the socket connection - which also helps to ensure that it never pings out, tests so far have had it online for just over 2 days with no interruptions.

Ill keep you posted as to the arrival of the new one incase anybody wants to have a play with it.
Post Reply