Simple IRC bot written in PHP extendible by plugins
- Introduction
- Future improvements
- Dynamic plugins
- Error handling
- Restructure
- How to use
- Plugins
- Examples
This is a simple IRC bot I wrote back in 2011 when I used to play RuneScape (yes I am a nerd). It was written for the purpose for hosting dice games on IRC. There are a few bugs as it only took me a few hours to write, but it worked well enough for what I wanted.
Being able to load and unload a plugin without having to restart the bot is a huge advantage. I started working on this briefly as you can see in the /dev/unplug.php
file. The idea is to go through the plugin file and give each class a unique name. There would be a main plugin array in the bot that would contain a reference to the correct plugin class, which would get updated every time a plugin was loaded/unloaded. Obviously after time you'd want to restart the bot to release memory.
This is probably a good example of why PHP isn't the best choice of language for a IRC bot. Node.js or Python would be better. V2 is done in Node and has a web panel
I never got around to implementing proper error handling so that is a must for future development.
The whole bot is a bit clunky; it needs to start from fresh. More regular expression could have been used on the /lib/parser.php
file for example.
Setting up certain bot parameters when initialising the bot would have been a good idea. e.g instead of this
$bot = new bot();
Have something like
$bot = new bot('Server', 'Port', 'Nick', 'Name', 'Password');
Other things include:
- Load multiple plugins from 1 array with the ability to pass params
- Condense the components
- Basic bot functions removed from a plugin file and part of core bot
- Some magic to do asynchronous things
- Stop plugins loading if required plugins don't exist
- Auto re-join
Copy the /lib/
folder to your project. Then create a file and include the same content as in mybot.php
. Once you have done that run your bot with PHP and you are good to go!
set_time_limit(0);
ini_set('display_errors', 'on');
// Include essential files
require_once 'lib/bot.php';
// Create a new instance of the bot
$bot = new bot();
// Configure the bot
$bot->setServer('irc.server.com');
$bot->setPort(6667);
// Bot identification vars
$bot->setNick('My_bot');
$bot->setName('My_bot');
$bot->setMask('My.Bot');
$bot->setPassword('password');
// Default chanels to join
$bot->setChannel(array('#channel', '#channel passkey')); // or just a single channel : $bot->setChannel('#channel');
// Load some plugins
$bot->loadPlugin('base');
$bot->loadPlugin('move');
// Establish a connection
$bot->connect();
The plugin template is included: plugin_template.php
. It is important that all the plugins are placed in the folder /lib/plugins/
. Plugin file names should be lower case and loaded in the order they are required. This will be fixed to be more flexible in future versions.
To load a plugin in the bot, use the following code in your bot file.
$bot->loadPlugin('base');
The plugin template contains some core functions which are used to capture IRC events: message($m)
, command($m)
, trigger($type, $data)
and triggerNum($num, $data)
. These functions are detailed below including what data is returned.
The message
and command
functions share the same format of what is returned, in fact you could arguably not need the command
function and do it all based on the message
function. The only difference is that the command
function is only called when a command is called. It also has the $m['cmd']
parameter.
public function message($m)
{
switch ($m['ty'])
{
case 'NOTICE':
// Do something
break;
case 'PRIVMSG':
// Do something
break;
}
}
public function command($m)
{
switch ($m['cmd'])
{
case '!move':
// Do something
break;
case '!help':
// Do something
break;
}
}
The examples are based on the raw line below
:Test!Test@somemask.com PRIVMSG #channel :!help Hello world
Option | Type | Description | Example |
---|---|---|---|
$m['ty'] |
String | Type Message type either: PRIVMSG or NOTICE |
PRIVMSG |
$m['to'] |
String | To Where the message was sent |
#channel |
$m['fr']['na'] |
String | From name Senders name |
Test |
$m['fr']['ma'] |
String | From mask Senders mask |
somemask.com |
$m['re'] |
String | Reply Where to reply to. Name or channel |
#channel |
$m['pm'] |
Boolean | Private message Was it a private message? |
false |
$m['me']['pl'] |
String | Message line The message send by the user |
!help Hello world |
$m['me']['ex'] |
Array | Message exploded Message parts split on space |
array('!help', 'Hello', 'world') |
$m['cmd'] |
String | Command Command with the prefix (first word of the message) |
!help |
The trigger
function as shown below is used to catch the following IRC events: NICK
, KICK
, QUIT
, JOIN
, PART
. These events all return different $data - the tables below show exactly what is returned with working examples.
public function trigger($type, $data){
switch($type)
{
case: 'NICK':
// Do something when someone changes their name
break;
case: 'JOIN':
// Do something when someone joins
break;
}
}
The examples are based on the raw line below
:Test!Test@somemask.com NICK Test1
Option | Type | Description | Example |
---|---|---|---|
$data['o'] |
String | Original line Original line from the server |
:Test!Test@somemask.com NICK Test1 |
$data['from']['nick'] |
String | From name Original name |
Test |
$data['from']['mask'] |
String | From mask Original mask |
somemask.com |
$data['to'] |
String | To New nick |
Test1 |
The examples are based on the raw line below
:Test!Test@somemask.com KICK #channel Spammer :Spamming. Please don't come back
Option | Type | Description | Example |
---|---|---|---|
$data['o'] |
String | Original line Original line from the server |
:Test!Test@somemask.com KICK #channel Test :Spamming. Please don't come back |
$data['who'] |
String | Who Nick of the person who got kicked |
Spammer |
$data['by']['nick'] |
String | Kickers nick Nick of who kicked the user |
Test |
$data['by']['mask'] |
String | Kickers mask Mask of who kicked the user |
somemask.com |
$data['why'] |
String | Why Reason for kick |
Spamming. Please don't come back |
The examples are based on the raw line below
:Test!Test@somemask.com QUIT :Bye for now!
Option | Type | Description | Example |
---|---|---|---|
$data['o'] |
String | Original line Original line from the server |
:Test!Test@somemask.com QUIT :Bye for now! |
$data['who']['nick'] |
String | Quitters nick Nick of who quit |
Test |
$data['who']['mask'] |
String | Quitters mask Mask of who quit |
somemask.com |
$data['message'] |
String | Message Quit message |
Bye for now! |
The examples are based on the raw line below
:Test!Test@somemask.com PART #channel
Option | Type | Description | Example |
---|---|---|---|
$data['o'] |
String | Original line Original line from the server |
:Test!Test@somemask.com PART #channel |
$data['who']['nick'] |
String | Leavers nick Nick of who left |
Test |
$data['who']['mask'] |
String | Leavers mask Mask of who left |
somemask.com |
$data['channel'] |
String | Channel Channel they left |
#channel |
The examples are based on the raw line below
:Test!Test@somemask.com JOIN :#channel
Option | Type | Description | Example |
---|---|---|---|
$data['o'] |
String | Original line Original line from the server |
:Test!Test@somemask.com JOIN :#channel |
$data['who']['nick'] |
String | Joiners nick Nick of who joined |
Test |
$data['who']['mask'] |
String | Joiners mask Mask of who joined |
somemask.com |
$data['channel'] |
String | Channel Channel they joined |
#channel |
The examples are based on the raw line below
:Test!Test@somemask.com MODE :#channel +o Test1
Option | Type | Description | Example |
---|---|---|---|
$data['o'] |
String | Original line Original line from the server |
:Test!Test@somemask.com JOIN :#channel |
$data['who']['nick'] |
String | Joiners nick Nick of who set the mode |
Test |
$data['who']['mask'] |
String | Joiners mask Mask of who set the mode |
somemask.com |
$data['channel'] |
String | Channel Channel modes were set on |
#channel |
$data['modes'] |
Array | Modes Modes array |
array(0 => array('mode' => '+h', 'who' => 'Test1')) |
The triggerNum
function is called when the server gets a numerical response.
public function triggerNum($num, $data) {
switch($num)
{
case 366:
// Do something
break;
}
}
Sometimes you may wish to split up your project into seperate plugins, but at the same time you'd like to be able to access another plugin from within a plugin. To do this we have a getPlugins()
method.
To include another plugin in your plugin use the following code:
public function getPlugins()
{
$this->getPlugin('base');
}
Where base is the plugin name in LOWER case. Then from within your functions you can access the external plugin by doing:
$this->base->someFunction();
There are a few examples of bots in the /examples/
folder. These are the bots that I used to use for my clan. Some of the plugins include an admin, move and games plugin. Look at the code to see how to use these with all the commands.
PLEASE NOTE: A couple of the plugins require a database connection, I've lost the schema for the tables so you'll have to figure out that yourself until I can find it. Sorry xD