Обзор сетевых функций PHP

Обзор сетевых функций PHP

В этой статье рассматривается использование сетевых функций популярного языка программирования PHP. При написании этой статьи я решил отойти от общепринятой схемы, которая употребляется в руководстве по PHP: 

«тип название (параметры) – описание» 

Наоборот, в статье собраны полезные практические примеры. Из-за большого объема информации (язык PHP предназначен для Web-программирования, поэтому достаточно большую часть функций можно назвать сетевыми), я ограничусь только теми, которые использую наиболее часто. 

Переменные окружения интерфейса CGI

При использовании интерфейса CGI (Common Gateway Interface) программисту доступно множество переменных окружения. Сейчас мы рассмотрим наиболее полезные в нашем случае переменные (см. таблицу 1). 

Переменные окружения можно использовать в программе также как обыкновенные переменные. Например, для вывода IP-адреса клиента достаточно одного оператора: 

echo $REMOTE_ADDR 

Таблица 1. 

Переменная

Описание

HTTP_USER_AGENT

С помощью этой переменой можно определить броузер пользователя, а также его операционную систему. Например, для Netscape, запущенным под Linux, эта переменная будет содердать значение: 

Mozilla/4.7 [en] (Linux; I) 

Для Internet Explorer 5.0 и Win98: 

Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)

HTTP_HOST

Содержит доменное имя сервера, на котором запущен сценарий.

SERVER_PORT

Порт сервера, к которому обратился броузер. Обычно используется порт 80.

REMOTE_ADDR

Содержит IP-адрес клиента, то есть IP-адрес пользователя, который запустил броузер

REMOTE_PORT

Порт для получения ответа сервера. Этот порт закрепляется за каждой запущенной копией броузера

Получение документа по протоколу HTTP

Получить документ по протоколу HTTP довольно просто: 

Листинг 1. Получение документа по HTTP 

<?

1. $file = join( '', file( 'http://localhost/index.html' ) );

2. echo $file;

?>

В первой строке листинга 1 мы получаем весь документ в строку $file, а второй – отправляем документ в броузер. Функция file() возвращает массив строк. N-ый элемент этого массива соответствует N-ой строке файла. 

Если нас интересует HTML-код получаемого документа, вывести код в броузер поможет листинг 2, который я позаимствовал из руководства по PHP. 

Листинг 2. Вывод HTML-кода документа 

<?

1. $fcontents = file( 'http://localhost' );

2. while ( list( $line_num, $line ) = each( $fcontents ) ) {

3. echo "<b>Line $line_num:</b> " . htmlspecialchars( $line) . "<br>\n";

4. }

?>

Работа с сокетами

Функция file() (равно как и fopen() ) позволяет нам работать только с содержимым файла, который получен по тому или иному протоколу. Предположим, что нас интересуют заголовки, переданные сервером. Получить эти заголовки мы можем с помощью функции 

int fsockopen(string $host, int $port, [, int &$errno] [, string &$errstr]) 

Данная функция позволяет инициализировать потоковое соединение с указанным хостом и программой, которая связана с указанным портом. Кроме того, эта функция поддерживает Unix-сокеты. При этом параметр $hostname будет использован как путь к файлу сокета, а параметр $port должен быть равен 0. 

После установления соединения функция возвращает обыкновенный дескриптор файла. С этим дескриптором могут работать функции fread(), fwrite(), fgets(), feof() и другие. 

В случае ошибки функция возвратит false и, если указаны необязательные параметры $errno и $errstr, соответственно, номер ошибки и текст сообщения об ошибке. 

Рассмотрим листинг 3 – «Виртуальный браузер»: мы посылаем серверу HTTP-запрос GET и, получив ответ, выводим его в броузер. 

Листинг 3. «Виртуальный браузер» 

<?

// Подключаемся к серверу

1. $fsoc = fsockopen("localhost",80);

2. fputs($fsoc, "GET / HTTP/1.0\n\n");

3. echo "<pre>";

4. while (!feof($fsoc))

5. echo HtmlSpecialChars(fgets($fsoc,1000));

6. echo "</pre>";

// Отключаемся от сервера

7. fclose($fsoc);

?>

Как я уже отмечал выше, при использовании функции fsockopen мы получаем весь ответ сервера – вместе с заголовками. Функцию HtmlSpesialChars() мы используем для корректного отображения HTML-кода в текстовом формате. В броузере мы должны получить примерно следующее: 

HTTP/1.1 200 OK

Date: Sat, 16 Mar 2002 10:46:59 GMT

Server: Apache/1.3.12 (Linux)

Last-Modified: Sat, 20 Nov 1999 13:29:40 GMT

ETag: "0-574-3836a244"

Accept-Ranges: bytes

Content-Length: 1396

Connection: close

Content-Type: text/html



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">

<HTML>

sp;<HEAD>

<TITLE>Test Page for Apache Installation</TITLE>

</HEAD>

...

Ответ сервера HTTP/1.1 200 OK соответствует коду ответа 200 и означает безошибочное выполнение операции (в данном случае передачи документа по запросу GET). 

Установить нужный нам заголовок ответа мы можем с помощью функции Header(). Например, Header("Location://www.softerra.ru/freeos"); 

Запретить кэширование можно с помощью установки заголовка Pragma: no-cache. К сожалению одного этого заголовка явно не хватит для запрещения кэширования. Для полного запрета нужно использовать целых четыре заголовка. Установить с помощью Header их можно так: 

Header("Pragma: no-cache"); 

Header("Cache-control: no-cache, must-revalidate"); 

Header("Expires: Mon, 01 Jan 1990 01:01:01 GMT"); 

Header("Last-Modified: ".gmdate("D, d M Y H:i:s")."GMT"); 

Первый из них устанавливает заголовок запрета кэширования согласно протокола HTTP/1.0, а второй – HTTP/1.1. Третий определяет задает дату в прошлом, а четвертый устанавливает дату последнего обновления документа. Функция gmdate() возвращает дату в нужном нам формате. Устанавливать все четыре заголовка крайне желательно, так как запрет кэширования может не сработать или на прокси-сервере или в броузере, и пользователь получит устаревшую версию документа. 

Функции для работы с DNS

При написании сценариев вне зависимости от языка программирования часто возникает потребность разрешения IP-адреса в доменное имя и наоборот. 

Преобразование IP-адреса в доменное имя выполняет функция 

string gethostbyaddr(string $ip_address); 

В случае ошибки возвращается IP-адрес. 

Преобразование имени хоста в IP-адрес выполняет функция 

string gethostbyname(string $host); 

Если вам нужно получить все IP-адреса хоста с именем $host, используйте функцию 

array gethostbynamel(string $host); 

В листинге 4 применена именно функция gethostbynamel. 

Листинг 4. Получение всех IP-адресов хоста $host 

<?

$host="www.yahoo.com";

$ips=gethostbynamel($host);

foreach($ips as $ip) echo $ip;

?>

Определить почтовик для указанного хоста hostname можно с помощью функции 

int getmxrr(string hostname, array mxhosts, array [weight]); 

Данная функция запрашивает DNS на предмет наличия записей MX для указанного хоста. 

Следующие функции никакого отношения к DNS не имеют, но чтобы не создавать другого раздела в статье, я описал их здесь. 

int getprotobyname(string name); 

Функция getprotobyname() возвращает номер протокола, который соответствует имени $name. 

Обратная ей функция 

string getprotobynumber(int number); 

возвращает имя протокола по его номеру. 

Функция 

int getservbyname(string service, string protocol); 

возвращает номер порта Internet-сервиса, название которого указано в параметре $service. Второй параметр функции – это протокол: tcp или udp. 

Например, оператор 

echo getservbyname("ftp", "tcp"); 

выведет в окно броузера число 21. 

Для функции getservbyname() также существует обратная ей: 

string getservbyport(int port, string protocol); 

При использовании функции getservbyport() нужно указать номер порта и протокол (tcp или udp) и, как результат, вы получите название Internet-сервиса. 

Например, 

echo getservbyport(21, "tcp"); 

выведет в окно броузера название сервиса – ftp. 

Функции протоколирования

Иногда нужно записать некоторую информацию, например, сообщение об ошибке, в системный журнал syslog. В PHP для этого предусмотрена целая серия функций: 

int openlog(string ident, int option, int facility); 

int syslog(int priority, string message); 

int closelog(void); 

Первая из них открывает соединение с демоном syslog. Вторая – порождает системное сообщение (другими словами записывает сообщение с указанным приоритетом в протокол). Функция closelog() закрывает соединение протокола. 

Отправка сообщения

Я не открою Америки, если заявлю, что для отправления почты в PHP используется функция mail. Здесь я только приведу несколько рекомендаций относительно использования этой функции. 

Напомню формат вызова функции: 

mail(string $to, string $subject, string $msg [, string $headers]); 

Например, 

mail("root@localhost", "Test", "Message\nLine2", "From: den@localhost\n", "Reply-To: den@localhost\n"); 

Все работает хорошо до тех пор, пока не начинаются проблемы с кодировками. Для указания кодировки нужно установить заголовок 

Content-type: text/plain; charset=koi8-r 

Для преобразования самих кодировок используется функция convert_cyr_string(). Использовать ее предельно просто, например, 

convert_cyr_string($msg,"k","w"); 

Этим вызовом функции convert_cyr_string() мы преобразуем кодировку koi8-r в windows-1251. Разумеется, заголовок Content-type нужно изменить на 

Content-type: text/plain; charset=win-1251 

При использовании функции mail целесообразно хранить все заголовки в теле письма. Тогда один раз вызвав функции convert_cyr_string() мы конвертируем все письмо в нужныю нам кодировку. В этом случае вызов функции mail должен быть произведен так: 

mail("root@localhost","",$msg); 

Значение переменной $msg будет таким: 

$msg="From: Денис <den@localhost>\n

To: Администратор <root@localhost>\n

Content-type: text/plain; charset=win-1251\n

\n

Текст сообщения

...

Обратите внимание, что после всех заголовков должно следовать два символа новой строки \n: один после последнего заголовка, а другой перед текстом сообщения.