summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Blatech.ini5
-rw-r--r--Blatech.php62
-rw-r--r--Client.ini10
-rw-r--r--Client.php248
4 files changed, 325 insertions, 0 deletions
diff --git a/Blatech.ini b/Blatech.ini
new file mode 100644
index 0000000..9ee7489
--- /dev/null
+++ b/Blatech.ini
@@ -0,0 +1,5 @@
+;[Command Name]
+;command = shell_command
+;path = false | /path/to/command
+;stdin = true | false
+;args = true | false
diff --git a/Blatech.php b/Blatech.php
new file mode 100644
index 0000000..c1b477e
--- /dev/null
+++ b/Blatech.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * Run shell commands loaded from a config file
+ *
+ * @author Phil Burton <phlbeansburton@gmail.com>
+ */
+class Blatech
+{
+ protected $blatech = null;
+
+ /**
+ * Construct the object loading the config file and storing it
+ * as an array in the $blatech var
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @param $config String The file and path of the config file
+ */
+ public function __construct($config)
+ {
+ $this->blatech = parse_ini_file($config,true);
+ }
+
+ /**
+ * Run a shell command and return the result
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @param $message Array The message containing the required commands
+ * @param $args String The sting of space seperated arguments
+ * @return String The result of the shell command
+ * @todo Abstract IRC related information away from this class
+ */
+ public function runCommand($message, $args)
+ {
+ $nick = ltrim(explode('!', $message[0])[0],":");
+ $channel = $message[2];
+
+ $msg = explode(" ", ltrim(trim($message[3],"\r\n"), ":!"));
+ if (!isset($msg[0])) {
+ return null;
+ } else {
+ if (array_key_exists($msg[0], $this->blatech)) {
+ $command = $this->blatech[$msg[0]]['command'];
+ $stdin = $this->blatech[$msg[0]]['stdin'];
+ $cargs = $this->blatech[$msg[0]]['args'];
+ $path = $this->blatech[$msg[0]]["path"];
+ if ($path == true) {
+ $cd = "cd " . $path . ' && ';
+ } else {
+ $cd = "";
+ }
+ if ($stdin == true) {
+ return explode("\n", shell_exec($cd . 'echo "' . $args . '" | ' . $command))[0];
+ } else if ($cargs == true) {
+ return 'Command Line Arguments Not Supported Yet.';
+ } else {
+ return explode("\n", shell_exec($cd . $command))[0];
+ }
+ }
+ }
+ }
+}
diff --git a/Client.ini b/Client.ini
new file mode 100644
index 0000000..2e61b34
--- /dev/null
+++ b/Client.ini
@@ -0,0 +1,10 @@
+;[config]
+
+;server = example.com
+;port = 12345
+;channel = #channel
+;realname = Bot
+;username = Bot
+;hostname = bla.com
+;servername = someserver.com
+;pass = PASSWORD for user on network
diff --git a/Client.php b/Client.php
new file mode 100644
index 0000000..cfd0fca
--- /dev/null
+++ b/Client.php
@@ -0,0 +1,248 @@
+<?php
+
+/**
+ * A headless, slim IRC Client, that act's as the core of an IRC BOT.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ */
+class Client {
+
+ protected $connected = false;
+ protected $socket = null;
+ protected $config = null;
+ protected $blatech = null;
+
+ /**
+ * Constructor to load up a config file, and create a socket connection
+ * and register the client to the IRC server. Then join then the channel
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @param $config array An array of config options
+ * @todo Use a config object and create a isConfigValid function
+ */
+ public function __construct($config)
+ {
+ // Create the client from the given config
+ $this->config = parse_ini_file($config);
+ if ($error = $this->isSocket() === true) {
+ $this->userCommand();
+ $ping = $this->nickCommand();
+ $this->pongCommand($ping);
+ $this->connected = true;
+ $this->identifyCommand();
+ $this->joinCommand();
+ } else {
+ var_dump($error);
+ die();
+ }
+
+ }
+
+ /**
+ * Checks to see if a socket has already been created
+ * If not, it creates the new socket based on the config
+ * and then returns true if the socket is created
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @return bool True if socket is created otherwise false
+ * @todo gracefully return false if the socket didn't get created
+ */
+ protected function isSocket()
+ {
+ if (!$this->socket) {
+ // Try and create socket
+ if (($this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
+ echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
+ die();
+ }
+ if (!socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
+ echo socket_strerror(socket_last_error($this->socket));
+ }
+ if (socket_connect($this->socket, $this->config['server'], $this->config['port']) === false) {
+ echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($this->socket)) . "\n";
+ }
+ }
+ $this->getResponse();
+ return true;
+ }
+
+ /**
+ * Send the USER command to the IRC server using the config to get the
+ * required details.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @todo Create sendCommand function to handle generic message sending
+ */
+ protected function userCommand()
+ {
+ socket_write($this->socket, "USER ". $this->config["username"] . ' ' . $this->config['hostname'] . ' ' . $this->config['servername'] . " :" . $this->config['realname'] . "\r\n");
+ }
+
+ /**
+ * Send the NICK command to the IRC server using the config to get the
+ * required details.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @todo Create sendCommand function to handle generic message sending
+ */
+ protected function nickCommand()
+ {
+ // Set the nick
+ socket_write($this->socket, "NICK ". $this->config["username"] . "\r\n");
+ $response = $this->getResponse();
+ var_dump('NICK COMMAND RESPONSE: ');
+ var_dump($response);
+ return $response; // save response to use in pong response
+ }
+
+ /**
+ * Send the PONG command to the IRC server using the config to get the
+ * required details. If the ping param is set, then send that too.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @param @ping String A message to send along with the pong response
+ * @todo Create sendCommand function to handle generic message sending
+ * @todo Create better way to handle respones, and log them
+ */
+ protected function pongCommand($ping = null)
+ {
+ // Pong the server
+ if (!$ping) {
+ socket_write($this->socket, "PONG");
+ } else {
+ socket_write($this->socket, "PONG $ping\r\n");
+ }
+ if (!$this->connected) {
+ var_dump('PONG COMMAND RESPONSE: ');
+ $this->getResponse();
+ }
+ }
+
+ /**
+ * Send a mesage to the IRC server, messaging the nick server to identify
+ * the client with the config details.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @todo Create sendCommand function to handle generic message sending
+ * @todo Create better way to handle respones, and log them
+ */
+ protected function identifyCommand()
+ {
+ // Identify the user
+ socket_write($this->socket, "PRIVMSG ". "nickserv identify " . $this->config["pass"] . "\r\n");
+ var_dump('IDENTIFY COMMAND RESPONSE: ');
+ $this->getResponse();
+ }
+
+ /**
+ * Send a JOIN command to the IRC server to join a channel based on the
+ * config details
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @todo Create sendCommand function to handle generic message sending
+ * @todo Create better way to handle respones, and log them
+ * @todo Find a way to support multiple channels
+ */
+ protected function joinCommand()
+ {
+ // Join the channel
+ socket_write($this->socket, "JOIN ". $this->config["channel"] . "\r\n");
+ var_dump('JOIN COMMAND RESPONSE: ');
+ $this->getResponse();
+ }
+
+ /**
+ * Read the socket, waiting for an incoming message from the IRC
+ * server. Display memory usage here. Dump and return the response.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @return String The response from the server
+ * @todo Create better way to handle respones, and log them
+ */
+ protected function getResponse()
+ {
+ var_dump("memory: " . memory_get_usage()/1000 . 'KB');
+ $response = "";
+ while(true) {
+ sleep(1);
+ $response .= socket_read($this->socket,4096);
+ if ($response == 0) {
+ echo($response) . "\n";
+ return $response;
+ }
+ }
+ }
+
+ /**
+ * Send a PRIVMSG command to the IRC server to message a channel based on
+ * the config details.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @todo Create sendCommand function to handle generic message sending
+ * @todo Create better way to handle respones, and log them
+ * @todo Find a way to support multiple channels
+ * @todo Find a way to support private and channel message sending
+ */
+ public function msgCommand($msg)
+ {
+ socket_write($this->socket, "PRIVMSG ". $this->config["channel"] . ' ' . $msg . "\r\n");
+ }
+
+ /**
+ * The main loop of the Client. Constantly listen for incoming messages
+ * from the IRC server; respond to pings, and look out for bot commands.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @todo Create sendCommand function to handle generic message sending
+ * @todo Create better way to handle respones, and log them
+ * @todo Find a way to support multiple channels
+ * @todo Find a way to support private and channel message sending
+ */
+ public function loop()
+ {
+ while (true) {
+ $message = explode(" ", $this->getResponse());
+ if ($message[0] == 'PING') {
+ $this->pongCommand($message[1]);
+ } else {
+ if (strpos($message[3], ":!") === 0) {
+ $args = '';
+ if(($count = count($message)) > 4) {
+ for ($i = 4; $i < $count; $i++ ) {
+ $args .= rtrim($message[$i]) . ' ';
+ }
+ $args = rtrim($args);
+ }
+ $this->msgCommand($this->blatech->runCommand($message, $args));
+ }
+ }
+ $message = null;
+ }
+ }
+
+ /**
+ * Check for an existing Blatech object, if it doesn't exist, create it
+ * with the config path that is passed.
+ *
+ * @author Phil Burton <philbeansburton@gmail.com>
+ * @return Blatech The Blatech object
+ */
+ public function loadBlatech($config)
+ {
+ if (null == $this->blatech) {
+ include_once("Blatech.php");
+ $this->blatech = new Blatech($config);
+ }
+ return $this->blatech;
+ }
+}
+
+// Create a new client object
+$client = new Client('Client.ini');
+// Load up the blatech Object
+$client->loadBlatech('Blatech.ini');
+// Send a hello command to the channel
+$client->msgCommand('In The Rear, With The Gear!');
+// Start the main loop
+$client->loop();
+