Получение информации из сети Интернет
Открыть для чтения можно не только локально сохраненный файл, но и файл, находящийся на другом сервере в Интернете. С помощью функций fopen(), file() и file_get_contents() файл можно получить как по прото- колу HTTP, так и по протоколу FTP. Для этого достаточно указать соответст- вующий протокол в URL-адресе, переданном в качестве параметра <Путь к файлу> этим функциям:
http://www.site.ru/file.txt ftp://www.site.ru/file.txt
Как вам уже известно, в логах сервера отображается программное обеспече- ние сделавшего запрос клиента. С помощью директивы user_agent в файле php.ini можно задать свое название. Для этого вместо строки
; user_agent="PHP"
нужно написать другую, например:
user_agent="MySpider/1.0"
При обработке больших файлов может потребоваться больше времени, чем задано по умолчанию (30 секунд). Увеличить время работы сценария можно с помощью директивы max_execution_time:
max_execution_time = 120
Кроме того, следует учитывать, что с помощью директивы allow_url_fopen можно запретить открытие внешних файлов. Для получения информации из сети Интернет значение директивы должно быть равно On:
allow_url_fopen = On
Получить документ с помощью функции fopen() можно следующим обра-
зом:
$host = ‘http://wwwadmin.ru/testrobots.php?var1=10&var2=15′;
$content = ”;
$header = "User-Agent: MySpider/1.0\r\n";
$header .= "Cookie: test=5\r\n";
$option = array(
‘http’ => array(‘method’ => ‘GET’, ‘header’=> $header)
);
$context = stream_context_create($option);
@$file = fopen($host, ‘r’, false, $context);
if ($file) {
while(!feof($file)) {
$content .= fgets($file, 1024);
}
fclose($file);
echo ‘<b>Содержимое страницы:</b><br><br>’;
echo ‘<pre>’ . htmlspecialchars($content) . ‘</pre>’;
}
else {
echo ’Не удалось открыть файл’;
}
Если необходимо получить документ в виде массива или строки, то можно воспользоваться функциями file() и file_get_contents():
$host = ‘http://wwwadmin.ru/testrobots.php?var1=10&var2=15′;
$header = "User-Agent: MySpider/1.0\r\n";
$header .= "Cookie: test=5\r\n";
$option = array(
‘http’ => array(‘method’ => ‘GET’, ‘header’=> $header)
);
$context = stream_context_create($option);
$file1 = implode(”, file($host, 0, $context));
if ($file1) {
echo ‘<b>Содержимое страницы (file()):</b><br><br>’;
echo ‘<pre>’ . htmlspecialchars($file1) . ‘</pre>’;
}
$file2 = file_get_contents($host, 0, $context);
if ($file2) {
echo ‘<b>Содержимое страницы (file_get_contents()):</b><br><br>’;
echo ‘<pre>’ . htmlspecialchars($file2) . ‘</pre>’;
}
Функция fsockopen() позволяет получить не только содержимое документа, но и все заголовки ответа сервера. Эта функция очень универсальна и позво- ляет открыть соединение не только с портом 80, но и с любым другим. На- пример, можно передать сообщение почтовому серверу на 25-й порт. Функ- ция имеет следующий формат:
fsockopen(<Хост>, <Порт>, [<Номер ошибки>], [<Сообщение об ошибке>], [<Таймаут>]);
Функция устанавливает сетевое соединение и возвращает его дескриптор. Если соединение не установлено, то функция возвращает false. Получить номер и сообщение об ошибке можно с помощью необязательных парамет- ров <Номер ошибки> и <Сообщение об ошибке>. В необязательном параметре
<Таймаут> можно указать максимальное время, в течение которого произво-
дится попытка соединения (в секундах). Если параметр не указан, то будет использовано значение из директивы default_socket_timeout файла php.ini:
default_socket_timeout = 60
После установки соединения необходимо передать заголовки запроса. Между собой заголовки должны разделяться с помощью комбинации символов \r\n. Заголовки должны отделяться от тела запроса с помощью комбинации
\r\n\r\n.
Открытым соединением можно манипулировать как обычным файлом с по- мощью функций fgets(), fwrite(), feof() и др. Закрыть соединение позво- ляет функция fclose().
Функция stream_set_blocking() позволяет установить режим блокировки соединения. Имеет следующий формат:
stream_set_blocking(<Дескриптор соединения>, <Режим блокировки>);
Если режим равен 1, то функции чтения будут ожидать полного завершения передачи данных. Если указать 0, то блокировка снимается.
В качестве примера получим документ методом GET и выведем отдельно за-
головки ответа сервера и содержимое документа (листинг 5.52).
Листинг 5.52. Чтение документа методом GET
<?php
$page = "/testrobots.php?var1=10&var2=15";
$port = "80";
$host = "wwwadmin.ru";
$header = "GET $page HTTP/1.1\r\n";
$header .= "Host: $host\r\n";
$header .= "User-Agent: MySpider/1.0\r\n";
$header .= "Accept: text/html, text/plain, application/xml\r\n";
$header .= "Accept-Language: ru, ru-RU\r\n";
$header .= "Accept-Charset: windows-1251\r\n";
$header .= "Accept-Encoding: identity\r\n";
$header .= "Connection: close\r\n";
$header .= "Cookie: test=5\r\n";
$header .= "\r\n";
@$fsock = fsockopen($host, $port, $err, $err_text, 30);
if ($fsock) { stream_set_blocking($fsock, 0); fwrite($fsock, $header);
$s = 5;
$content = "";
$headers = "";
$buffer = "";
while(!feof($fsock)) {
$buffer = fgets($fsock, 1024);
if ($buffer == "\r\n") { $s = 10; }
if ($s == 5) { $headers .= $buffer; }
else { $content .= $buffer; }
}
fclose($fsock);
}
else {
echo "Произошла ошибка " . $err . ": " . $err_text;
}
echo "<b>Заголовки ответа сервера:</b><br><br>";
echo "<pre>" . htmlspecialchars($headers) . "</pre>"; echo "<br><br><b>Содержимое страницы:</b><br><br>"; echo "<pre>" . htmlspecialchars($content) . "</pre>";
?>
Обратите внимание на строку
$host = "wwwadmin.ru";
Мы не указали протокол соединения, так как протокол http:// по умолча-
нию закреплен за 80-м портом.
Если необходимо получить только заголовки ответа сервера, то вместо мето-
да GET следует указать метод HEAD. Для этого строку
$header = "GET $page HTTP/1.1\r\n";
следует заменить на
$header = "HEAD $page HTTP/1.1\r\n";
Данные можно передать не только методами GET и HEAD, но и методом POST, имитируя таким образом передачу данных формы. Рассмотрим это на приме- ре (листинг 5.53).
Листинг 5.53. Имитация передачи данных методом POST
<?php
$page = "/testrobots.php";
$port = "80";
$host = "wwwadmin.ru";
$header = "POST $page HTTP/1.1\r\n";
$header .= "Host: $host\r\n";
$header .= "User-Agent: MySpider/1.0\r\n";
$header .= "Accept: text/html, text/plain, application/xml\r\n";
$header .= "Accept-Language: ru, ru-RU\r\n";
$header .= "Accept-Charset: windows-1251\r\n";
$header .= "Accept-Encoding: identity\r\n";
$header .= "Connection: close\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: 15\r\n";
$header .= "Cookie: test=5\r\n";
$header .= "\r\n";
@$fsock = fsockopen($host, $port, $err, $err_text, 30);
if ($fsock) { stream_set_blocking($fsock, 0); fwrite($fsock, $header); fwrite($fsock, "var1=10&var2=15");
$s = 5;
$content = "";
$headers = "";
$buffer = "";
while(!feof($fsock)) {
$buffer = fgets($fsock, 1024);
if ($buffer == "\r\n") { $s = 10; }
if ($s == 5) { $headers .= $buffer; }
else { $content .= $buffer; }
}
fclose($fsock);
}
else {
echo "Произошла ошибка " . $err . ": " . $err_text;
}
echo "<b>Заголовки ответа сервера:</b><br><br>";
echo "<pre>" . htmlspecialchars($headers) . "</pre>"; echo "<br><br><b>Содержимое страницы:</b><br><br>"; echo "<pre>" . htmlspecialchars($content) . "</pre>";
?>
В этом примере мы заменили метод передачи данных с GET на POST и добави-
ли два заголовка:
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: 15\r\n";
Первый заголовок имитирует передачу данных формы, а второй указывает длину данных, переданных методом POST. Сами данные мы передаем после всех заголовков:
fwrite($fsock, "var1=10&var2=15");
Использование библиотеки CURL
Вместо перечисленных функций для получения информации из сети Интер- нет можно воспользоваться библиотекой CURL (Client URL Library). Чтобы использовать библиотеку CURL, необходимо в файле php.ini убрать символ комментария (;) перед строкой
;extension=php_curl.dll
В библиотеку CURL входят следующие функции:
? curl_init([<URL-адрес>]) создает новый сеанс и возвращает идентифи-
катор;
? curl_close(<Идентификатор>) завершает сеанс;
? curl_setopt(<Идентификатор>, <Параметр>, <Значение>) устанавлива-
ет параметры сеанса.
<Параметр> может равняться одной из следующих констант, определяю-
щих смысл параметра <Значение>:
• CURLOPT_URL — URL-адрес;
• CURLOPT_PORT — номер порта;
• CURLOPT_USERAGENT — значение HTTP-заголовка User-Agent;
• CURLOPT_RETURNTRANSFER — если параметр не равен 0, то функция curl_exec() будет возвращать результат, а не выводить его сразу в Web-браузер;
• CURLOPT_TIMEOUT — максимальное время выполнения операции (в секундах);
• CURLOPT_HEADER — если параметр не равен 0, то результат будет включать не только содержимое документа, но и заголовки ответа сервера;
• CURLOPT_NOBODY — если параметр не равен 0, то результат будет включать только заголовки ответа сервера;
• CURLOPT_POST — если параметр не равен 0, то запрос будет оправлен методом POST. Кроме того, будет добавлен HTTP-заголовок Content-
Type со значением application/x-www-form-urlencoded. Этот заго-
ловок обычно используется при передаче данных формы;
• CURLOPT_POSTFIELDS — строка, содержащая данные для передачи ме-
тодом POST;
• CURLOPT_REFERER — значение HTTP-заголовка Referer;
• CURLOPT_COOKIE — значение HTTP-заголовка Cookie;
• CURLOPT_FOLLOWLOCATION — если параметр не равен 0, то перенаправ-
ления будут обрабатываться автоматически;
• CURLOPT_HTTPHEADER — массив с дополнительными HTTP-заголов-
ками;
• CURLOPT_FILE — дескриптор файла, в который будет выведен резуль-
тат операции;
• CURLOPT_WRITEHEADER — дескриптор файла, в который будут выведе-
ны полученные заголовки;
• CURLOPT_STDERR — дескриптор файла, в который будут выводиться сообщения об ошибках;
? curl_exec(<Идентификатор>) выполняет запрос;
? curl_getinfo(<Идентификатор>, [<Параметр>]) возвращает информа- цию о последней операции. Если <Параметр> не указан, то функция воз- вращает ассоциативный массив. Если <Параметр> равен CURLINFO_HTTP_CODE, то функция возвращает последний полученный код HTTP. Если <Параметр> равен CURLINFO_CONTENT_TYPE, то функция воз- вращает содержимое полученного заголовка Content-Type или значение NULL, если заголовка нет в ответе сервера;
? curl_errno(<Идентификатор>) возвращает код последней ошибки;
? curl_error(<Идентификатор>) позволяет получить строку с описанием последней ошибки.
Пример запроса методом GET с получением содержимого документа и всех заголовков ответа сервера приведен в листинге 5.54.
Листинг 5.54. Получение документа методом GET с использованием библиотеки CURL
<?php
$url = "http://wwwadmin.ru/testrobots.php?var1=1&var2=5&var3=45";
@$curl=curl_init();
if (!curl_errno($curl)) { curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_USERAGENT, "MySpider/1.0"); curl_setopt($curl, CURLOPT_HEADER, 1);
$headers = array(
"Accept: text/html, text/plain, application/xml", "Accept-Language: ru, ru-RU",
"Accept-Charset: windows-1251", "Accept-Encoding: identity", "Connection: close",
"Cookie: test=5"
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($curl);
if (!curl_errno($curl)) {
echo "<b>Код возврата:</b> ";
echo curl_getinfo($curl, CURLINFO_HTTP_CODE);
echo "<br><b>Заголовок Content-Type:</b> ";
echo curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
echo "<br><br>";
echo "<b>Содержимое страницы:</b><br><br>";
echo "<pre>" . htmlspecialchars($content) . "</pre>";
}
else {
echo "Произошла ошибка " . curl_errno($curl) . ": ";
echo curl_error($curl);
}
curl_close($curl);
}
else {
echo "Произошла ошибка " . curl_errno($curl) . ": ";
echo curl_error($curl);
}
?>
В ряде случаев достаточно получить только заголовки ответа сервера (лис-
тинг 5.55).
Листинг 5.55. Получение заголовков ответа с использованием библиотеки CURL
<?php
$url = "http://wwwadmin.ru/testrobots.php?var1=1&var2=5&var3=45";
@$curl=curl_init();
if (!curl_errno($curl)) { curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_USERAGENT, "MySpider/1.0"); curl_setopt($curl, CURLOPT_HEADER, 1); curl_setopt($curl, CURLOPT_NOBODY, 1);
$headers = array(
"Accept: text/html, text/plain, application/xml", "Accept-Language: ru, ru-RU",
"Accept-Charset: windows-1251", "Accept-Encoding: identity", "Connection: close",
"Cookie: test=5"
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($curl);
if (!curl_errno($curl)) {
echo "<b>Код возврата:</b> ";
echo curl_getinfo($curl, CURLINFO_HTTP_CODE);
echo "<br><b>Заголовок Content-Type:</b> ";
echo curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
echo "<br><br>";
echo "<b>Заголовки ответа сервера:</b><br><br>";
echo "<pre>" . htmlspecialchars($content) . "</pre>";
}
else {
echo "Произошла ошибка " . curl_errno($curl) . ": ";
echo curl_error($curl);
}
curl_close($curl);
}
else {
echo "Произошла ошибка " . curl_errno($curl) . ": ";
echo curl_error($curl);
}
?>
Приведем также пример запроса методом POST, в котором мы не получа- ем заголовки ответа сервера, а только выводим содержимое страницы (лис- тинг 5.56).
Листинг 5.56. Передача данных методом POST с использованием библиотеки CURL
<?php
$url = "http://wwwadmin.ru/testrobots.php";
@$curl=curl_init();
if (!curl_errno($curl)) { curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_USERAGENT, "MySpider/1.0"); curl_setopt($curl, CURLOPT_HEADER, 0);
$headers = array(
"Accept: text/html, text/plain, application/xml", "Accept-Language: ru, ru-RU",
"Accept-Charset: windows-1251", "Accept-Encoding: identity", "Connection: close",
"Cookie: test=5"
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, "var1=1&var2=5&var3=45");
$content = curl_exec($curl);
if (!curl_errno($curl)) {
echo "<b>Код возврата:</b> ";
echo curl_getinfo($curl, CURLINFO_HTTP_CODE);
echo "<br><b>Заголовок Content-Type:</b> ";
echo curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
echo "<br><br>";
echo "<b>Содержимое страницы:</b><br><br>";
echo "<pre>" . htmlspecialchars($content) . "</pre>";
}
else {
echo "Произошла ошибка " . curl_errno($curl) . ": ";
echo curl_error($curl);
}
curl_close($curl);
}
else {
echo "Произошла ошибка " . curl_errno($curl) . ": ";
echo curl_error($curl);
}
?>
Источник: Прохоренок Н. А. HTML, JavaScript, PHP и MySQL. Джентльменский набор Web-мастера. — 3-е изд., перераб. и доп. — СПб.: БХВ-Петербург, 2010. — 912 с.: ил. + Видеокурс (на CD-ROM) — (Профессиональное программирование)