Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <? /***************************************/
- /************* 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
- // Tirando timeout
- set_time_limit(0); ?><font face="Verdana" size="2"><?
- // Criando a classe e setando as variaveis
- $bot=@new bot;
- $bot->senha = "chester1"; // Senha do nickserv. deixe vazio ("") para não identificar
- $bot->server = "irc.freenode.net"; // 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 = "#ecart"; // 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 = true; // 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>
Add Comment
Please, Sign In to add comment