Chat
|
|
|
|
<?php /*
* IRC Client - An RFC1489 compliant IRC class
*
* Copyright (c) 2005, Victor Roman Archidona <daijo@unixevil.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <ORGANIZATION> nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
class IRCClient {
private $buf_size = 1024; /**< Default buffer size */
private $sock = 0; /**< Socket handler */
private $connected = 0; /**< Status flag */
private $show_trans = false; /**< Debug flag */
/*
* The following array contains information which be provided by the user
* using SetOptions to connect to IRC.
*/
private $user_config = array("nick" => NULL, /* Nickname */
"real" => NULL, /* Real name */
"mode" => NULL /* User modes */
);
/*
* The following array contains information about last received message
* from the IRC server which has been processed. The field 'user' only
* exists if command ('cmd') processed is PRIVMSG or NOTICE.
*/
private $cur_message = array("orig" => NULL, /* Origin */
"cmd" => NULL, /* Command */
"dest" => NULL, /* Destination */
"text" => NULL /* Message */
);
private $cur_user = array("nick" => NULL, /* Nickname */
"host" => NULL, /* Hostname or IP */
"identd" => NULL /* Ident (rarely real use) */
);
/*
* Function...: Constructor
* Task.......: Checks for PHP version
*/
public function __construct()
{
if (version_compare(phpversion(), "5.0.0", "gt") < 0)
trigger_error("Class ".__CLASS__." requires PHP 5.0.0 or greater ".
"and you have ".phpversion().". Please upgrade.",
E_USER_ERROR);
}
/*
* Function...: Flush
* Task.......: Clean cur_message and cur_user
*/
public function Flush()
{
unset($this->cur_message);
unset($this->cur_user);
}
/*
* Function...: SetOptions
* Task.......: Set the internal array user_config with nneeded parameters
* to connect to IRC.
*
* Param......: $nick -> Nickname (Mandatory, STRING)
* Param......: $realname -> Real user name (Optional, STRING)
* Param......: $modes -> User modes to use on connect (Optional, STRING)
*/
public function SetOptions($nick, $realname = NULL, $modes = NULL)
{
/*
* If realname is not specified, we adjust it with the same content
* than nick.
*/
if (!strlen($realname)) {
$realname = $nick;
}
$this->user_config = array("nick" => $nick,
"real" => $realname,
);
}
/*
* Function...: IsConnected
* Task.......: Checks if a connection to the server exists
*/
public function IsConnected()
{
return $this->connected;
}
/*
* Function...: Send
* Task.......: Sends a string to server
*
* Param......: $text -> String to be send (Mandatory, STRING)
*
* Returns....: -1 -> if sockets does not exists
* Returns....: -2 -> if we cannot write in the socket
* Returns....: Number of bytes written if all were ok.
*/
public function Send($text)
{
$ret = 0; /* Status variable */
/* If socket does not exists, returns -1. Before we MUST create it */
if (!$this->sock) {
return -1;
}
/* Now try to write in the socket */
$ret = fwrite($this->sock, $text."rn", strlen($text)+2);
/* Well... we cannot write in the socket, returns -2 */
if (!$ret) {
return -2;
}
/*
* If debugging is active AND text is not null, show the string
* sent in stdout (console)
*/
if ($this->show_trans && strlen($text)) {
echo "[out] $textn";
}
/*
* if all are ok, returns the number of bytes written and stored
* in $ret
*/
return $ret;
}
/*
* Function...: Connect
* Task.......: Connects to the IRC server.
*
* Param......: $server -> Server to connect to (Mandatory, STRING)
* Param......: $port -> Server port to connect (Optional, INTEGER)
* Param......: $ssl -> Use a secure connection (Optional, BOOLEAN)
* Param......: $pass -> Pass of the server if any (Optional, STRING)
*
* Returns....: 1 -> Connection ok, or connection already stablished
* Returns....: -1 -> Error creating socket
*/
public function Connect($server, $port = 6667, $ssl = 0, $pass = NULL)
{
/* If we are connected, return 1 here */
if ($this->IsConnected()) {
return 1;
}
/*
* If in the internal array user_config the nick field is not
* specified, we warn the user and finish the script execution:
*/
if (!strlen($this->user_config['nick'])) {
trigger_error("Before call Connect(), you MUST set the connection ".
"options with SetOptions()n", E_USER_ERROR);
}
/*
* If we want to use SSL, we create the variable $tls_server which
* contains the connection URI, and increase the buffe size to 8192
* bytes to receive correctly the certificate
*/
if ($ssl == 1) {
$tls_server = "tls://".$server;
$this->buf_size = 8192;
}
/* Now we try to create the socket. If an error exists, returns -1 */
if ($ssl == 1) {
$this->sock = fsockopen($tls_server, $port);
} else {
$this->sock = fsockopen($server, $port);
}
if ($this->sock === FALSE) {
return -1;
}
/* We are connected!. If a PASSword is required and specified, we send it: */
if (strlen($pass)) {
$this->Send("PASS :".$pass."rn");
}
/* Now send the NICK */
$this->Send("NICK ".$this->user_config['nick']."rn");
/* And last, send the USER */
$user_string = "USER ".$this->user_config['nick']." ".$server;
$user_string .= " ".$server." :".$this->user_config['real'];
$this->Send($user_string);
/*
* Sets the internal var connected to 1 which means that we're
* connected, and returns it:
*/
$this->connected = 1;
return $this->connected;
}
/*
* Function...: Recv
* Task.......: Reads data from the socket
*
* Returns....: NULL if we are not connected
* Returns....: The text if it exists, or NULL otherwise
*/
public function Recv()
{
if ($this->IsConnected()) {
$text = fgets($this->sock, $this->buf_size);
return $text;
}
return null;
}
/*
* Function...: Disconnect
* Task.......: Disconnects from the server
*
* Returns....: 1 -> Connection was successfully closed
* Returns....: 0 -> Connection cannot be closed
*/
public function Disconnect()
{
if ($this->sock) {
if (fclose($this->sock)) {
$this->connected = 0;
return 1;
}
}
return 0;
}
/*
* Function...: Process
* Task.......: Process the IRC data received from the socket
*
* Param......: $text -> Text to be process (Optional, STRING)
*
* Returns....: 1 -> Data correctly parsed
* Returns....: 0 -> Data can't be parsed
*
* Explanation: This is the main routine. If the first parameter ($text) is
* not specified, it takes the stream calling Recv. When the
* data is being parsed, at first checks if a PING if received.
* In this case reply it with PONG and returns 1. If isn't a
* ping and isn't an error, continues parsing the stream.
*
* The stream is handly broken to strip necesara data to fill
* internal array cur_message, taking care and checking if we
* received a PRIVMSG or a NOTICE.
*/
public function Process($text)
{
/* If debugging is active, show the data to be parsed in the console */
if ($this->show_trans && strlen($text)) {
echo "[in] ".$text;
}
/* Before analice the text, we drop existings r and n */
$text = str_replace('r', '', $text);
$text = str_replace('n', '', $text);
/*
* If we are in connection stage or ping reply, the command does not
* starts with ':'. If is a PING, we reply it with PONG. If is an
* ERROR, returns 0. (This behavior can be change to die()).
*/
if ($text[0] && $text[0] != ":") {
if (strstr($text, "PING :")) {
$text[1] = "O";
$this->Send($text);
return 1;
/* Si ocurre un error, cerramos la conexion: */
} else if (strstr($text, "ERROR :")) {
$this->Disconnect();
$this->connected = 0;
die("exiting due an error!!n");
}
/*
* Well, is not a PING. And isn't util information... OK, OK,
* returns 1 :-).
*/
return 1;
}
/*
* If we are here, we have a server string to be parsed. The following
* code search for the FIRST ':', which marks the begin of the message
* and breaks it into ORIGIN and MESSAGE. Lets go.
*/
$space = strpos($text, " ") - 1;
$origin = substr(strstr($text, ':'), 1, $space);
$npos = strpos($text, ':', 1) + 1;
$texto = substr($text, $npos);
$texto = str_replace('r', '', $texto);
$texto = str_replace('n', '', $texto);
/* Stores the actual infromation into the array destined to do it: */
$numeric_destination = explode(" ", substr($text, $space + 2));
$this->cur_message['orig'] = $origin;
$this->cur_message['cmd'] = $numeric_destination[0];
$this->cur_message['dest'] = $numeric_destination[1];
$this->cur_message['text'] = $texto;
/*
* If numeric is "PRIVMSG" or "NOTICE", save into $cur_user the
* information of the SENDER
*/
if ($this->cur_message['cmd'] == ("PRIVMSG" || "NOTICE")) {
$text = explode(" ", $text); /* Strip spaces... */
$text = $text[0]; /* ...and process the util data */
$this->cur_user['host'] = substr(strrchr($text, "@"), 1);
$this->cur_user['nick'] = substr($text, 1, strpos($text, "!")-1);
$this->cur_user['identd'] = substr($text, strpos($text, "!") + 1,
(strpos($text, "@")) -
(strpos($text, "!") + 1));
}
}
/*
* Function...: GetCurrentText
* Task.......: Gets the current text in the internal data array
*/
function GetCurrentText()
{
if (isset($this->cur_message['text']))
return $this->cur_message['text'];
return NULL;
}
/*
* Function...: GetCurrentNumeric
* Task.......: Gets the current numeric in the internal data array
*/
function GetCurrentNumeric()
{
if (isset($this->cur_message['cmd']))
return $this->cur_message['cmd'];
return NULL;
}
/*
* Function...: GetCurrentOrigin
* Task.......: Gets the current origin in the internal data array
*/
function GetCurrentOrigin()
{
if (isset($this->cur_message['orig']))
return $this->cur_message['orig'];
return NULL;
}
/*
* Function...: GetCurrentDestination
* Task.......: Gets the current destination in the internal data array
*/
function GetCurrentDestination()
{
if (isset($this->cur_message['dest']))
return $this->cur_message['dest'];
return NULL;
}
/*
* Function...: GetCurrentNick
* Task.......: Gets the current nick in the internal data array
*/
function GetCurrentNick()
{
if (isset($this->cur_message['nick']))
return $this->cur_message['nick'];
return NULL;
}
/*
* Function...: GetCurrentHost
* Task.......: Gets the current host in the internal data array
*/
function GetCurrentHost()
{
if (isset($this->cur_message['host']))
return $this->cur_message['host'];
return NULL;
}
/*
* Function...: GetCurrentIdentd
* Task.......: Gets the current identd in the internal data array
*/
function GetCurrentIdentd()
{
if (isset($this->cur_message['identd']))
return $this->cur_message['identd'];
return NULL;
}
} ?>
|
|
|
Usage Example
|
|
|
Rate This Script
|
|
|
|