Доступ к Skype API используя PHP на *nix системах

    Еще давно я хотел иметь свой автоответчик или бота для скайпа, называйте как вам угодно. В гугле я ничего найти не мог, да еще из-за того, что я пользуюсь Ubuntu, задача становилась сложнее в несколько раз. А если учесть, что я знаю только PHP, и то, не очень хорошо, моя мечта становилась нереальной.

    Но недавно, просматривая официальную документацию по API скайпа, я обратил внимание на «D-BUS messaging», не знаю, почему я раньше не обращал на него внимание. Разобравшись со всем, я наконец сделал то, что давно хотел! Я получил доступ к Skype API на PHP. Об этом я и хочу рассказать в своей статье.



    Для установки dbus-php нужен phpize, который идет в пакете php5-dev, установим его:
    sudo apt-get install php5-dev
    

    Теперь установим php-pear, выполнив такие команды:
    sudo apt-get install php-pear
    pear install PEAR
    

    Устанавливаем dbus расширение для php, предварительно установив зависимости(У Вас должен быть установлен make, иначе установка dbus-beta завершится ошибкой!):
    sudo apt-get install libdbus-1-dev libxml2-dev
    pecl install dbus-beta
    

    Добавляем загрузку расширения в конфигурацию php:
    echo -e "; configuration for php DBus module\nextension=dbus.so"| sudo tee -a /etc/php5/conf.d/dbus.ini
    

    Проверяем, работает ли расширение, вводим в терминале команду php -i и находим там:
    dbus
    
    Dbus support => enabled
    Version => 0.1.0
    

    Нашли? Отлично! Можете продолжать!
    Не нашли? Что же, повторите все, найдите ошибку, исправьте и продолжайте чтение, у Вас все выйдет.

    Все! Теперь у нас есть все необходимое для работы.

    Приступим к самому коду php.
    Самое простое и важное — подключение к скайпу и запрос на доступ к api, сделаем мы это таким образом:
    $dbus = new Dbus(Dbus::BUS_SESSION, true); //Инициализируем Dbus
    $n = $dbus->createProxy('com.Skype.API', '/com/Skype', 'com.Skype.API'); //Подключаемся к скайпу
    $n -> Invoke('NAME PHP'); //Имя нашей программы, авторизация в скайпе
    $n -> Invoke('PROTOCOL 8'); //Используем последний протокол
    

    Метод Invoke() будет основным для отправки указаний скайпу.
    Теперь, научим наш скрипт получать уведомления скайпа:
    //продолжение предыдущего отрывка кода
    class phpSkype {
    	public static function notify ($notify) {			    
    		echo $notify."\n";
    	}
    }
    
    $dbus -> registerObject('/com/Skype/Client', 'com.Skype.API.Client', 'phpSkype'); //Регистрируем просмотр уведомлений скайпа
    
    while(1) {
    	$s = $dbus -> waitLoop(1);
    }
    

    Запустив этот скрипт, вы сможете наблюдать все уведомления скайпа, примерно так:
    CONNSTATUS ONLINE
    CURRENTUSERHANDLE *my_user*
    USERSTATUS DND
    CHATMESSAGE 5150665 STATUS READ
    CHATMESSAGE 5149961 STATUS READ
    CHATMESSAGE 5149993 STATUS READ
    CHATMESSAGE 5150025 STATUS READ
    CHATMESSAGE 5150057 STATUS READ
    CHATMESSAGE 5150697 STATUS SENDING
    CHAT #zaidin16/$e00fc2f75170ec9e ACTIVITY_TIMESTAMP 1345401315
    CHATMESSAGE 5150697 STATUS SENT
    

    Дополняем класс phpSkype и обучаем наш скрипт обрабатывать и отвечать на сообщения, вот что получилось у меня:
    <?php
    $dbus = new Dbus(Dbus::BUS_SESSION, true); //Инициализируем Dbus
    $n = $dbus->createProxy('com.Skype.API', '/com/Skype', 'com.Skype.API'); //Подключаемся к скайпу
    $n -> Invoke('NAME PHP'); //Имя нашей программы, авторизация в скайпе
    $n -> Invoke('PROTOCOL 8'); //Используем последний протокол
    
    class phpSkype {
    
    	/*
    	* Эту функцию мы будем использовать для проверки последних сообщений в скайпе.
    	* Если вы не хотите, чтобы программа реагировала на ваши сообщения, используйте
    	* preg_match('/RECEIVED/', $notify)
    	*/
    
    	public static function notify ($notify) {		
    
    		if (preg_match('#RECEIVED|SENT#Uis', $notify)) {
    			$message_id = explode(' ', $notify);			
    			bot::get_details($message_id[1]); //Вызываем обработчик сообщений	    
    		}
    	}
    }
    
    class bot
    {
    	
    	private static $last_id;
    
    	public static function get_details ($message_id)
    	{
    		global $n;
    
    		$ch = $n -> Invoke('GET CHATMESSAGE '.$message_id.' CHATNAME'); //Получаем id чата, используется для ответа
    		$mess = $n -> Invoke('GET CHATMESSAGE '.$message_id.' BODY'); //Получаем текст сообщения
    		$aut = $n -> Invoke('GET CHATMESSAGE '.$message_id.' FROM_DISPNAME'); //Получаем автора сообщения
    		
    		/*
    		* Теперь мы получим из строк, которые мы только что получили, нужные нам данные.
    		* А именно: Автора сообщения, id чата и текст сообщения.
    		*/
    
    		$author = explode('FROM_DISPNAME ', $aut);		
    		$chat = explode('CHATNAME ', $ch);
    		$message = explode('BODY ', $mess);
    
    		echo $author[1].': '.$message[1]."\n"; //Выводим в консоль автора и сообщение
    
    		/*
    		* Мне не нужно, чтобы бот пытался найти ответ на каждое сообщение, из-за этого
    		* я вызываю обработку сообщения только когда оно начинается на "!".
    		*/
    
    		if ($message[1][0] == '!') { 
    			self::reply($chat[1], $message[1], $message_id);
    		}
    	}
    
    	public function reply ($chat, $message, $id)
    	{
    		global $n;
    
    		/*
    		* Проверки, больше ли id сообщение, на которое нужно ответить, изначально не было, но
    		* мои любезные друзья начали загружать бота кучей "!test" в одном сообщении, он хоть и отвечал
    		* лишь на первое, но потом ответил и на остальные. Из-за этого я сделал проверку и если id
    		* сообщения, на которое нужно ответить, меньше чем id предыдущего, то ответа не будет.
    		*/
    
            self::$last_id = $message;
    
            if (self::$last_id <= $message) {        	
            	
    			switch ($message) {
    				case '!test':
    					$reply = 'It\'s work!';
    					break;
    
    				case '!help':
    					$reply = 'Нету, пока нету';					
    					break;				
    				
    				default:
    					$reply = 'Используйте !help';
    					break;
    			}
    			if ($reply != '') $n -> Invoke('CHATMESSAGE '.$chat.' '.$reply); //Посылаем сообщение	
    		} else {
    			echo 'Уже отвечал!'."\n"; 
    		}
    	}    
    }
    
    $dbus -> registerObject('/com/Skype/Client', 'com.Skype.API.Client', 'phpSkype'); //Регистрируем просмотр уведомлений скайпа
    
    while(1) {
    	$s = $dbus -> waitLoop(1);
    }
    ?>
    


    Теперь наш скрипт умеет отвечать на определенные сообщения, а если Вы немного его измените — сможет отвечать на любые сообщения. Если навскидку подумать, можно реализовать что-то интересное на сайте, если он хостится на вашем компьютере, ну или через связку скрипта на локалхосте и на хостинге, это уже как Вы придумаете.

    Подробный список команд, которые доступны через метод Invoke() Вы найдете тут.
    А [Неактуально из-за действий Microsoft'a] исходники и более функциональный скрипт.

    Все это я делал в системе Ubuntu 12.04 LTS, работу на остальных системах не гарантирую и буду рад, если кто-то проверит.
    Любые идеи приветствуются.
    Спасибо за чтение!
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 23
    • 0
      Класс! Спасибо, пригодится.
      Если не сложно, спрячьте код под спойлер
      • +5
        О, так можно и полноценный web-skype организовать. Да и вообще множество различных применений. В общем полезно, однозначно в закладки. :)
        • +1
          А как-то можно запустить сам скайп на headless-сервере?
          • +1
            xvfb? Сомневаюсь, что без Х-ов как-то получиться.
            • +1
              Можно попробовать сделать свою прокси-библиотеку поверх Qt, которая будет перехватывать графические вызовы и игнорировать их с флагом «завершено успешно», а обращения ко всяким QTcpSocket перенаправлять настоящей библиотеке, и подгружать все это добро через LD_PRELOAD. Насколько мне известно, kekekeks далеко продвинулся именно в хаке графической части скайпа, надеюсь, он увидит этот пост и сможет рассказать подробнее.

              Или взять какой-нибудь dummy X-сервер, который, опять-таки, игнорирует все, что ему говорят, притворяясь при этом рабочим сервером — чтобы даже фреймбуфер не создавал.
              • +5
                Если мне не изменяет память, скайп отлично заводится под VNCшным X-сервером. Если нужна мультисессионность, это нормально достигается через --dbpath=путь. Если нужно к каждому инстансу ломиться через API, достаточно поднять отдельную DBus-сессию, могу поделиться специальным лянчером, который помимо скайпа сразу в ней же запустит остальной нужный софт.

                Но вообще лучше не над ним не издеваться и отдать 5 баксов за SkypeKit, он мощнее и к нему есть биндинги на C++, Python, Java и .NET (последние для работы под Mono надо весьма хитро патчить, опять же, если кому надо, могу поделиться).
                • 0
                  Коль я правильно понимаю, Xvnc и производные обязан иметь фреймбуфер, в котором он сохраняет промежуточные результаты отрисовки, и отрисовка, как таковая, все равно происходит. Если никто и никогда не будет подключаться к нему по VNC и смотреть, что же там видно, в этом нет нужды и на самом факте отрисовки можно освободить ресурсы.

                  На какие подводные грабли можно наступить в случае использования «я X-сервер, я не хочу ничего рисовать, я хочу хур-дур-дур» по сравнению с xvfb?
                  • 0
                    Думаю, необходимость всё же такой X-сервер написать. На самом деле оно памяти сожрёт совсем немного, так что можно не принимать во внимание. А вообще, skypekit намного удобнее, лучше всё же раскошелиться на $5.
                    • +1
                      Признаться, я больше думал не о потреблении памяти, которое даже в случае невообразимого разрешения 2880х1800x32b составит аж 20 MiB, сколько о вычислительных ресурсах, необходимых для отрисовки всяких анимаций, всплывающих окон с меняющейся полупрозрачностью отдельных регионов окна, градиентных кнопок, меню, аватаров и тому подобных вещей, которые в headless-конфигурации никто не оценит.

                      Ну или сесть один раз и сделать libqt-headless, как раз для таких случаев.
                      • +1
                        > Ну или сесть один раз и сделать libqt-headless, как раз для таких случаев.

                        Это все чтобы сэкономить 5$ за официальную версию, правильную лицензию, совместимость в будущем и дополнительные функции и возможности, или я чего-то не понимаю?
                        • 0
                          Иногда удовольствие от ресеча перекрывает экономическую выгоду.
                          • +2
                            Говорят, Лицензия skypekit запрещает серверное использование.
                            • 0
                              Оно так и есть, его лицензия слишком строгая, имхо.
                • +2
                  Мы используем для этого skype --pipelogin + xvfb. Для первичной настройки запускается X11vnc на соответсвующем $DISPLAY
                • 0
                  Сразу нашел Creating an SMS message но цены на смс у скайпа очень завышены :(
                  • 0
                    Для отправки смс давно есть нормальные сервисы.
                  • 0
                    Я как-то хотел сделать бота для скайп чата.
                    В целом это оказалось довольно легко, я делал под виндой, у скайпа есть все необходимое в апи.
                    Но, нужна машина с запущенным скайпом (винда или, как вижу, linux).
                    Жаль, что на web сервере такое не получится реализовать.
                    • +1
                      Даже со skypekit?
                      • 0
                        Ух ты, не знал, спасибо.
                        Там много ограничений по лицензии, но я думал, что ничего подобного до сих пор нету.
                    • 0
                      Спасибо, годный пост. Пока пользуюсь skype4py, получаю уведомления из заббикса в чатик, удобно.
                      • 0
                        Спасибо, как раз думал менять статусы через API
                        • 0
                          Интересно! Я делал через вызовы из php к Skype4Py, запуская skype на нулевом X дисплее, при этом нещадно обрезая трафик процесса. Работает, В итоге всё снёс, не стоит того, ибо такую истинную проприетарщину, хоть и не суперноду, держать на рабочем сервере было очково.
                          • 0
                            Можно же завести через Xen, оно будет дешево по ресурсам, и изоляция чуть ли не лучшая из аналогичных решений.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.