::: PHP.com.ua - учимся вместе. ::: ::: PHP.com.ua - учимся вместе. :::



 
   - GEO_IP (?)
  - Продаж трафіка (платні лінки)
  - Вакансия PHP-программист, Днепропетровск...
  - Проблема с передачей переменной в PHP ск...
  - Как хранить конфигурацию cms'ки?
  - Проблема с сортировкой массива
  - коллизии md5


Главная
Новости
Статьи
Шпаргалки
Файлы
О проекте
Форум
Футболки


FREEhost.com.ua - купил хостинг 10 у.е. на Begun в подарок.

iName.com.ua - регистрация доменных имен и хороший хостинг.

Библиотека программиста - нужный вам исходник или документация по необходимому для вас языку программирования.

Designclub - Клуб дизайнеров Украины.

Регистрация доменов
Хостинг

 HowtoForge.ORG.UA - Это первый Украинский ресурс развития open source программного обеспечения


Путь: Статьи > Готовые решения

Готовые решения

Автор: - Crocodile
Дата публикации - 11.5.2005
Просмотров: - 10833

IRC bot (демон на php)


[p]Предистория[/p]

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

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

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

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

[php]
#!/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("/\bFound\syour\shostname\b/"$line)) {
            
$flag=1;
        }
    }
    
// Пишем в сокет данные о авторизации бота
    
fputs ($fpsprintf ("NICK %s\n"$bot["nick"]));
    
fputs ($fpsprintf ("USER %s \"%s\" \"%s\" :%s\n",
                         
$bot["user"], $bot["host"], $bot["ip"], $bot["hz"]));
    
$flag=0;
    
// Снова вычитываем все до ключевого номера 700, после которого можно
    // начинать заходить в каналы
    
while (!$flag && !feof($fp)) {
        
$line=fgets ($fp);
        if (
preg_match("/\b700\b/"$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")-10date("s"),
                        
date ("m"), date ("d"), date ("Y"));
    
// Если пора что-то говорить - формируем фразу,
    // если нет - возвращаем пустое значение
    
if ($timer<$time_to_say) {
        
// Сбрасываем таймер
        
$timer=$now;
        
// Определяем фразу
        
srand(make_seed());
        
$mess=rand(1sizeof($texts));
        
$texts[$mess]=trim($texts[$mess]);
        
// Форматируем строку для отсылки серверу
        
$message sprintf ("PRIVMSG #%s :%s\n",$chan,$texts[$mess]);
        
// Если выражение не пустое пишем в лог
        
if ($texts[$mess]!='') {
            
$log_file='/home/myaccount/irc_log/#'.$chan.date("Ymd").'.log';
            
$lf=fopen($log_file,"a");
            
fputs ($lfsprintf("[%s] <%s> %s\n",
                         
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(1sizeof($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 ($lfsprintf("[%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 ($spsprintf("JOIN #%s\n"$channel_name));
        
fputs ($spsprintf("MODE #%s\n"$channel_name));
        
// Ниже бот берет на себя права оператора сервера, для этого
        // для него должны быть определены соответствующие настройки сервера
        // (см. документацию к серверной части)
        
fputs ($spsprintf("OPER %s PHP_BOT_oper_password\n"$bot["nick"]));
        
fputs ($spsprintf("MODE %s +a\n"$bot["nick"]));
        
fputs ($spsprintf("MODE %s +A\n"$bot["nick"]));
        
fputs ($spsprintf("SAMODE #%s +o %s\n"$channel_name$bot["nick"]));
        
// Определение регэкспов для отслеживания ключевых выражений
        // Вход пользователя на канал
        
$joined[$channel_name]=
            
'/:(.+)\!.+\sJOIN\s:\#('.$channel_name.')/';
        
// Сообщение от пользователя в канал
        
$privmsg[$channel_name]=
            
'/:(.+)\!.+\sPRIVMSG\s\#('.$channel_name.')\s:(.+)/';
        
// Выход пользователя с канала
        
$partmsg[$channel_name]='/:(.+)\!.+\sPART\s\#('.$channel_name.')/';
        
// Установка темы канала
        
$topic[$channel_name]=
            
'/:(.+)\!.+\sTOPIC\s\#('.$channel_name.')\s:(.+)\s/';
        
// Отключение пользователя от сервера
        
$quitmsg='/:(.+)\!.+\sQUIT\s:Quit:\s(.*)\s/';
        
// Сообщение в приват боту
        
$private_me='/:(.+)\!.+\sPRIVMSG\s('.$bot["nick"].')\s:(.+)/';
        
// Смена ника юзером
        
$nick='/:(.+)\!.+\sNICK\s:(.+)\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 ($lfsprintf("[%s] * <%s> вошел на канал %s\n",
                            
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 ($lfsprintf("[%s] * <%s> покинул канал %s\n",
                                 
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 ($lfsprintf(
                                        
"[%s] * <%s> покинул IRC сервер %s\n",
                                         
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 ($lfsprintf("[%s] * %s взял имя %s\n",
                                        
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 ($lfsprintf("............",
                                        
date("H:i"),
                                        
$matches[1],
                                        
$matches[3]));
                                    
fclose ($lf);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
// Пауза 1 сек. - чтобы меньше грузить сервер
sleep(1);
}
// Закрытие сокета
fclose ($sp);
?>
[

/php]

[p]Ключевые моменты[/p]

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

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

[p]Заключение[/p]

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



Обсудить в ФОРУМе - комментариев ()


Путь: Статьи > Готовые решения

Если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Контакты Design by webFaction Ukrainian PHP Group 2004-2005