PHP может открывать соккеты на локальной или удаленной машине. В данной статье будет рассмотрен пример использования соккетов для: соединения с Usenet-новостным сервером, ведения диалога с ним и скачивания некоторых статей. Открываем соккет. Для открывания соккета используется функция fsockopen(). Эта функция доступна, как в PHP3, так и PHP4. Вызов функции имеет следующий вид: int fsockopen (string hostname, int port [, int errno [, string errstr [, double timeout]]]) Для UDP соединения, надо определить протокол: udp://hostname. Больше информации о функции fsockopen() можно узнав здесь: http://www.php.net/manual/function.fsockopen.php NNTP-протокол (Network News Transfer Protocol) Для доступа к новостному usenet-серверу мы будем использовать NNTP-протокол. Этот протокол детально описан в RFC977 (Request For Comment number 977). Полное описание присутствует в Интернете: http://www.w3.org/Protocols/rfc977/rfc977.html Этот документ детально описывает процедуру соединения и диалога с сервером. Соединение (Connecting) Для соединения с NNTP-сервером нам необходимо знать его имя (или IP-адрес) и порт. Так же необходимо указывать таймер, чтобы в случае невозможности подсоединения к серверу не "заморозили" application. <?php $cfgServer = "your.news.host"; $cfgPort = 119; $cfgTimeOut = 10; // open a socket if(!$cfgTimeOut) // without timeout $usenet_handle = fsockopen($cfgServer, $cfgPort); else // with timeout $usenet_handle = fsockopen($cfgServer, $cfgPort, &$errno, &$errstr, $cfgTimeOut); if(!$usenet_handle) { echo "Connexion failed
"; exit(); } else { echo "Connected
"; $tmp = fgets($usenet_handle, 1024); } ?> Ведение диалога с сервером.
Итак, теперь мы присоединились к серверу и можем вести диалог с ним, используя ранее открытый соккет. Для примера, попробуем достать десять последних сообщений с какой-либо группы. В RFC977 описано, что первый шаг - выбрать группу с помощью GROUP команды: GROUP ggg Обязательный параметр - ggg - имя группы, которую мы хотим выбрать (например, "net.news"). Список существующих групп может быть получен с помощью команды LIST. Удачный выбор группы будет подтвержден ответом сервера, где будет сообщаться количество новых, старых статей и общее количество. chrome:~$ telnet my.news.host 119 Trying aa.bb.cc.dd... Connected to my.news.host. Escape character is '^]'. 200 my.news.host InterNetNews NNRP server INN 2.2.2 13-Dec-1999 ready (posting ok). GROUP alt.test 211 232 222996 223235 alt.test quit 205
После получения команды "GROUP alt.test", новостной сервер ответил "211 232 222996 223235 alt.test". 211 - определенный RFC спецификацией код (говоря обычным языком - 212 - означает, что команда была завершена с положительным результатом - смотрите документацию RFC для более полной характеристики). Следующая цифра - 232 - количество имеющихся в текущий момент новых статей. 222996 - старых. 223235 - всего статей. 232+222996 не равно 223235. Почему? Возможно, недостающие семь статей были каким-либо образом удалены модератором или самим автором. В зависимости от сервера (public или private) вас могут попросить идентифицироваться. Так же возможно, что идентификация понадобиться только при написании своих сообщений, а чтение может производиться без этого. <?php //$cfgUser = "xxxxxx"; //$cfgPasswd = "yyyyyy"; $cfgNewsGroup = "alt.php"; // identification required on private server if($cfgUser) { fputs($usenet_handle, "AUTHINFO USER ".$cfgUser."
"); $tmp = fgets($usenet_handle, 1024); fputs($usenet_handle, "AUTHINFO PASS ".$cfgPasswd."
"); $tmp = fgets($usenet_handle, 1024); // check error if($tmp != "281 Ok
") { echo "502 Authentication error
"; exit(); } } // select newsgroup fputs($usenet_handle, "GROUP ".$cfgNewsGroup."
"); $tmp = fgets($usenet_handle, 1024); if($tmp == "480 Authentication required for command
") { echo "$tmp
"; exit(); } $info = split(" ", $tmp); $first = $info[2]; $last = $info[3]; print "First : $first
"; print "Last : $last
"; ?> Скачивание некоторых статей Теперь мы имеем номер последней статьи, так что сейчас нам не составит труда скачать десять последних статей. RFC977 спецификация допускает использование комманды ARTICLE, как с номером статьи, так и Message ID (Уникальный Номер Сообщения). Будьте внимательны здесь - номер статьи отличен от Message ID. Если статья опубликована на нескольких серверах, то она несомненно будет иметь разный номер оба раза, но одинаковый Message ID. Грубо говоря, номер статьи - присваивается каждый раз по-новому на сервере, и может меняться со временем; Message ID - у каждой статьи уникальный. <?php $cfgLimit = 10; // upload last articles $boucle=$last-$cfgLimit; while ($boucle <= $last) { set_time_limit(0); fputs($usenet_handle, "ARTICLE $boucle
"); $article=""; $tmp = fgets($usenet_handle, 4096); if(substr($tmp,0,3) != "220") { echo "+----------------------+
"; echo "Error on article $boucle
"; echo "+----------------------+
"; } else { while($tmp!=".
") { $tmp = fgets($usenet_handle, 4096); $article = $article.$tmp; } echo "+----------------------+
"; echo "Article $boucle
"; echo "+----------------------+
"; echo "$article
"; } $boucle++; } ?> Так же благодаря команде HEAD возможно получить только хэадер (header) сообщения или же только текст, используя команду BODY. Отсоединяемся от сервера Чтобы закрыть сессию с NNTP-сервером, просто закройте соккет используя fclose() (аналагично закрытию файла). <?php // close connexion fclose($usenet_handle); ?> Заключение Мы только что видели как открыть, использовать и затем закрыть соккет - для соединения с NNTP-сервером и получения некоторых статей из новостных групп. Для опубликования сообщения необходимо использовать POST комманду. Примеры приложений работающих с новостными группами можно найти здесь: http://www.phpindex.com/ng/ |