![]() |
Модераторы: skyboy, MoLeX, Aliance, ksnk |
![]() ![]() ![]() |
|
AztEK |
|
||||||||||||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 723 Регистрация: 4.1.2005 Репутация: 6 Всего: 18 |
Сокеты в PHP. Пособие для начинающих.
Сокеты как таковые (не только реализованные в PHP) – мощнейший инструмент сетевого программирования. Они позволяют передавать и получать данные на прикладном уровне. Наиболее частое использование сокетов в контексте web-программирования - это работа со страницами, расположенными на разных хостах и взаимодействие с различными типами протоколов, используемых в Интернете (HTTP, FTP, SMTP, IMAP и проч.). Для взаимодействия с сокетами в PHP чаще всего используется функция fsockopen, синтаксис которой приведён ниже. resource fsockopen ( string $host [, int $post [, int &$errno [, string &$errstr [, float $timeout]]]] ) $host - хост, к которому будет производиться подключение $port - порт, по которому будет производиться подключение $errno - переменная, в которую запишется номер ошибки если таковая произойдёт $errstr - переменная, в которую запишется текст ошибки если таковая произойдёт $timeout - время в течении которого мы будем будет производиться попытка соединения с хостом Мы разберём подключение к серверу по 80-му порту и использование протокола HTTP. Поэтому хотя бы основы HTTP надо знать (в общем то любому web-программисту надо их знать). Спецификацию HTTP можно скачать по ссылке, расположенной в конце статьи. Больше не будет теоретизировать, сразу перейдём к практике. Распространённые примеры использования сокетов. Пример 1. Передаём данные и получаем страницу. Создайте php-скрипт следующего содержания:
Он, как нетрудно догадаться, выводит переменные, которые мы передадим в теле HTTP-запроса: строку User-Agent(где клиент говорит о том, какой у него браузер и ОС), HTTP-Referer(откуда он пришёл) и тестовую cookie (они ведь тоже передаются в HTTP). Теперь напишем скрипт обращения к странице и передачи переменных.
Разберём построчно этот пример. $fp = fsockopen('localhost', 80); Открываем сокет с идентификатором $fp и присоединяемся к хосту localhost (напомню, что получить имя хоста из URL можно функцией gethostbyname). Обратите внимание – перед названием хоста НЕ НАДО писать http:// - мы вполне бы могли работать и не с этим протоколом. Теперь, когда создан сокет, мы может получать и передавать информацию по нему с помощью функций, используемых для работы с файлами (fread(), fwrite(), fgets(), feof()). Этим и займёмся. fputs($fp, "GET /test_sock.php HTTP/1.0\nUser-Agent: У меня Firefox 1.5 и Windows XP\nReferer: Я пришёл с microsoft.com\nCookie: test=test_cookie\n\n"); С помощью функции fputs передаём данные, используя формат HTTP. Давайте разберём, что же там написано.
В первой строке мы указываем, какую страницу на сервере мы хотим получить (/test_sock.php). Соответственно, если бы нам была нужна страница, расположенная в директории test на сервере, мы бы написали так: /test/test_sock.php, а если бы была нужна главная страница сервера, напишем просто /. HTTP/1.0 показывает, какую версию протокола HTTP мы будем использовать, обращаясь к серверу. В следующих строках мы будем передавать серверу информацию в виде
Это называется заголовок HTTP-запроса. Вот распространённые значения (все возможные значения можно прочитать в спецификации HTTP): User-Agent Пример: User-Agent: Mozilla/4.5 [en] (Win95; I) Строка, описывающая браузер и ОС. На основе этого заголовка создается переменная окружения HTTP_USER_AGENT. Referer Пример: Referer: php.net URL страницы, с которой клиент перешел на данную страницу. На основе этого заголовка создается переменная окружения HTTP_REFERER. Как видите, не стоит сильно доверять этой переменной при написании систем авторизации, поскольку клиент (или хакер) может передать в этом заголовке всё что угодно. Accept Пример: Accept: text/html, text/plain, image/gif, image/jpeg Эта строка используется браузером, что сказать серверу, какие типы данных он понимает На основе этого заголовка создается переменная окружения HTTP_ACCEPT_ENCODING. Cookie Пример: Cookie: a=1;b=2;c=3; Передаём cookie. На основе этого заголовка создается глобальный массив $_COOKIE. После того, как мы передали все необходимые нам переменные, идут подряд два символа перевода строки(\n\n). Это означает, что всё, что клиент хотел сказать серверу, он сказал и теперь ожидает ответа. while(!feof($fp)) echo fgets($fp); Используя функции feof() и fgets(), выводим ответ сервера на наш запрос. У моего сервера ответ получился такой:
Не буду сдаваться в подробности того, какие заголовки вывел сервер, всё это вы можете прочитать в документации. Как видите, послать серверу можно что угодно, поэтому дважды подумайте, прежде чем доверять переменным окружения. В умелых руках это серьёзное оружие взлома. P.S. Довольно часто получать содержание страницы в Интернете пытаются функциями наподобие file() и file_get_contents(). Почему этого не стоит делать, читайте здесь. Пример 2. Определить, существует ли страница в Интернете. Довольно популярный вопрос, который обычно пробуют решать примерно так:
Сейчас разберёмся, как сделать это грамотнее. Немного отвлечёмся от программирования. Вот вы бродите по Интернету, открываете страницы и вдруг ошиблись при наборе адреса и попали на несуществующую страницу. Что делает ваш браузер? Конечно он хороший браузер и говорит, что такой страницы не существует. В тексте сообщения об ошибке наверняка попадётся число 404. Это даёт нам идею для реализации нашей задачи. Давайте вернёмся немного назад, к предыдущему примеру. Сервер первой строкой отдал нам следующее: HTTP/1.1 200 OK Что это значит? HTTP/1.1 – это ясно, версия протокола, на котором отдан ответ клиенту. Следующая часть уже интереснее, 200 – это так называемый код состояния, число, используя которое, сервер говорит, что он сделал с нашим запросом и чего нам следует теперь ожидать. В очередной раз отправляю вас к документации по HTTP, где написано, что код 200 означает, что «Запрос был удачно выполнен». Это хорошо. А что возвратит сервер, если страница не найдена? Правильно, уже знакомое нам 404. Итак, определить наличие страницы в Интернете можно так:
Справедливости ради, следует отметить, что сервер, не найдя страницу может и не возвращать 404. Вполне возможно, что он редиректнет нас, причем возвратит код 200. Здесь приведён простейший пример, в реальных условиях, возможно, потребуются дополнительные проверки. Пример 3. Передаём данные на сервер методом POST, не используя HTML-форму. Самый животрепещущий вопрос на тему сокетов ![]() Добавьте в скрипт, к которому мы обращались в прошлом примере строчку echo 'POST: ' . $_POST['test'] . "\n"; Сейчас будем ловить POST-данные. Теперь наш запрос к серверу будет выглядеть таким образом:
Разберём этот запрос. Вот он:
Рассмотрим, чем этот запрос отличается от запроса из предыдущего примера. Прежде всего, в первой строке используется "POST", а не "GET". Это значит, что после двух переносов строки будут идти данные, которые сервер, возможно, передаст PHP-интерпретатору. Кроме того, среди заголовков есть два новых для нас. Content-length Пример: Content-length: 2452 Длина данных, которые, грубо говоря, будут переданы после двух переносов строки. Используется, когда сервер отвечает на запрос или, как в нашем случае, если передаются POST-данные. Размер переданных данных должен быть обязательно равен этому значению. На основе этого заголовка создается переменная окружения CONTENT_LENGTH. Content-Type Пример: Content-Type: text/html Задаёт тип документа и его кодировку. Для передачи данных методом POST мы использовали application/x-www-form-urlencoded. Чтобы передать несколько переменных методом POST, перечислите их через символ «&» (совсем как в GET), например:
Полезные ссылки Википедия Спецификация HTTP1.0 Спецификация HTTP1.1 Описание функции fsockopen (php.net) Сокеты в PHP (php.net) Почему нельзя использовать fopen, file_get_contents при работе с HTTP? Заключение Следует отметить, что подключаться к хосту можно совсем не обязательно на 80-й порт и работать не с протоколом HTTP. Использовать сокеты можно и для работы с FTP, почтой, ICQ и проч. Главное знать, какой порт и протокол использовать в том ли ином случае. Мы разобрали взаимодействие сокетов с HTTP-протоколом, самый простой и очевидный. Удачи вам в программировании! С уважением, AztEK. Это сообщение отредактировал(а) AztEK - 13.7.2006, 17:15 -------------------- Linux is like wigwam -- no windows, no gates, apache inside. |
||||||||||||||||||||
|
|||||||||||||||||||||
GiV |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 137 Регистрация: 13.7.2006 Где: rus|53 Репутация: 4 Всего: 9 |
Небольшое уточнение:
Формат функции
несколько не верен. resource fsockopen ( string target [, int port [, int &errno [, string &errstr [, float timeout]]]] ) Во-первых, функция возвращает ресурс. Т.е. идентификатор соединения. И опущен параметр timeout, он устанвливает время в течении которого мы будем пытаться соединится с ресурсом. Если в течении указанного времени соединение установить не удалось, идентификатор соединения не будет создан. |
|||
|
||||
AztEK |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 723 Регистрация: 4.1.2005 Репутация: 6 Всего: 18 |
GiV, да, спасибо. Действительно, это ошибка. Зачем то взял BNF функции из Котерова, а не c php.net.
Исправил. -------------------- Linux is like wigwam -- no windows, no gates, apache inside. |
|||
|
||||
AztEK |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 723 Регистрация: 4.1.2005 Репутация: 6 Всего: 18 |
Что, больше никто ничего не может сказать?
![]() -------------------- Linux is like wigwam -- no windows, no gates, apache inside. |
|||
|
||||
nerezus |
|
|||
![]() Вселенский отказник ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3330 Регистрация: 15.6.2005 Репутация: 12 Всего: 43 |
Если честно, то тема абсолютно не раскрыта =(
А я то уж было хотел неблок. сокеты почитать, открываю тему... и облом... |
|||
|
||||
MoLeX |
|
|||
![]() Местный пингвин ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 4076 Регистрация: 17.5.2007 Репутация: 46 Всего: 140 |
Неплохая статья на мой взгляд. держи +1
Это сообщение отредактировал(а) MoLeX - 26.1.2008, 10:33 -------------------- Amazing ![]() |
|||
|
||||
![]() ![]() ![]() |
Правила форума "PHP" | |
|
Новичкам:
Важно:
Внимание:
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | PHP: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |