This is code that I wrote for some Olympian (remember those guys?) alliance tools way back when. I tried to code it in a manner that made it easy for me to add on to, and maintain... so its probably all confusing and such to persons without my coding mentality.
This code has the ability to add remote interactivity by adding seperately and individually coded scripts, read on for further details. Also, it automatically logs whatever it sees.
This code was written on Win2k, in a pretty new version of PHP, and has connectability to a MySQL DB. It must be run from the shell (command prompt, etc). Read up on the PHP website on how to setup your PHP module and webserver to accomplish that. It's beyond the scope of this post to explain that as well.
Before I post the code, I'll try to explain it slightly. Basically, my IRC bot consists of four MAIN functions which call on a number of other functions for operability. The four functions are: one to load the configuration and register any global variables, one to connect to the server, one to register the "client", and one to maintain the IRC process. Here are these four functions.
Code:
irc_load_configuration("rheia.ini");
irc_connect($irc_config['server'], $irc_config['port']);
irc_register($irc_config['user'], $irc_config['nick'], $irc_config['name']);
irc_process();
The "rheia.ini" file is a config file consisting of these changeable variables. It should be placed in the same directory as the main script. I'm pretty sure that this is all that you will have to change for the basics.
Code:
user = "Rheia"
name = "Rheia"
nick = "Rheia" ; bot nick
server = "irc.server.org"
port = "6667"
nspass = "*****"
adminpass = "somepass"
maxlag = "300" ;set the max time between ping/pongs that the connection will stay alive
[access]
council = "checker"
council = "pointshostile"
council = "pointsfriendly"
council = "pointscheck"
battlefield = "pointshostile"
battlefield = "checker"
battlefield = "pointscheck"
Most applications require database connectivity, which can be achieved in this next bit of code.
Code:
$database_server = "127.0.0.1";
$database_username = "*****";
$database_password = "*****";
$database_name = "Rheia";
$Now = time();
if (!$dblink = mysql_connect($database_server, $database_username, $database_password))
{
echo "Fatal Error! Could not connect to the database server.";
}
if (!mysql_select_db($database_name, $dblink))
{
echo "<FONT COLOR = '#FF0000'> Fatal Error! Could not find the database.</FONT><BR>";
}
// Unset the database variables, for security means.
unset ($database_server, $database_username, $database_password, $database_name);
$TimeZone = "CEST";
Ok, here is where it will get confusing. This next set of code is the "meat and potatoes" of this bot. These are all of the functions which are used by the initial four functions I spoke of earlier and the sub functions used within those. I keep these separate because they are very generic and should work for most any application be it a bot for planetarion or whatever else you want to use it for in the IRC-sense. I recommend copy and pasting this bit, save it in a file called 'irc.php' and just include it in your script before the four main functions.
Code:
set_time_limit(0);
require("irc.dbconn.php");
function irc_success($str)
{
echo " + SUCCESS: $str\n";
irc_debug_log(" + SUCCESS: " . $str);
}
function irc_error($str)
{
echo " - ERROR: $str\n";
irc_debug_log(" - ERROR: " . $str);
}
function irc_dbquery($sql)
{
global $dblink;
if (!$Qry = mysql_query($sql, $dblink))
{
irc_error("Could not query the database " . mysql_error());
// Error("Could not query the database");
}
return $Qry;
}
function irc_prepstring($str)
{
$str = mysql_escape_string($str);
$str = strip_tags($str);
return $str;
}
function irc_connect($address, $port)
{
global $irc; // THE SOCKET WHICH WE WILL CREATE
$irc = socket_create(AF_INET, SOCK_STREAM, 0);
if ($irc < 0)
{
irc_error("socket_create() failed: ".socket_strerror(socket_last_error()));
exit;
}
if (!socket_connect($irc, $address, $port))
{
irc_error("socket_connect() failed: ".socket_strerror(socket_last_error()));
exit;
}
if (!socket_set_nonblock($irc))
{
irc_error("socket_set_nonblock() failed: ".socket_strerror(socket_last_error()));
exit;
}
irc_success("Socket successfully created, and connected to $address:$port");
}
function irc_debug_log($text)
{
$str = "[" . date("d.m.Y") . "][" . date("H:i:s") . "] " . $text . " \r\n";
$logfile = "logs__" . date("d_m_Y") . ".log";
$fp = fopen($logfile, "a");
fwrite($fp, $str);
fclose($fp);
}
function irc_load_configuration($path)
{
global $irc_config, $irc_scripts, $irc_channels;
srand((double)microtime()*1000000);
if (!file_exists($path))
{
irc_error("Could not open the file specified by the path: $path");
return -1;
}
$x = 0;
irc_debug_log("---------------------------------------------------------[ START ]-");
irc_debug_log("Type\tSetting\t\t\tValue");
irc_debug_log(" ");
foreach(file($path) as $line)
{
$x++;
if (ereg("^\[([^]]+)\].*$", trim($line), $data))
{
$section = strtolower($data[1]);
}
else if(ereg("^([^[:space:]]+)[^=]*=[^\"]*\"([^\"]+)\".*$", trim($line), $data))
{
$setting = strtolower($data[1]); // The Left Side
$value = $data[2]; // The Right Side
switch($section)
{
case 'main':
$irc_config[$setting] = $value;
irc_debug_log("CONFIG\t$setting\t\t\t$value");
break;
case 'access':
$channel = "#" . $setting;
$scriptname = $value;
$scriptfile = "scripts/irc_" . stripslashes($scriptname) . ".php";
// LOAD THE FILE and DO THAT STUFF
if ($scriptname)
{
if (file_exists($scriptfile))
{
include_once($scriptfile);
irc_debug_log("Referencing Script File: " . $scriptfile);
}
else
{
irc_error("Could not load the script (" . $scriptfile . ")");
}
}
// FIX THE CHANNEL PERMISSIONS
$irc_channels[$channel][commands] .= $irc_scripts[$scriptname][command] . " ";
break;
}
}
}
irc_success("Configuration file successfully loaded");
}
function irc_send($str)
{
global $irc, $irc_config;
$str .= "\n";
socket_write($irc, $str, strlen($str));
}
function irc_reply($str, $target)
{
global $irc_reply_buffer;
$irc_reply_buffer[] = "PRIVMSG " . $target . " :" . irc_prepstring($str);
}
function irc_micropause($usec)
{
// Function inspired by [email protected]
// usleep() rendition for Windows
$start = gettimeofday();
do {
$stop = gettimeofday();
$timePassed = 1000000 * ($stop['sec'] - $start['sec']) + $stop['usec'] - $start['usec'];
} while ($timePassed < $usec);
}
function irc_reply_buffer_maintenance()
{
global $irc_reply_buffer;
while (count($irc_reply_buffer) > 0)
{
irc_send(array_shift($irc_reply_buffer));
}
}
function irc_register($user, $nick, $name)
{
irc_send("USER " . $user . " 2 3 :" . $name);
irc_send("NICK " . $nick);
}
function irc_process()
{
global $irc;
while (1)
{
sleep(1);
$read = array($irc);
if (socket_select($read, $write, $except = NULL, 1))
{
if ($buffer = socket_read($irc, 10240))
{
while (($pos = strstr($buffer, "\n")) && $pos)
{
$line = str_replace($pos, "", $buffer);
irc_parse_commands($line);
$buffer = str_replace($line."\n", "", $buffer);
}
}
}
irc_reply_buffer_maintenance();
if ($irc_current_nick != $irc_config['nick'])
{
irc_send("NICK " . $irc_config['nick']);
if ($irc_config['nspass'])
{
irc_send("NS RECOVER " . $irc_config['nick'] . $irc_config['nspass']);
irc_debug_log("NickServ Recovery Process");
}
}
}
}
function irc_parse_commands($line)
{
global $irc_config, $irc_scripts, $irc_channels, $msg, $last_lag_check;
$parts = explode(" ", $line);
if (sizeof($parts) > 0)
{
irc_debug_log($line);
if ($parts[0] == 'PING')
{
irc_send("PONG " . $parts[1]);
irc_debug_log("PING? PONG!");
$last_lag_check = time();
return 1;
}
if ($parts[0] == 'ERROR')
{
irc_send("QUIT");
irc_error("Shutting Down");
irc_shutdown();
return 0;
}
switch ($parts[1])
{
/* End of MOTD -or- No MOTD file found. Join the channels from the .ini file (Basically, a primitive perform) */
case '376': case '422':
if ($irc_config['nspass'])
{
irc_send("NS IDENTIFY " . $irc_config['nspass']);
irc_debug_log("NickServ information sent");
foreach(array_keys($irc_channels) as $channel)
{
irc_send("CS INVITE " . $channel);
irc_debug_log("Requesting a ChanServ Invite to: " . $channel);
}
}
foreach(array_keys($irc_channels) as $channel)
{
irc_send("JOIN " . $channel);
irc_debug_log("Attempting to join: " . $channel);
}
break;
/* NICKNAME IS IN USE */
case '433':
if ($irc_config['nspass'])
{
irc_send("NS RECOVER " . $irc_config['nick'] . $irc_config['nspass']);
irc_debug_log("NickServ Recovery Process");
irc_send("NICK " . $irc_config['nick'] . "ghost");
$irc_current_nick = $irc_config['nick'] . "ghost";
}
else
{
irc_send("NICK " . $irc_config['nick'] . "ghost");
$irc_current_nick = $irc_config['nick'] . "ghost";
}
break;
/* The bot has been kicked, try to rejoin */
case 'KICK':
irc_debug_log("Kicked from " . trim($parts[2]) . " - Attempting to rejoin...");
irc_send("JOIN " . trim($parts[2]));
break;
/* A standard client message */
case 'PRIVMSG':
eregi("^:(([^!]+)!([^@]+)@([^ ]+)) PRIVMSG ([^ ]+) :(.*)$", trim($line), $regs);
$msg = array ("ident" => $regs[1],
"nick" => $regs[2],
"user" => $regs[3],
"host" => $regs[4],
"target" => $regs[5],
"content" => $regs[6]
);
eregi("^:(([^!]+)!([^@]+)@([^ ]+)) PRIVMSG ([^ ]+) :(([^ ]+).*)$", trim($line), $regs);
$command = $regs[7];
$msg['command'] = $command;
if ($msg['content'] == "!disconnect " . $irc_config['adminpass'] && !strstr($msg['target'], "#"))
{
irc_debug_log($msg['nick'] . " issued the !disconnect command");
irc_send("QUIT :Closing - " . $irc_config['name'] . " - By [email protected]");
irc_shutdown();
die;
}
if ($msg['content'] == "!reconnect " . $irc_config['adminpass'] && !strstr($msg['target'], "#"))
{
irc_debug_log($msg['nick'] . " issued the !reconnect command");
irc_send("QUIT :Reconnecting - " . $irc_config['name'] . " - By [email protected]");
irc_shutdown();
irc_connect($irc_config['server'], $irc_config['port']);
irc_register($irc_config['user'], $irc_config['nick'], $irc_config['name']);
}
if ($msg['content'] == "!reauth " . $irc_config['adminpass'] && !strstr($msg['target'], "#"))
{
irc_debug_log($msg['nick'] . " issued the !reauth command");
if ($irc_config['nspass'])
{
irc_send("NS IDENTIFY " . $irc_config['nspass']);
irc_debug_log("NickServ information sent");
foreach(array_keys($irc_channels) as $channel)
{
irc_send("CS INVITE " . $channel);
irc_debug_log("Requesting a ChanServ Invite to: " . $channel);
}
}
foreach(array_keys($irc_channels) as $channel)
{
irc_send("JOIN " . $channel);
irc_debug_log("Attempting to join: " . $channel);
}
}
$commands_on_this_channel = strtolower($irc_channels[$msg['target']][commands]);
if (strstr($commands_on_this_channel, $command))
{
for ($i = 0; $i <= sizeof($irc_scripts); $i++)
{
$get_script = each($irc_scripts);
$key = $get_script['key'];
$val = $get_script['value'];
$function_name = $irc_scripts[$key]['function_name'];
if (($irc_scripts[$key]['command'] == $command))
{
call_user_func($function_name);
irc_debug_log($function_name . "(" . $command . ") executed for " . $msg['nick'] . "@" . $msg['host'] . ". Parameters: " . $msg['content']);
}
} reset($irc_scripts);
}
break;
}
}
}
function irc_shutdown()
{
global $irc;
socket_close($irc);
irc_success("Socket closed");
}
Finally, to provide user interactivity, my bot includes a creative scripting mechanism. Basically, here is what you do. In the same directory as the main bot file, create another directory called "scripts". The bot will automatically check this directory when it is activated, and load the contents of each script file and enable its operation.
Each "script" used by the bot has to be in its own file. Therefore if you want your users to have the ability to check coords with a "!check xx:yy" command, you would have to have a file named something along the lines of "check_coords.php". If you also wanted to have a command such as "!search <roid-size>", you would need another file named something else. Here is the template and some sample scripts that I made. They are pretty straight forward.
Code:
irc_search.php
<?PHP
$irc_scripts[$scriptname] = array(
"title" => "Rheia Search",
"author" => "[email protected]",
"command" => "!search", // THIS IS THE TRIGGER FOR THIS COMMAND THE BOT WILL LOOK FOR
"function_name" => "search", // THE ACTUAL NAME OF THE FUNCTION USED IN THE CODE, CASE-SENSITIVE
"type" => "command"
);
function search()
{
global $msg;
irc_reply("Search Results: ", $msg['nick']);
}
?>
///////////////////////////////////////////////////////////
irc_pointshostile.php
<?PHP
$irc_scripts[$scriptname] = array(
"title" => "Adding Hostile Points to the database",
"author" => " [email protected]",
"command" => "!hostile",
"function_name" => "Hpointsadd",
"type" => "command"
);
function Hpointsadd()
{
global $msg;
ereg ("^" . $msg['command'] . " ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})$", $msg['content'], $coords);
if ($coords[1] < 1 || $coords[2] < 1 || $coords[3] < 1 )
{
irc_reply("Invalid coords entered. Please use the format: !hostile xx:yy:zz", $msg['nick']);
return 0;
}
irc_prepstring($coords[1]);
irc_prepstring($coords[2]);
irc_prepstring($coords[3]);
$Qry1 = irc_dbquery("SELECT RulerName FROM dump_planet_flux WHERE X = $coords[1] AND Y = $coords[2] AND Z = $coords[3]");
if (mysql_num_rows($Qry1) > 0)
{
while ($Rec1 = mysql_fetch_array($Qry1))
{
$Ruler = irc_prepstring($Rec1['RulerName']);
}
$Qry1 = irc_dbquery("SELECT PlanetID FROM info_planet WHERE RulerName = '$Ruler'");
if (mysql_num_rows($Qry1) > 0)
{
irc_dbquery("UPDATE info_planet SET HostilePoints = HostilePoints + 10 WHERE RulerName = '$Ruler'");
}
else
{
irc_dbquery("INSERT INTO info_planet (RulerName, HostilePoints) VALUES ('$Ruler', 10)");
}
irc_dbquery("INSERT INTO PointLog (Date, Value, Description, RulerName) VALUES (" . time() . ", -10, '(IRC) Hostile Points <BR><FONT COLOR = #777777>Added by: " . $msg['nick'] . "@" . $msg['host'] . "</FONT>', '$Ruler')");
irc_reply("HOSTILE rating points added to ($coords[1]:$coords[2]:$coords[3])", $msg['nick']);
}
else
{
irc_reply("These coords do not exist. Please try again.", $msg['nick']);
}
}
?>
/////////////////////////////////////
the basic template
<?PHP
$irc_scripts[$scriptname] = array(
"title" => "title",
"author" => "Your Name [email protected]",
"command" => "!remote_control",
"function_name" => "MyFunction",
"type" => "command"
);
function MyFunction()
{
}
?>
So, that should be it. If you need some help with this, you can hit me up at
[email protected] for questions, but you better have a clue about PHP at least a little bit. It's been ALONG time since I coded anything so I don't know how much help I will be, but you can use this as a guide.
Enjoy.