Ключевые слова:php, socket, nntp, news, (найти похожие документы)
From: Denis Roshchin <denis@komkon.org.>
Date: Mon, 20 Sep 2004 18:21:07 +0000 (UTC)
Subject: Использование сокетов в PHP
Оригинал: http://www.komkon.org:8008/~denis/mydoc/Using%20sockets%20in%20PHP.htm
Использование сокетов в PHP
(работа с Usenet-новостными серверами)
Denis Roshchin, Armel Fauveau.
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.phpNNTP-протокол (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\n";
exit();
}
else {
echo "Connected\n";
$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 Ok\r\n") {
echo "502 Authentication error\n";
exit();
}
}
// select newsgroup
fputs($usenet_handle, "GROUP ".$cfgNewsGroup."\n");
$tmp = fgets($usenet_handle, 1024);
if($tmp == "480 Authentication required for command\r\n") {
echo "$tmp\n";
exit();
}
$info = split(" ", $tmp);
$first = $info[2];
$last = $info[3];
print "First : $first\n";
print "Last : $last\n";
?>
Скачивание некоторых статей
Теперь мы имеем номер последней статьи, так что сейчас нам не составит
труда скачать десять последних статей. 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\n");
$article="";
$tmp = fgets($usenet_handle, 4096);
if(substr($tmp,0,3) != "220") {
echo "+----------------------+\n";
echo "Error on article $boucle\n";
echo "+----------------------+\n";
}
else {
while($tmp!=".\r\n") {
$tmp = fgets($usenet_handle, 4096);
$article = $article.$tmp;
}
echo "+----------------------+\n";
echo "Article $boucle\n";
echo "+----------------------+\n";
echo "$article\n";
}
$boucle++;
}
?>
Так-же благодаря комманде HEAD возможно получить только хэадер
(header) сообщения или-же только текст, используя команду BODY.
Отсоединяемся от сервера
Чтобы закрыть сессию с NNTP-сервером, просто закройте соккет используя
fclose() (аналагично закрытию фаила).
Больше информации о функции fclose() можно узнать здес:
http://www.php.net/manual/function.fclose.php
<?php
// close connexion
fclose($usenet_handle);
?>
Заключение
Мы только что видели как открыть, использовать и затем закрыть соккет
- для соединения с NNTP-сервером и получения некоторых статей из
новостных групп.
Для опубликования сообщения необходимо использовать POST комманду.
Примеры приложений работующих с новостными группами можно найти здесь:
http://www.phpindex.com/ng/
* Denis Roshchin
* Armel Fauveau
>почему если я пытаюсь со своим хостом - все нормально. С другим
>- вылазит это сообщение. можно как-то с этим бороться? Спасибо
На нормальных хостингах запрещают исходящие коннекты. Ибо находятся умники, которые на каждый запрос парсят в realtime с десяток внешних сайтов (воруют погоду, валюту, гороскоп) или еще хуже пытаются поднять скрипт с функциями прокси.
Вопрос: используя этот подход можно ли получить с удаленного сервера обычную html страницу сайта ? к примеру index.html ? в точности такую, как если бы мы заходили на него обычным браузером.
При создании сокета функцией socket_create(AF_INET, SOCK_STREAM, 0) выбивает ошибку:
Fatal error: Call to undefined function: socket_create() in ...
Чем это может быть вызвано и как это можно устранить? Пожалуйстаб подскажите.
1. Надо залезть в файл php.ini и добавить строчку "extension=php_sockets.dll",
Если она уже есть и закомментирована, надо убрать комментарий (;)...
2. Потом скачать файл php_sockets.dll (скачай http://www.nodevice.ru/dll/P_p23.html) в папку extensions (по умолчанию).
3. И перезапустить сервер...