Оглавление

25.10. Получение информации из сети Интернет

Открыть  для  чтения  можно  не  только  локально  сохраненный  файл,  но  и файл,  находящийся  на  другом  сервере  в  Интернете.  С  помощью  функций 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://wwwtest.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 и выведем отдельно заголовки ответа сервера и содержимое документа (листинг 52).


Листинг 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 = "wwwtest.ru";

Мы  не  указали протокол  соединения,  так  как протокол http:// по  умолчанию закреплен за 80-м портом.
Если необходимо получить только заголовки ответа сервера, то вместо метода GET следует указать метод HEAD. Для этого строку

$header = "GET $page HTTP/1.1\r\n";

следует заменить на

$header = "HEAD $page HTTP/1.1\r\n";

Данные можно передать не только методами GET и HEAD, но и методом POST, имитируя таким образом передачу данных формы. Рассмотрим это на примере (листинг 53).

 
Листинг 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");
Комментарии принадлежат их авторам. Мы не несем ответственности за их содержание.
Отправитель Нити