Zend - The PHP Company




Chat

Add Code


IRC Client class (RFC1459 Compliant)  

Type: class
Added by: daijo
Entered: 06/12/2005
Last modified: 02/12/2005
Rating: - (fewer than 3 votes)
Views: 3474
This class allows to connect to an IRC server (including SSL). With it you can make easily IRC bots.


<?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($text1strpos($text"!")-1);
            
$this->cur_user['identd'] = substr($textstrpos($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





Search



This Category All Categories