PHP работа с ICQ (php bot icq)


Сегодня я бы хотел поговорить о том, как можно легко работать с ICQ на языке PHP.

Это порой бывает очень полезно. Используя свою фантазию, можно написать много полезностей для своего сайта. Например для управления сервером или сайтом через аську. Вы можете просто отправлять заранее запрограммированные команды, например отключить какой-нибудь товар с интернет-магазина, через icq и получать в ответ отчеты о работе.

Рассмотрим мы взаимодействие PHP и ICQ на реальном примере. Попробуем написать программу шпаргалок на ICQ. Разобрав её, вы без труда сможете её переделать для выполнения любых задач.
Суть программы будет заключаться в следующем:

  1. Заливаем на сервер файл .txt со списком вопросов и ответов в заранее определённом формате (например разделяя вопрос от ответа каким-нибудь разделителем)
  2. Программа будет прогружать этот файл в массив
  3. При отправлении нашему боту (назовем его так) команды например «list», программа должна нам отправить пронумерованный список вопросов
  4. При отправке номера вопроса, мы должны получить на него ответ

В общих чертах должно быть как-то так.

И так, приступим!

Для работы ICQ в PHP нам нужен специальный класс WebIcqPro. Скачать его можно на сайте разработчика http://wip.asminog.com/. Данный класс написан специально для взаимодействия с протоколом OSCAR. Его функционал постоянно расширяется, поэтому стоит следить за обновлениями.

Сейчас подумаем над синтаксисом текстового файла с вопросами/ответами.

Самый простой вариант для этого – это писать в каждой строчке по вопросу, затем разделитель (например тройное двоеточие «:::»), а затем уже ответ. Получаем по вопросу (ответу) в строчку. Накидаем тестовый файл vopros.txt.

Вопрос 1:::Ответ 1
Вопрос 2:::Ответ 2
Вопрос 3:::Ответ 3
Вопрос 4:::Ответ 4
Вопрос 5:::Ответ 5
Вопрос 6:::Ответ 6
Вопрос 7:::Ответ 7

Тут все понятно. Теперь разберёмся с самой программой. 

В скаченном вами с сайта архиве, вы можете найти файл bot.php. Это тестовый пример для работы бота. В нем есть основной функционал этого класса. На его базе и напишем нашего бота. Все лишнее удалим, недостающее добавим. В результате я получил следующий шаблон:

<?
ini_set("max_execution_time", 0);
error_reporting(E_ALL);

define('UIN', '*********');
define('PASSWORD', '*********');
define('ADMINUIN', '*********');

$help = "
\t    Bot commands:\r
\t'!help' - Этот мини-хелп.\r
\t'!list' - Список всех вопросов.\r
\t'Любая цифра - номер вопроса.\r
\t'!exit' - Отключить бот.\r
";

require_once ('WebIcqPro.class.php');
$msg_old = array();
$icq = new WebIcqPro();

while (1) {
    if ($icq->connect(UIN, PASSWORD))
        $icq->sendMessage(ADMINUIN, "Бот запущен!");
    else
        die("Подключение не удалось. Попробуйте через несколько минут.");

    while ($icq->isConnected()) {
        $msg = $icq->readMessage();
        if ($msg && $msg !== $msg_old) {
            echo $icq->error;
            $icq->error = '';
            if (isset($msg['encoding'])) {
                if ($msg['encoding']['numset'] === 'UNICODE') {
                    $msg['realmessage'] = $msg['message'];
                    $msg['message'] = mb_convert_encoding($msg['message'], 'cp1251', 'UTF-16');
                }
                if ($msg['encoding']['numset'] === 'UTF-8') {
                    $msg['realmessage'] = $msg['message'];
                    $msg['message'] = mb_convert_encoding($msg['message'], 'cp1251', 'UTF-8');
                }
            }

            $msg_old = $msg;
            if (isset($msg['type']) && $msg['type'] == 'message' && isset($msg['from']) &&
                isset($msg['message']) && $msg['message'] != '') {
                $messaga = strtolower(trim($msg['message']));

                /*Тут будем писать обработку команд*/
                //
                //

            } elseif (isset($msg['errors'])) {
                foreach ($msg['errors'] as $error) {
                    $answer = 'Ошибка. Код: ' . $error['code'] . " " . $error['error'] . "\r\n";
                }
                $icq->sendMessage(ADMINUIN, $answer);
            }
        } else {
            echo $icq->error;
            $icq->error = '';
        }
        flush();
        sleep(2);
    }
}
?>

Данный скрипт вначале устанавливает некоторые настройки сервера (max_execution_time – время выполнения устанавливается бесконечное и error_reporting – включаются оповещения о всех ошибках).

Затем необходимо зарегистрировать для бота свой номер ICQ. Они указываются в 5 и 6 строчке. Также для управления ботом необходимо указать номер админа бота. Ему будут доступны привилегированные команды. Затем мы просто подключаем наш класс и создаем объект WebIcqPro. С ним мы и будем работать в дальнейшем.
Стартуем бес конечный цикл (while(1)). Он нам нужен для постоянной работы. Если необходимо будет его завершить, сделаем это с помощью команды die().

Метод «connect(UIN, PASSWORD)» авторизует бота. Если попытка была неудачна, то либо указаны неверные логин и пароль к учетной записи бота, либо превышен лимит подключений. В этом случае нужно подождать несколько минут и попробовать ещё раз. Если программа подключится, на номер администратора отправится сообщение, информирующее и подключении бота.

Метод readMessage() возвращает специальный массив со всей информацией о сообщениях. Каждые 2 секунды он выполняется и проверяются новые сообщения.

Далее проверяется кодировка сообщения и при необходимости оно перекодируется.

Затем сообщение проверяется, чтобы оно не было пустым, чтоб его тип был «message» и существовал обратный адресат.

Теперь приступим к обработки файла с вопросами/ответами.

Сразу после определения номера администратора вставим следующий код:

<?
$po_skolko = 10; //  По сколько сообщений отправлять в списке, т.к. есть ограничения на размер сообщения
$file = "text.txt"; // В каком файле вопросы
$separate = ":::"; // Разделитель вопросов

if (file_exists($file)) {
    $fp = fopen($file, "r") or die("Не удалось открыть файл. Проверьте права доступа скрипта.");
    while (!feof($fp)) {
        $temp = explode($separate, fgets($fp, 12000));
        $v['vopros'] = $temp[0];
        $v['otvet'] = $temp[1];
        $questions[] = $v;
    }
} else {
    die("Файл '" . $file . "' с вопросами не найден");
}
?>

Он не сложный, но все равно в двух словах опишу что он делает.

Если $file существует, программа открывает его. Начинает считывать по строчке и заносить информацию в ассоциативный массив $questions. Из него в дальнейшем будет браться вся информация.

Теперь начинаем писать обработку команд (это место находится на 48 строчке).

Суть будет простейшая. Операторов if мы будем проверять что-за команда пришла, и в зависимости от неё, будем выполнять различные действия.

Напишем первую обработку:

<?
if ($messaga == '!help') {
    $icq->sendMessage($msg['from'], $help);
}
?>

Тут думаю даже пояснений никаких не нужно. В переменной $messaga сидит сообщение полученное из icq. Мы просто сравниваем его на соответствие с заранее задуманной строкой и в зависимости от того, совпадает она или нет, выполняем определённые действия.

Второй обработчик будет немного поинтереснее:

<?
if ($messaga == '!exit') {
    if ($msg['from'] == ADMINUIN) {
        $icq->sendMessage(ADMINUIN, "Бот остановлен!");
        $icq->disconnect();
        die;
    } else {
        $icq->sendMessage($msg['from'], "Недостаточно прав для данной операции!");
    }
}
?>

Если строка равняется !exit то мы останавливаем бота. Но не каждый может его остановить, именно поэтому мы сначала проверяем чтобы номер отправителя сообщения равнялся номеру админа, указанного в начале программы.

Таким способом можно программировать любые процедуры доступные только для админа сервера.

Следующая обработка будет отправлять пронумерованный список всех вопросов.

<?
if ($messaga == '!list') {
    /*Формирую список вопросов*/
    $ind = 0;
    $string = '';
    for ($i = 0; $i < count($questions); $i++) {
        $string .= "\t " . $i . ": " . $questions[$i]['vopros'] . "\r";

        if ($ind == $po_skolko or $i == (count($questions) - 1)) {
            $icq->sendMessage($msg['from'], $string);
            $string = '';
            $ind = 0;
        }

        $ind++;
    }
}
?>

Здесь я перебираю массив с вопросами, формирую строку $string и отправляю её, но не сразу весь список, а по $po_skolko штук. Сделал я это затем, что у аськи есть ограничения на размер сообщения. Если вопросов будет много, то не все они дойдут. Сообщение обрежется. Поэтому приходится отправлять частями.

И теперь самая главная обработка, это отправка ответа на вопрос:

<?
if (!empty($questions[$messaga]['otvet']) and trim(@$questions[$messaga]['otvet']) != '') {
    $icq->sendMessage($msg['from'], $questions[$messaga]['otvet']);
}
?>

Тут я не стал хитрить и сделал тупую проверку !empty($questions[$messaga]['otvet']).  Конечно можно сделать и по правильнее, но во-первых такой вариант тоже имеет право на существование, а во-вторых я просто пытаюсь передать суть.

Вот полный код программы:

<?
ini_set("max_execution_time", 0);
error_reporting(E_ALL);


define('UIN', '******');
define('PASSWORD', '***');
define('ADMINUIN', '***');
$po_skolko = 5; //  По сколько сообщений отправлять в списке, т.к. есть ограничения на размер сообщения
$file = "text.txt"; // В каком файле вопросы
$separate = ":::"; // Разделитель вопросов
$help = "
\t    Bot commands:\r
\t'!help' - Этот мини-хелп.\r
\t'!list' - Список всех вопросов.\r
\t'Любая цифра - номер вопроса.\r
\t'!exit' - Остановить бот.\r
";


require_once ('WebIcqPro.class.php');
$msg_old = array();
$icq = new WebIcqPro();


if (file_exists($file)) {
    $fp = fopen($file, "r") or die("Не удалось открыть файл. Проверьте права доступа скрипта.");
    while (!feof($fp)) {
        $temp = explode($separate, fgets($fp, 12000));
        $v['vopros'] = $temp[0];
        $v['otvet'] = $temp[1];
        $questions[] = $v;
    }
} else {
    die("Файл '" . $file . "' с вопросами не найден");
}


while (1) {
    if ($icq->connect(UIN, PASSWORD))
        $icq->sendMessage(ADMINUIN, "Бот запущен!.");
    else
        die("Подключение не удалось. Попробуйте через несколько минут.");

    while ($icq->isConnected()) {
        $msg = $icq->readMessage();
        if ($msg && $msg !== $msg_old) {
            echo $icq->error;
            $icq->error = '';
            if (isset($msg['encoding'])) {
                if ($msg['encoding']['numset'] === 'UNICODE') {
                    $msg['realmessage'] = $msg['message'];
                    $msg['message'] = mb_convert_encoding($msg['message'], 'cp1251', 'UTF-16');
                }
                if ($msg['encoding']['numset'] === 'UTF-8') {
                    $msg['realmessage'] = $msg['message'];
                    $msg['message'] = mb_convert_encoding($msg['message'], 'cp1251', 'UTF-8');
                }
            }

            $msg_old = $msg;
            if (isset($msg['type']) && $msg['type'] == 'message' && isset($msg['from']) &&
                isset($msg['message']) && $msg['message'] != '') {
                $messaga = strtolower(trim($msg['message']));


                /*------- Список вопросов -------*/
                if ($messaga == '!list') {
                    /*Формирую список вопросов*/
                    //   Тут химичу с количеством вопросов т.к. есть ограничения на размер сообщения...  А вопросов может быть много.
                    $ind = 0;
                    $string = '';
                    for ($i = 0; $i < count($questions); $i++) {
                        $string .= "\t " . $i . ": " . $questions[$i]['vopros'] . "\r";

                        if ($ind == $po_skolko or $i == (count($questions) - 1)) {
                            $icq->sendMessage($msg['from'], $string);
                            $string = '';
                            $ind = 0;
                        }

                        $ind++;
                    }
                }

                /*------- Ответ на вопрос -------*/
                if (!empty($questions[$messaga]['otvet']) and trim(@$questions[$messaga]['otvet']) != '') {
                    $icq->sendMessage($msg['from'], $questions[$messaga]['otvet']);
                }

                /*------- Справка -------*/
                if ($messaga == '!help') {
                    $icq->sendMessage($msg['from'], $help);
                }

                /*------- Остановка бота -------*/
                if ($messaga == '!exit') {
                    if ($msg['from'] == ADMINUIN) {
                        $icq->sendMessage(ADMINUIN, "Бот остановлен!");
                        $icq->disconnect();
                        die("<br>Бот остановлен.");
                    } else {
                        $icq->sendMessage($msg['from'], "Недостаточно прав для данной операции!");
                    }
                }


            } elseif (isset($msg['errors'])) {
                foreach ($msg['errors'] as $error) {
                    $answer = 'Ошибка: ' . $error['code'] . " " . $error['error'] . "\r\n";
                }
                $icq->sendMessage(ADMINUIN, $answer);
            }
        } else {
            echo $icq->error;
            $icq->error = '';
        }
        flush();
        sleep(2);
    }
}
?>

Если развить эту мысль то можно написать приложение для управления сайтом через ICQ, например отключить товар с интернет-магазина. И не только сайтом, но и сервером. Главное не забывать делать проверки на соответствие номера админа.

Также можно отправлять вместе с командой какой-нибудь параметр, например номер статьи. Например строка   hide_article 28 означает скрыть статью с номером статьи. Обработчик для неё будет следующий:

<?
if (strpos($messaga, "hide_article")) {
    if ($msg['from'] == ADMINUIN) {
        $namb = explode(" ", $messaga);
        $namb = mysql_real_escape_string($namb[1]);

        if (mysql_query(" UPDATE articles SET show='0' WHERE id='" . $namb . "' ")) {
            $icq->sendMessage($msg['from'], "Статья успешно отключена");
        } else {
            $icq->sendMessage($msg['from'], "Произошла ошибка");
        }

    } else {
        $icq->sendMessage($msg['from'], "Недостаточно прав для отключения статьи.");
    }
}
?>

А дальше можно подключать свою фантазию и писать любые обработки для управления сайтом через icq.

Архив с исходниками можно скачать здесь.

 


Тэги:

Комментарии: 1

Прокомментировать »

 
 
Angelotox
2.10.2017
 

Do you feel like you have tried everything possible in order to lose weight? You are not alone--many people have the same problem. The following article is designed to give you tips that you may not have even known existed. By following these tips, you will reach your weight loss goal in no time.

 

Прокомментировать

 
 
Сообщение *
 
Проверочный код *
 
 
 
Яндекс.Метрика