IRCbot

Publicado por Perfil removido 25/01/2004

[ Hits: 8.712 ]

Download ircbot.php




O IRCbot 1.1 é um bot para IRC criado por Matheus Meira utilizando linguagem PHP. O
IRCbot tem funções básicas como op, deop, voice, devoice, ban, kick, etc.
  
O código está todo comentado, detalhando como funciona todas as inúmeras funções. Ideal
para quem deseja aprender o funcionamento de um bot em PHP.

  



Esconder código-fonte

<? /***************************************/
   /************* IRCbot 1.1 **************/
   /** por infos (infos@superig.com.br) ***/
   /***************************************/
   /***** idéia original por ShadowMan ****/
   /***************************************/
   /*          Futuras adesões:           */
   /* Melhoramento nos Timers             */
   /* Melhoramento no tratamento das RAWS */
   /* Sistema de usuários em Mysql        */
   /* Comando !ping                       */
   /* Tratamento aos CTCPs                */
   /***************************************/

/*
      Adesões

1.1
- Feito comando timer (não ficou bom, mas foi o melhor que deu para fazer)
- Opção para exibir log no browser ou não (se exibir log no browser o bot só se mantém conectado enquanto o browser estiver aberto, bom para ver erros, se não exibir o log, o bot fica conectado mesmo depois de feixar o browser)
- Melhorado o sistema visual (agora com cores)

1.0
- Feito todos os sistemas básicos
- Feito comando para adicionar ativadores
- Adicionado funções básicas como op, deop, kick, etc.
- Feito sistema visual (tanto no navegador quanto nos logs)

      À corrigir:
- comando emote();
*/

// os comandos prontos são para voces se familiarizarem com o bot e estão prontos para serem utilizados
// ps: altere a linha nº 207 com o Nick!User_Name@end correto do nickserv da sua rede.

// Tirando timeout
set_time_limit(0); ?><font face="Verdana" size="2"><?
// Criando a classe e setando as variaveis
$bot=@new bot;
$bot->senha = "uma_senha";            // Senha do nickserv. deixe vazio ("") para não identificar
$bot->server = "irc.servidor.com.br";   // Servidor
$bot->porta = 6667;                  // porta
$bot->owner = "owner";               // nick do owner
$bot->me = "bot";                  // nick do bot
$bot->username = "phpbot";            // username do bot (nick!username@end)
$bot->realname = "PHPbot por infos";   // nome do bot
$bot->canais = "";                  // canais para entrar ao conectar
$bot->quitmsg = "Requested.";         // mensagem padrão de quit
$bot->modes = "+p";                  // Modos postos pelo bot ao conectar.. deixe vazio ("") para não setar
$bot->reconectar = true;            // reconectar ao perder conexão?
$bot->visual = false;               // Bot com visual?
                              // quando true: o navegador mostrará o log de tudo que o bot recebe do servidor/do que o bot envia para o servidor, o bot só permanece conectado enquanto o navegador estiver aberto. o bot também loga tudo no arquivo bot.log. ideal para ser utilizado ao fazer alterações no bot (ver erros).
                              // quando false: o log das ações enviadas para o servidor e recebidas pelo mesmo só são postas no arquivo bot.log. o bot é executado mesmo quando o navegador está fechado.
class bot {
   function conectar() {
      // abre o socket, dá erro de falhar
      $this->fp=@fsockopen($this->server ,$this->porta,$erro,$ermsg) or die("Erro ao abrir o socket. Erro $erro: $ermsg ".$this->server.":".$this->porta."</font>");
      if ($this->visual) {
         echo "Conectado...";
         flush();
      }
   }
   function logar() {
      // seta o username, modo de usuário e realname
      $this->enviar("USER ".$this->username." 0 * :".$this->realname);
      // seta o nick
      $this->enviar("NICK ".$this->me);
      // identifica o nick
      if ($this->senha != "") $this->enviar("nickserv identify ".$this->senha);
      // se foi especificado algum modo, ele seta
      if ($this->modes != "") $this->enviar("MODE ".$this->me." ".$this->modes);
   }
   function desconectar() {
      // Fui desconectado
      // Tira a flags pra reconectar (?) exibe desconectar no log e no navegador
      $this->log("-> Desconectado", "","<br>");
      fclose($this->fp); fclose($this->log);
   }
   function quit($q = null) {
      // idem ao de cima, porém ele aqui solicita a desconexão.. e exibe a mensagem de quit padrão se não for especificada..
      $this->reconectar=false;
      if ($q != null) $this->enviar("QUIT :".$q);
      else $this->enviar("QUIT :".$this->quitmsg);
      sleep(1);
      fclose($this->fp); fclose($this->log); die("</font>");
   }
   function enviar($texto) {
      // envia um comando ao servidor, e chama o comando pra logar a mensagem
      fputs($this->fp, $texto."\r\n");
      $this->log("-> ".$texto);
   }
   function log($texto, $pre = "", $suf = "") {
      // exibe o parametro no log e no navegador
      // $pre eh para ser utilizado coisas como, cores, etc..
      // $suf para fechar as tags
      fwrite($this->log,$texto."\n");
      if ($this->visual) {
         echo "<br>".$pre."(".date("H:i:s").") ".$texto.$suf;
         flush();
      }
   }
   function rodar() {
      // enquanto tiver setado para permanecer o bot conectado
      while ($this->reconectar) {
         // abre o log
         $this->log=fopen('Bot.log','a');
         // conecta
         $this->conectar();
         sleep(1);
         // envia os parametros da conexão
         $this->logar();
         // entra nos canais especificados automaticamente
         $this->join($this->canais);
         $timea=time(); // para o timer (leia sobre ele mais em baixo)

         // Seta o timeout da conexão pra 5 minutos (se ele não receber nada do servidor em 5 minutos ele desconecta o socket). o default é 1 minuto (ele recebe o PING do servidor pelo menos 1 vez a cada 5 minutos com certeza, por isso setei um valor alto)
         stream_set_timeout($this->fp,300);

         // enquanto a conexão estiver ativa, pega o texto recebido
         while (!feof($this->fp)) {
            $t=fgets($this->fp);
            // limpa as quebras de linha
            $t=trim($t);
            // divide ele num array para tratamento
            $q=explode(" ",$t);
            // pega o host do user (user!username@address)
            $host=substr($q[0],1);
            // pega o host
            $nick=explode("!",$host);
            $nick=$nick[0];
            // seta vazio para não pegar valores passados
            $msg="";
            // se o parametro for notice ou privmsg (mensagem)
            if (($q[1] == "NOTICE") || ($q[1] == "PRIVMSG")) {
               // se for canal, seta o nome do canal
               if (substr($q[2],0,1) == "#") $onde=$q[2];
               // se for pvt, seta pvt
               else $onde="PVT";
            }
            // se nao for mensagem ou notice, seta NONE pra não chamar o evento que vai ver se tem algum comando "chamado"
            else $onde="NONE";
            // limpa a string (?)
            $q[3]=trim($q[3]);
            // se a string tiver : no início, ele tira (parametros com mais de 1 palavra vem precedidos de ":")
            if (substr($q[3],0,1) == ":") $q[3]=substr($q[3],1);
            // $q[3] no caso seria !join em "!join canal balblabla"

            // para x=4 (início dos parametros) até o fim dele, seta tudo numa variavel
            for ($x=4;$x <= count($q);$x++) $msg .= " ".$q[$x];
            // limpa a mensagem de espaços e quebras de linha (eles ocorrerão)
            $msg=trim($msg);
            // mensagem total..
            $msgt = trim($q[3]." ".$msg);

            // INÍCIO DO TIMER (leia abaixo nos comandos sobre ele..)
            // $timea é a ultima vez que eu recebi um pacote! (se voce leu sobre ele abaixo, saberá do que se trata)
            // entao eu vou testando segundo por segundo o $timea até o time() atual
            // buscando ver todos os timers (inclusive os atrazados..)
            for($time=time();$timea <= $time; $timea++) {
               // como todo array tem que começar com uma letra, a + tempo_procurado é o valor do array que eu vou buscar
               $timeb="a".$timea;
               // Para cada valor do array
               foreach($this->vtimer as $chave => $ok) {
                  // se o nome da chave for igual ao tempo procurado
                  if ($chave == $timeb) {
                     // executamos os comandos pedidos...
                     foreach ($ok as $comando) {
                        $this->$comando();
                     }
                  }
               }
               // apagamos a variavel para não gastar memoria atoa..
               unset($this->vtimer[$timeb]);
            }
            // tempo do ultimo pacote para usar no timer
            $timea=time();
             
            // Início da parte de logs (no navegador e arquivo)

            // EVENTO JOIN
            if ($q[1] == "JOIN") $this->log("--> Entrou ".substr($q[2],1).": ".$nick." (".$host.")","<font color=\"red\">","</font>");

            // EVENTO PART
            elseif ($q[1] == "PART") $this->log("--> Saiu ".$q[2].": ".$nick." (".$host.")","<font color=\"red\">","</font>");

            // O servidor manda eventos "NOTICE" simples.. como NOTICE :*** AUTH blablabla..
            // loga normalmente como vem do servidor
            elseif ($q[0] == "NOTICE") $this->log($t);
            // Se for setado algum modo
            elseif ($q[1] == "MODE") $this->log("---> MODE ".$q[2]." ".$q[3]." ".$msg);
            // Se alguém muda de nick
            elseif ($q[1] == "NICK") $this->log("---> ".$nick." mudou o nick para: ".substr($q[2],1));
            // Se alguém desconectou
            elseif ($q[1] == "QUIT") $this->log("---> QUIT ".$nick.": ".substr($t,strpos($t,"QUIT")+6),"<font color=\"gray\">","</font>");
            // Se foi mudado o topico
            elseif ($q[1] == "TOPIC") $this->log("---> ".$nick." mudou o topico de ".$q[2]." para: ".$msgt);
            // Se foi recebida alguma mensagem (sintaxe: [nick\onde] texto) onde "onde" é PVT ou o nome do canal
            elseif ($q[1] == "PRIVMSG") $this->log("(".$nick."\\".$onde.") ".$msgt,"<font color=\"blue\">","</font>");
            // Se foi recebido algum notice (sintaxe: [nick\onde] texto) onde "onde" é PVT ou o nome do canal
            elseif ($q[1] == "NOTICE") $this->log("[".$nick."\\".$onde."] ".$msgt,"<font color=\"blue\">","</font>");
            // Se mensagem total for vazia [lembrem-se que mensagemT é setado quando agente recebe uma mensagem ou notice, tendo a mensagem completa (e somente ela)] ele joga no log como uma função do server não catalogada..
            elseif (trim($msgt) == "") $this->log("-SERVER- ".$t);
            // mensagens do servidor normais (outras raws, motd, etc)
            else $this->log("-SERVER- ".$msgt);
            // se recebi um PING (mensagem do servidor pra ver se o cliente esta ativo e não caiu) ele manda sua resposta
            if ($q[0] == "PING") $this->enviar("PONG ".$q[1]);
            // Identifique o nick, caso o nickserv peça
            if (($host == "NickServ!services@brasnet.org") && ($this->senha != "") && (strtoupper($msgt) == strtoupper("Este nick esta registrado e protegido.  Se o nick pertence"))) $this->enviar("nickserv identify ".$this->senha);
            // se $ONDE for diferente de none (onde eh none quando o texto recebido não é de mensagem ou notice)
            if ($onde != "NONE") {
               // verifica aqui se o comando "pego" ($q[3]) existe na lista de comandos a executar uma função..
               $array=$this->comandos[strtoupper($q[3])];
               $ondec=$this->comandos[strtoupper("onde".$q[3])];
               if ((strtoupper($onde) == strtoupper($ondec)) || (substr(strtoupper($onde),0,1) == strtoupper($ondec)) || (strtoupper($ondec) == "ALL")) $this->$array($nick, $host, $msg, $msgt, $onde);
               // (acima) se para o comando, existir uma função, ela é chamada
            }
            // Seta o timeout da conexão pra 5 minutos (se ele não receber nada do servidor em 5 minutos ele desconecta o socket). o default é 1 minuto (ele recebe o PING do servidor pelo menos 1 vez a cada 5 minutos com certeza, por isso setei um valor alto)
            stream_set_timeout($this->fp,300);
         }

         // Fui desconectado!
         $this->desconectar();
      }
   }
   function novocmd($cmd = null, $ativ = null, $onde = "all") {
      // Função que adiciona os comandos à "lista de comandos a executar uma função"
      // se existir um comando E um ativador
      if (($cmd != null) && ($ativ != null)) {
         // $x recebe $this (objeto, @new bot) e o comando
         $x=array($this,$cmd);
         // se a função existe (para evitar futuros erros..) ele adiciona no array da lista de funções
         if (is_callable($x,false)) $this->comandos=array_merge($this->comandos, array(strtoupper($ativ) => strtoupper($cmd), strtoupper("onde".$ativ) => strtoupper($onde)));
         // Se não existir, ele cancela o processo pra evitar erros futuros
         else die("Você não pode definir um comando com uma função inexistente! (função: ".$cmd.")</font>");
      }
      else $this->log("Erro na adição de um novo comando! -COMANDO IGNORADO- Comando a ser executado: ".$cmd." Ativador: ".$ativ);
   }
   function timer($cmd = null, $tempo = null) {
      if (($cmd != null) && ($tempo != null) && (is_int($tempo))) {
         $x=array($this,$cmd);
         $tempo = (string) "a".intval($tempo+time());
         if (is_callable($x,false)) {
            $this->vtimer=array_merge($this->vtimer, array($tempo => array_merge($this->vtime[$tempo], array($cmd))));
         }
         else die("Você não pode definir um comando com uma função inexistente! (função: ".$cmd.")</font>");
      }
      else $this->log("Erro no timer! -TIMER IGNORADO- Comando a ser executado: ".$cmd);
   }

   // funções básicas..
   // Sintaxe delas: $onde $quem/$msg/$host/$nick/$canais $modo $tipo
   // nem todas recebem todas as variaveis..
   function msg($onde = null, $msg = null) {
      // se existir um lugar e existir uma mensagem
      // envia a mensagem para o lugar
      if (($onde != null) && ($msg != null)) $this->enviar("PRIVMSG ".$onde." :".$msg);
   }
   function emote($onde = null, $msg = null) {
      // se existir um lugar e existir uma mensagem
      // envia a ação para o lugar
      if (($onde != null) && ($msg != null)) $this->enviar("PRIVMSG ".$onde." :ACTION".$msg);
   }
   function notice($onde = null, $msg = null) {
      // se existir um lugar e existir uma mensagem
      // envia a mensagem para o lugar
      if (($onde != null) && ($msg != null)) $this->enviar("NOTICE ".$onde." :".$msg);
   }
   function op($onde = null, $quem = null) {
      // se existir o lugar e alguém
      // dá op para o usuário no canal especificado
      if (($onde != null) && ($quem != null)) $this->mode($onde, $quem, "-v");
   }
   function deop($onde = null, $quem = null) {
      // se existir o lugar e alguém
      // tira o op do usuario no canal especificado
      if (($onde != null) && ($quem != null)) $this->mode($onde, $quem, "-v");
   }
   function voice($onde = null, $quem = null) {
      // se existir o lugar e alguém
      // dá voice para o usuário no canal especificado
      if (($onde != null) && ($quem != null)) $this->mode($onde, $quem, "-v");
   }
   function devoice($onde = null, $quem = null) {
      // se existir o lugar e alguém
      // tira o voice do usuario no canal especificado
      if (($onde != null) && ($quem != null)) $this->mode($onde, $quem, "-v");
   }
   function ban($onde = null, $host = null) {
      // se existir o lugar e alguém
      // bane a !!MASCARA!! do canal
      if (($onde != null) && ($quem != null)) $this->mode($onde, $quem, "+b");
   }
   function nick($nick) {
      // se o nick desejado for diferente do atual, muda..
      if (($nick != null) && (strtoupper($nick) != strtoupper($this->me))) $this->enviar("NICK ".$nick);
   }
   function kick($onde = null, $quem = null, $motivo = "Requested") {
      // se existir o local e a pessoa
      // kicka ela do canal com o motivo solicitado (ou o padrao)
      if (($onde != null) && ($quem != null)) $this->enviar("KICK ".$onde." ".$quem." :".$motivo);
   }
   function join($canais = "") {
      // se existir os canais
      // entra em todos os canais separados por um " " (espaço)
         if ($canais != "") {
            $canais=explode(" ",$canais);
            foreach($canais as $x) $this->enviar("JOIN ".$x);
         }
   }
   function part($canais = "") {
      // se existir os canais
      // sai de todos os canais separados por um " " (espaço)
         if ($canais != "") {
            $canais=explode(" ",$canais);
            foreach($canais as $x) $this->enviar("PART ".$x);
         }
   }
   function mode($onde = null, $quem = null, $modo = null, $tipo = 0) {
      // $tipo = 0 quando eu vou setar todos os "+b-x+z" pela variavel $modo
      // $tipo = 1 (default) eu vou utilizar $modo = "+b"
      // e $quem = "eu1 eu2 eu3"
      // e a funcao vai, automaticamente, ir setando os outros "+b" para todos da lista.. (soh funciona pra setar um unico modo..)
      // se existir lugar, alguem e modo
      if (($onde != null) && ($quem != null) && ($modo != null)) {
         // se os modos ja estao setados pela variavel $modo, seta os modos
         if ($tipo == 0) $this->enviar("MODE ".$onde." ".$modo." ".$quem);
         // se nao, ele ve quantos usuarios sao, e executa o modo em todos..
         else {
            $qtd=explode(" ",$quem);
            $qtd=count($qtd);
            $this->enviar("MODE ".$onde." ".$modo.str_repeat(substr($modo,1,1), $qtd-1)." ".$quem);
         }
      }
   }

   // comandos pré-definidos,  veja abaixo do que se trata
   function _mensagem($nick, $host, $msg, $msgt) {
      if (strtoupper($nick) == strtoupper($this->owner)) $this->msg("#aow_shard",$msg);
   }
   function _emote($nick, $host, $msg, $msgt) {
      if (strtoupper($nick) == strtoupper($this->owner)) $this->emote("#aow_shard",$msg);
   }
   function _op($nick, $host, $msg, $msgt, $onde) {
      if (strtoupper($nick) == strtoupper($this->owner)) $this->mode($onde, $nick, "+o");
   }
   function _part($nick, $host, $msg, $msgt) {
      if (strtoupper($nick) == strtoupper($this->owner)) $this->part($msg);
   }
   function _join($nick, $host, $msg, $msgt) {
      if (strtoupper($nick) == strtoupper($this->owner)) $this->join($msg);
   }
   function _nick($nick, $host, $msg, $msgt) {
      if (strtoupper($nick) == strtoupper($this->owner)) $this->nick($msg);
   }
   function _quit($nick, $host, $msg = null, $msgt) {
      if (strtoupper($nick) == strtoupper($this->owner)) {
      if ($msg != "") $this->quit($msg);
      else $this->quit($this->quitmsg); }
   }
   function __msg1() {
      return "msg1;
   }
   function __msg2() {
      return "msg2;
   }
   function __msg3() {
      return "msg3";
   }
   function __msg4() {
      return "msg4";
   }
   function __msg5() {
      return "msg5";
   }
   function __msg6() {
      return "msg6";
   }
   function __msg7() {
      return "msg7";
   }
   function _taow() {
      $cmd="__msg".rand(1,7);
      $this->msg("#canal", $this->$cmd());
      $this->timer("_taow", 300);
   }
}
// Adiciona novos comandos
// sintaxe novocmd(funcao a ser chamada, ativador, onde);
// se onde nao for especificado, é chamado em todos os lugares (canais e pvts)
// se onde = pvt, só é chamado no pvt
// se onde = #canal, só é chamado no canal em questão
// se onde = #, é chamado em qualquer canal
// a funcao deve ser criada na classe BOT para que funcione corretamente
// e deve ser declarada antes da função rodar()
// TODAS as funcoes devem receber como parâmetros:
// $nick, $host, $msg, $msgt, $onde
// ex: function _funcao($nick, $host, $msg, $msgt, $onde)
$bot->novocmd("_mensagem","!msg","pvt");
$bot->novocmd("_emote","!me","#canal");
$bot->novocmd("_quit","!quit");
$bot->novocmd("_part","!part");
$bot->novocmd("_nick","!nick");
$bot->novocmd("_op","!op","#");
$bot->novocmd("_join","!join");

// Breve descrição sobre o timer:
// O timer PERFEITO em php neste caso é algo meio impossível de se fazer
// Pois o PHP não suporta threads e não posso fazer 2 whiles rodar em paralelo...
// Um, no caso fazendo o papel do timer e o outro o papel do bot
// Porquê não fez tudo junto e deu certo?
// Simples! A função utilizada para receber um dado (socket) pára a execução do script
// até receber algum dado.. Ou seja, ele pode demorar 1 segundo para receber um dado
// do servidor, assim como pode demorar 5 minutos...
// Felizmente eu utilizei o artifício do servidor mandar em intervalos de cerca de 2 minutos
// o dado "PING" (pelo tempo que eu verifiquei na ocasiao era isto, agora verificando melhor,
// pode ser muito maior que 5 segundos, bem variavel) para verificar se o cliente
// está conectado e assim consigo fazer um timer "que atraza"
// Então eu fiz uma simulação de timer.. Como funciona?
// Depois de X -SEGUNDOS-, assim que o BOT receber um dado do servidor, ele VAI
// executar o comando desejado no timer.. Sendo esse tempo de, no máximo, o valor de
// intervalo entre 2 "PING"s enviados pelo servidor.. esse tempo varia, mas não muito
// Ainda não foi implementado algo que faça o timer rodar por X vezes (ou infinitamente)..
// mas é algo facilmente adicionavel.. é só fazer que a função chamada no timer chame
// outro timer....
// IMPORTANTE: o timer é chamado -ANTES- de verificar se a mensagem tem algum comando..
// Assim, se o timer atrazar, e você tiver um timer que cancele um comando, poderá
// faze-lo normalmente..

// neste exemplo, depois de 60 segundos ele ativa um timer que fala
// algo aleatorio no canal a cada 5 minutos
$bot->timer("_taow", 60);


$bot->rodar();
$bot->desconectar();
?></font>

Scripts recomendados

Busca por Dominio .com .net e .org

adm pure-ftp+mysql

Pegando tweets de forma simples

Leitor de RSS O.O.

Geração de códigos captcha em formulários HTML com PHP e PostgreSQL


  

Comentários

Nenhum comentário foi encontrado.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts