IRCbot

Publicado por Perfil removido 25/01/2004

[ Hits: 8.574 ]

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

WebLog - Logs do linux via web

Formatação de preço

Contador de tempo de carregamento

Relogio Digital

Sistema para postar fotos


  

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