Сетевое программирование на PHP: от сокетов до веб-скрапинга

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему сетевое программирование на PHP — это не страшно, а интересно

Когда слышишь «сетевое программирование», в голове сразу всплывают образы суровых C++-разработчиков, колдующих над низкоуровневыми сокетами, или админов, пишущих скрипты на Python для мониторинга сети. А PHP? Разве его удел — не просто выводить «Hello, World!» на сайте?

На самом деле, PHP — это мощный инструмент для сетевого взаимодействия. Он умеет открывать сокеты, ходить по HTTP, работать с WebSocket и даже парсить чужие сайты. И всё это — без установки дополнительных расширений (ну, почти).

В этой статье мы разберём ключевые техники сетевого программирования на PHP. Вы узнаете, как написать простой TCP-клиент, как автоматизировать запросы к API, как парсить сайты и как создать свой чат на WebSocket. Поехали!

1. Основы сокетов в PHP

Сокеты — это низкоуровневый способ общения между программами по сети. В PHP работа с сокетами реализована через функции семейства socket_*. Они есть в стандартной сборке, но иногда требуют включения расширения sockets в php.ini.

Создание TCP-клиента

Напишем простой клиент, который подключается к серверу (например, к time.nist.gov — серверу точного времени) и читает ответ:

<?php
$host = 'time.nist.gov';
$port = 37;

// Создаём сокет
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
    echo "Не удалось создать сокет: " . socket_strerror(socket_last_error()) . "\n";
    exit;
}

// Подключаемся
$result = socket_connect($socket, $host, $port);
if ($result === false) {
    echo "Не удалось подключиться: " . socket_strerror(socket_last_error($socket)) . "\n";
    exit;
}

// Читаем 4 байта (время в формате NTP)
$bytes = socket_read($socket, 4);
if ($bytes === false) {
    echo "Ошибка чтения: " . socket_strerror(socket_last_error($socket)) . "\n";
    exit;
}

// Закрываем сокет
socket_close($socket);

// Преобразуем бинарные данные в число
$time = unpack('N', $bytes)[1];
// NTP-время отсчитывается от 1900 года, отнимаем 70 лет (секунды)
$unix_time = $time - 2208988800;
echo "Текущее время (UNIX): " . date('Y-m-d H:i:s', $unix_time) . "\n";
?>

Этот код соединяется с сервером точного времени, читает 4 байта (время в формате NTP) и преобразует их в понятную дату. Обратите внимание на обработку ошибок — в сетевом программировании это критично.

Создание простого TCP-сервера

А теперь напишем свой мини-сервер, который будет принимать соединения и отвечать «Hello, client!»:

<?php
$host = '127.0.0.1';
$port = 8080;

$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, $host, $port);
socket_listen($server, 5);

echo "Сервер запущен на $host:$port\n";

while (true) {
    $client = socket_accept($server);
    if ($client === false) {
        continue;
    }
    $msg = "Hello, client!\n";
    socket_write($client, $msg, strlen($msg));
    socket_close($client);
}
socket_close($server);
?>

Запустите скрипт в консоли (php server.php), а затем подключитесь к нему через telnet: telnet 127.0.0.1 8080. Увидите приветствие.

Совет: Для реальных проектов используйте готовые библиотеки вроде ReactPHP или Amp — они дают асинхронность и удобный API.

2. HTTP-запросы с cURL

cURL — это швейцарский нож для работы с HTTP в PHP. Он умеет делать GET, POST, работать с куками, заголовками, прокси и сертификатами. Расширение curl обычно предустановлено.

Базовый GET-запрос

<?php
$ch = curl_init('https://api.github.com/repos/php/php-src');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP Script');
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === 200) {
    $data = json_decode($response, true);
    echo "Репозиторий: " . $data['full_name'] . "\n";
    echo "Звёзд: " . $data['stargazers_count'] . "\n";
} else {
    echo "Ошибка: HTTP $http_code\n";
}
?>

Обратите внимание: мы устанавливаем User-Agent — многие API (например, GitHub) блокируют запросы без этого заголовка.

POST-запрос с отправкой JSON

<?php
$ch = curl_init('https://jsonplaceholder.typicode.com/posts');
$payload = json_encode([
    'title' => 'Сетевое программирование на PHP',
    'body' => 'Это тестовый пост',
    'userId' => 1
]);

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Content-Length: ' . strlen($payload)
    ]
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === 201) {
    $data = json_decode($response, true);
    echo "Создан пост с ID: " . $data['id'] . "\n";
}
?>

Работа с прокси и таймаутами

Если вам нужно парсить сайты через прокси или ставить ограничения по времени:

<?php
$ch = curl_init('https://httpbin.org/ip');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_PROXY => 'http://user:pass@proxy.example.com:3128',
    CURLOPT_TIMEOUT => 10, // секунд
    CURLOPT_CONNECTTIMEOUT => 5
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>

3. Парсинг сайтов (веб-скрапинг)

Парсинг — одна из самых популярных задач сетевого программирования. PHP справляется с ней отлично, особенно в связке c cURL и библиотеками для работы с HTML.

Важно: Всегда проверяйте файл robots.txt и соблюдайте законы об авторских правах. Не парсьте сайты, которые это запрещают.

Парсинг с помощью регулярных выражений

Самый простой (но хрупкий) способ — использовать preg_match:

<                

Блоги

Рекомендаций по книгам