Использование сокетов в PHP
Автор: realcoding.net
PHP может
открывать сокеты на локальной или удаленной машине. В данной
статье будет рассмотрен пример использования сокетов для:
соединения с Usenet-новостным сервером, ведения диалога с ним
и скачивания некоторых статей.
Открываем сокет
Для открываения сокета используется функция fsockopen(). Вызов функции имеет
следующий вид:
int fsockopen (string hostname, int port [,
int errno [, string errstr [, double timeout]]])
Для
UDP соединения, надо определить протокол:
udp://hostname.
Больше информации о функции fsockopen()
можно узнать здесь.
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
failedn";
exit();
}
else {
echo
"Connectedn";
$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."n");
$tmp = fgets($usenet_handle,
1024);
fputs($usenet_handle, "AUTHINFO PASS
".$cfgPasswd."n");
$tmp = fgets($usenet_handle,
1024);
// check error
if($tmp != "281 Okrn")
{
echo "502 Authentication errorn";
exit();
}
}
// select newsgroup
fputs($usenet_handle,
"GROUP ".$cfgNewsGroup."n");
$tmp = fgets($usenet_handle,
1024);
if($tmp == "480 Authentication required for
commandrn") {
echo "$tmpn";
exit();
}
$info =
split(" ", $tmp);
$first = $info[2];
$last =
$info[3];
print "First : $firstn";
print "Last :
$lastn";
?>
Скачивание некоторых
статей
Теперь мы имеем номер последней статьи, так что
сейчас нам не составит труда скачать десять последних статей.
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 $bouclen");
$article="";
$tmp =
fgets($usenet_handle, 4096);
if(substr($tmp,0,3) != "220")
{
echo "+----------------------+n";
echo "Error on
article $bouclen";
echo
"+----------------------+n";
}
else
{
while($tmp!=".rn") {
$tmp = fgets($usenet_handle,
4096);
$article = $article.$tmp;
}
echo
"+----------------------+n";
echo "Article
$bouclen";
echo "+----------------------+n";
echo
"$articlen";
}
$boucle++;
}
?>
Также благодаря команде HEAD возможно получить только
хэадер (header) сообщения или-же только текст, используя
команду BODY.
Отсоединяемся от сервера
Чтобы закрыть
сессию с NNTP-сервером, просто закройте сокет используя
fclose() (аналогично закрытию файла).
Больше информации
о функции fclose() можно узнать здесь.
<?php
//
close connexion
fclose($usenet_handle);
?>
Заключение
Мы только что видели как открыть,
использовать и затем закрыть сокет – для соединения с
NNTP-сервером и получения некоторых статей из новостных
групп.
Для опубликования сообщения необходимо использовать
POST комманду.
Примеры приложений работующих с
новостными группами можно найти здесь:
http://www.phpindex.com/ng/