/ парсеры

Что такое контекст потока create_stream_context?

При простом парсинге используется встроеная php-функция file_get_contents. В основном эту функцию применяют без дополнительный надстроек над ней, просто указывая адрес, который нужно открыть: file_get_contenst('http://site.com/page.html'), и этого хватает.
Однако, бывают случаи, когда всё-же, обычной работы file_get_contents недостаточно. К примеру, нужно отправить POST-запрос, cookie, или работать через прокси, а переход на curl в рамках данной системе невозможен, или нерационален. В этом случае единственным решением является изменение контекста потока функции.

Контекст потока - это изменение поведения при получении данных, который меняется функцией stream_context_create. Можно указать тип запроса (GET, POST, PUT, и любой другой поддерживаемый http-метод), прокси, заголовки, и т.д.. Все опции можно посмотреть по ссылке
Эта функция и есть ответом на вопрос: "как отправить post запрос file_get_contents".

Если не передавать в file_get_contents контекст, то это не означает, что его не будет. Просто, он будет проставляться дефолтным. Увидеть это можно явно, прочитав информацию о запросе, который создаётся стандартным потоком:
context_standart

Однако, сегодня нас это не устраивает. И наша задача - изменить запрос на POST, передать некоторые данные в теле запроса, и изменить заголовки.
Функция stream_context_create принимает ассоциативный массив параметров. И ввиду того, что мы будем делать http-запрос, то необходимо передать вложенный массив с ключём http, указав method, header и content:


stream_context_create([
    'http' => [
        'method'  => 'POST', //метод запроса
        'header'  => 'Content-type: application/x-www-form-urlencoded', //заголовки
        'content' => 'key1=value1'
    ]
]);

Этот код создаёт новый http поток, которые изменяет method на POST, проставляет заголовок, и передаёт POST-параметр key1 = value1, который попадает в массив $_POST.

Однако, простого вызова функции недостаточно для того, чтобы эти изменения вступили в силу. Теперь необходимо передать в функцию этот контекст. Это удобно, когда для разных запросов нужно указывать разные контексты.
В итоге, функция будет иметь вид:
file_get_contents(url, false, stream_context_create(data))

В нашем случае:


//по правилам http-запросов, заголовки отделяются символом переноса строки (\r\n), 
//а имена и значения заголовков отделяются двоеточием
$headers = [
    'Content-type: application/x-www-form-urlencoded', //заголовок
    'Cookie: foo=bar;two=12' //куки, которые так же передаются в заголовке
];

$context = stream_context_create([
    'http' => [
        'method'    => 'POST',
        'content'   => 'key=value&key2=value2', //формат записи post-данных
        'header'    =>  implode("\r\n", $headers), //для удобства заголовки вынесли в массив, и объединили их функцией implode
        'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
    ]
]);

$result = file_get_contents($url, false, $context);

И, в итоге, получаем финальный результат:
context-result
Который демонстирует, что данные пришли запросом POST, и с указанными нами параметрами.


Для лучшего усвоения материала, можем написать простой скрипт, перевода текста с английского на русский, используя yandex-переводчик.
Перед этим, необходимо получить API-ключ на странице

Сейчас, когда уже есть API-ключ, можем выполнить первый запрос на перевод текста. Однако, сначала, в соответствии с документацией, сформируем параметры самого запроса:


$data = [
    'text' => 'Привет мир?', //текст
    'lang' => 'ru-en', //язык перевода с русского на английский
    'key' => 'ВАШ КЛЮЧ' //API ключ, полученный ранее
];

Однако, в виде массива отправить данные не получится, нам нужно привести их к виду: key1=valu1&key2=value2...
И, для того, чтобы не писать это вручную, существует специальная функция httt_build_query(), которая и приводит массив к строке такого вида.

И теперь осталось только отправить запрос:


$context = stream_context_create([
    'http' => [
        'method'    => 'POST',
        'content'   => http_build_query($data)
    ]
]);

$response = file_get_contents($url, false, $context);
$result = json_decode($response, true);

Здесь результат был получен в специальном формате json, который с помощью функции json_decode приводится к виду массива. И вуаля, ожидаемый результат:
result-yandex
А сам перевод текста содержится в массиве под ключём text

Теперь вы знаете, назначение функции stream_context_create, как подменять контекст, и отправлять POST-данные простой функцией file_get_contents, а так же, на примере запроса к API yandex-переводчика, узнали, как парсить json.