Время:
Новых сообщений: Нет
Вы на форуме дней
Ваша группа: Гость
Ваш IP: 18.227.26.171
Logical-Portal — молодежный портал со своей изюминкой, каждый сможет найти что-то интересное и полезное для себя, например наш форум общения с которым вам обязательно нужно ознакомиться.
  • Страница 1 из 1
  • 1
Архив - только для чтения
IRC bot (демон на php)
Сообщение оставлено 08.12.2010 в 07:28:02 | Сообщение #1
Предистория

Установил я значит как-то IRC сервер и радовались пользователи... Но захотели пользователи иметь возможность еще и логи читать (слово ж не воробей!).

Первым, что пришло в голову - запустить на сервере mIRC на постоянную и с него вести логи нужных каналов. Сказано - сделано. Однако не совсем удобно - постоянно держать законектеным mIRC. Вот тогда и зародилась идея о боте...

До этого я с IRC (и с ботами тем более) особо не сталкивался и потому пошел сразу в гугел. После 5 страниц полного бреда (как по моему) я нашел одну статейку (жаль урл не помню!) в которой была на мой взгляд самая что ни на есть ключевая фраза: "чтобы понять как общаются сервер и клиент можно включить в обычном mIRC опцию /debug on и все данные будут сохранятся в лог-файле". Дальше я не читал... Включив опцию, активно пообщавшись - за 2 часа у меня было достаточно информации.

Собственно скрипт бота (IRC Bot script):

Code


#!/usr/local/bin/php
<?php
// Параметры IRC сервера
$irc_server["ip"]='XXX.XXX.XXX.XXX';
$irc_server["port"]=6669;
$irc_server["name"]='irc.mine.net';

// Список каналов на которых будет присутствовать бот
$channels[0]="somechannel0";
$channels[1]="somechannel1";
$channels[2]="somechannel2";

// Таймер для отсчета времни чтобы выдать случайную фразу
$timer=0;

$privates=Array();

// Параметры бота
$bot["nick"]='PHP_Bot';
$bot["user"]='PHP_Bot';
$bot["host"]='bot.mine.net';
$bot["ip"]='XXX.XXX.XXX.XXX';
$bot["hz"]='PHP_Bot';

// Функция из мана используемая для получения "наиболее случайных чисел"
function make_seed() {
     list($usec, $sec) = explode(' ', microtime());
     return (float) $sec + ((float) $usec * 100000);
}

// Функция установки коннекта к IRC серверу
// Устанавливает начальный коннект
function connect_IRC () {
     global $irc_server, $bot, $fp;
     // Открываем сокет с заданым сервером и портом
     $fp = fsockopen($irc_server["ip"], $irc_server["port"], $errno, $errstr,30);
     $flag=0;
     // Вычитываем все что даст нам сервер, до ключевой фразы, после которой,
     // можно отсылать данные о пользователе
     while (!$flag && !feof($fp)) {
         $line=fgets ($fp);
         if (preg_match("/bFoundsyourshostnameb/", $line)) {
             $flag=1;
         }
     }
     // Пишем в сокет данные о авторизации бота
     fputs ($fp, sprintf ("NICK %sn", $bot["nick"]));
     fputs ($fp, sprintf ("USER %s "%s" "%s" :%sn",
                          $bot["user"], $bot["host"], $bot["ip"], $bot["hz"]));
     $flag=0;
     // Снова вычитываем все до ключевого номера 700, после которого можно
     // начинать заходить в каналы
     while (!$flag && !feof($fp)) {
         $line=fgets ($fp);
         if (preg_match("/b700b/", $line)) {
             $flag=1;
         }
     }
     // Возвращаем указатель на открытый сокет основной части
     return ($fp);
}

// Функция для подготовки вывода в канал
// одного из предопределенных случайных выражений
function is_time($chan) {
global $timer, $log_file, $bot;
     // Полный путь к текстовому файл в котором определены возможные выражения
     $texts=file('/home/myaccount/bot_conf/lyaps');
     $message='';
     $now=mktime(date ("H"), date("i"), date("s"), date ("m"),
                 date ("d"), date ("Y"));
     // Определяем интервал с которым бот будет что-то говорить в канал
     // (в этом примере - 10 минут)
     $time_to_say=mktime(date ("H"), date("i")-10, date("s"),
                         date ("m"), date ("d"), date ("Y"));
     // Если пора что-то говорить - формируем фразу,
     // если нет - возвращаем пустое значение
     if ($timer<$time_to_say) {
         // Сбрасываем таймер
         $timer=$now;
         // Определяем фразу
         srand(make_seed());
         $mess=rand(1, sizeof($texts));
         $texts[$mess]=trim($texts[$mess]);
         // Форматируем строку для отсылки серверу
         $message = sprintf ("PRIVMSG #%s :%sn",$chan,$texts[$mess]);
         // Если выражение не пустое пишем в лог
         if ($texts[$mess]!='') {
             $log_file='/home/myaccount/irc_log/#'.$chan.date("Ymd").'.log';
             $lf=fopen($log_file,"a");
             fputs ($lf, sprintf("[%s] <%s> %sn",
                          date("H:i"), $bot["nick"], $texts[$mess]));
             fclose ($lf);
         }
     }
     //Возвращаем подготовленую строку
     return ($message);
}

// Функция отсылки привествия для зашедших на канал пользователей
// берет одно из предопределенных приветствий и подставляет ник
function hello ($str) {
     global $bot;
     // Полный путь к текстовому файл в котором определены возможные выражения
     $texts=file('/home/myaccount/bot_conf/hello');
     // Определяем фразу
     srand(make_seed());
     $mess=rand(1, sizeof($texts));
     // Форматируем строку для отсылки серверу
     $message = sprintf ("PRIVMSG #%s :%s%s!n",$str[2],$texts[$mess], $str[1]);
     // Пишем в лог
     $log_file='/home/myaccount/irc_log/#'.$str[2].date("Ymd").'.log';
     $lf=fopen($log_file,"a");
     fputs ($lf, sprintf("[%s] <%s> %s%s!n",
                         date("H:i"), $bot["nick"], $texts[$mess], $str[1]));
     fclose ($lf);
     // Возвращаем подготовленую строку
     return ($message);
}

// Устанавливаем соединение с сервером
if ($sp=connect_IRC()) {
     reset ($channels); // Думаю что не нужен, но... на всяк пожарный
     while (list(,$channel_name)=each($channels)) {
         // Заходим во все определенные каналы
         fputs ($sp, sprintf("JOIN #%sn", $channel_name));
         fputs ($sp, sprintf("MODE #%sn", $channel_name));
         // Ниже бот берет на себя права оператора сервера, для этого
         // для него должны быть определены соответствующие настройки сервера
         // (см. документацию к серверной части)
         fputs ($sp, sprintf("OPER %s PHP_BOT_oper_passwordn", $bot["nick"]));
         fputs ($sp, sprintf("MODE %s +an", $bot["nick"]));
         fputs ($sp, sprintf("MODE %s +An", $bot["nick"]));
         fputs ($sp, sprintf("SAMODE #%s +o %sn", $channel_name, $bot["nick"]));
         // Определение регэкспов для отслеживания ключевых выражений
         // Вход пользователя на канал
         $joined[$channel_name]=
             '/:(.+)!.+sJOINs:#('.$channel_name.')/';
         // Сообщение от пользователя в канал
         $privmsg[$channel_name]=
             '/:(.+)!.+sPRIVMSGs#('.$channel_name.')s:(.+)/';
         // Выход пользователя с канала
         $partmsg[$channel_name]='/:(.+)!.+sPARTs#('.$channel_name.')/';
         // Установка темы канала
         $topic[$channel_name]=
             '/:(.+)!.+sTOPICs#('.$channel_name.')s:(.+)s/';
         // Отключение пользователя от сервера
         $quitmsg='/:(.+)!.+sQUITs:Quit:s(.*)s/';
         // Сообщение в приват боту
         $private_me='/:(.+)!.+sPRIVMSGs('.$bot["nick"].')s:(.+)/';
         // Смена ника юзером
         $nick='/:(.+)!.+sNICKs:(.+)s/';
     }
}

$flag=0;
// В принципе - бесконечный цикл (если не оборветься связь с сервером)
while (!$flag && !feof($fp)) {
$line=fgets($sp);
reset($joined);
// Проверяем - если идет команда PING от сервера - отвечаем PONG
$ping='/^(PING)b/';
if (preg_match($ping, $line)) {
     fputs ($fp, "PONG :".$irc_server["name"]."n");
}
else {
// Флаг для определения того что бот уже нашел ключевую фразу
     $stop=0;
     // Запускаем цикл по всем нужным каналам
     while ((list($keys, $values)=each($joined)) && !$stop) {
          // Проверяем не время ли сказать чего-нибудь в канал
         $str_=is_time($keys);
         fputs($fp, $str_);
         // Проверка на вход кого-либо на канал
         if (preg_match($joined[$keys], $line, $matches)) {
            $stop=1;
            if ($matches[1]!=$bot["nick"]) {
                    // Пишем в лог
                 $log_file='/home/myaccount/irc_log/#'.
                             $matches[2].date("Ymd").'.log';
                 $lf=fopen($log_file,"a");
                 fputs ($lf, sprintf("[%s] * <%s> вошел на канал %sn",
                             date("H:i"$matches[1], $matches[2]));
                 fclose ($lf);
                 // Получаем строку приветствия
                 $str_=hello($matches);
                 // Отсылаем фразу серверу
                 fputs ($fp, $str_);
             }
         }
         else {
             // если это просто фраза в канал, либо в приват боту
             if (!preg_match($action[$keys], $line, $matches)
                 && (preg_match($privmsg[$keys], $line, $matches)
                    || preg_match($private_me, $line, $matches))) {
                     $stop=1;
                     // Отсылаем функции обработки сообщений
                     // не рассматривается (в данной статье)
                     $str_=analyze_msg($matches);
                     // Выводим результат
                     fputs ($fp, $str_);
                 }
                 else {
                 // Если пользователь покинул канал
                 if (preg_match($partmsg[$keys], $line, $matches)) {
                     // Просто пишем в лог
                     $log_file='/home/myaccount/irc_log/#'.
                    $matches[2].date("Ymd").'.log';
                     $lf=fopen($log_file,"a");
                     fputs ($lf, sprintf("[%s] * <%s> покинул канал %sn",
                    date("H:i"), $matches[1], $matches[2]));
                     fclose ($lf);
                     }
                     else {
                         // Если пользователь покинул сервер
                         if (preg_match($quitmsg, $line, $matches)) {
                             // Просто пишем в лог
                             $log_file='/home/myaccount/irc_log/#'.
                    $keys.date("Ymd").'.log';
                             $textq='';
                             // Определяем причину выхода (если указана)
                             if (trim($matches[2])!='') {
                    $textq="(".trim($matches[2]).")";
                             }
                             $lf=fopen($log_file,"a");
                             fputs ($lf, sprintf(
                    "[%s] * <%s> покинул IRC сервер %sn",
                    date("H:i"), $matches[1], $textq));
                             fclose ($lf);
                         }
                         else {
                             // Если пользователь сменил ник
                             if (preg_match($nick, $line, $matches)) {
                    // Пишем в лог
                    $log_file='/home/myaccount/irc_log/#'.
                    $keys.date("Ymd").'.log';
                    $lf=fopen($log_file,"a");
                    fputs ($lf, sprintf("[%s] * %s взял имя %sn",
                    date("H:i"),
                    $matches[1],
                    $matches[2]));
                    fclose ($lf);
                             }
                             else {
                    // Если установлена тема
                    if (preg_match($topic[$keys],$line,$matches)) {
                    // Пишем в лог
                    $log_file='/home/myaccount/irc_log/#'.
                    $keys.date("Ymd").'.log';
                    $lf=fopen($log_file,"a");
                    fputs ($lf, sprintf("............",
                    date("H:i"),
                    $matches[1],
                    $matches[3]));
                    fclose ($lf);
                    }
                             }
                         }
                     }
                 }
             }
         }
     }
// Пауза 1 сек. - чтобы меньше грузить сервер
sleep(1);
}
// Закрытие сокета
fclose ($sp);
?>

Ключевые моменты

Все отсылаемые команды должны обязательно заканчиваться символом конца строки "n".

Файлы в которых храняться варианты приветствий и пр. - просто текстовые файлы, каждая отдельная фраза с новой строки. На эти файлы у пользователя под которым запускается бот должны минимально быть права на чтение.

Заключение

Вот вроде бы и все... Разбирая фразы - можно добавлять боту любую свою логику... В ближайшее время намереваюсь выложить скрипт для форматирования логов в HTML, хотя... надо ли? Это настолько очевидно...

 

У гениальности есть побочные эффекты
 
   
  • Страница 1 из 1
  • 1
Поиск:
 
Графика от: Megas, GraFOS | Дизайн сверстал E.A.
Хостинг от uCoz
Яндекс.Метрика