Загрузка HTML страниц в PHP: способы реализации

Раздел: Работа с сетью и файлами в PHP -> Работа с HTTP и URL в PHP

Основные методы сохранения HTML страниц в PHP

Самый надёжный и гибкий способ - использование расширения cURL.

Библиотека cURL позволяет отправлять HTTP запросы с полным контролем параметров: заголовки, таймауты, поддержка кук, редиректы, работа через прокси. Для сохранения HTML страницы используется функция curl_exec в паре с настройками через curl_setopt. Ниже приведён базовый пример.


$url = 'https://example.com';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$html = curl_exec($ch);
if (curl_errno($ch)) {
    // обработка ошибки
    $error = curl_error($ch);
} else {
    file_put_contents('page.html', $html);
}
curl_close($ch);

сохранение html страницы php (сохранение html-страницы с помощью php)

Шаги: инициализация дескриптора, настройка параметров, выполнение, сохранение результата в файл. Цель - получение полного HTML кода страницы с возможностью имитации браузера. Подходит для сайтов с простой структурой, не требующих выполнения JavaScript.

Как сохранить страницу без дополнительных расширений используя file_get_contents?

Если на сервере включена директива allow_url_fopen, можно применить встроенную функцию file_get_contents с контекстом потока. Это самый простой вариант, не требующий установки curl.


$options = [
    'http' => [
        'method' => 'GET',
        'header' => "User-Agent: Mozilla/5.0\r\n"
    ]
];
$context = stream_context_create($options);
$html = file_get_contents('https://example.com', false, $context);
if ($html !== false) {
    file_put_contents('page.html', $html);
}

Цель - быстрая загрузка небольших страниц на серверах с ограничениями на использование cURL.

Проблемы: эта функция не поддерживает автоматические редиректы (кроме CURL копии), ограничена настройками сервера, не умеет работать с куками и требует явного создания контекста для HTTPS.

Как выполнить потоковое сохранение большого HTML документа с помощью fopen?

Для очень крупных файлов, которые не умещаются в памяти, используют потоковое чтение через fopen и fread. Это экономит оперативную память.


$src = fopen('https://example.com', 'r');
$dest = fopen('page.html', 'w');
if ($src && $dest) {
    while (!feof($src)) {
        $chunk = fread($src, 8192);
        fwrite($dest, $chunk);
    }
    fclose($src);
    fclose($dest);
}

Цель - загрузка страниц размером от нескольких мегабайт (например, полные дампы или бинарные данные) при дефиците памяти.

Недостатки: отсутствие контроля редиректов, невозможность установки таймаутов на уровне потока, необходимость вручную управлять буферизацией.

Как загрузить HTML с помощью современного HTTP клиента Guzzle?

Composer пакет Guzzle предоставляет объектно ориентированный интерфейс, автоматически обрабатывает PSR-7 запросы, поддерживает пул соединений, куки, прокси, асинхронные запросы. Базовый пример для синхронной загрузки.


use GuzzleHttp\Client;

$client = new Client([
    'timeout'  => 30,
    'allow_redirects' => true
]);
$response = $client->get('https://example.com');
$html = $response->getBody()->getContents();
file_put_contents('page.html', $html);

Цель – интеграция с современными PHP фреймворками, где уже используется Composer, а также работа с API, требующая сложных заголовков и обработки ответов.

Возможные ошибки: отсутствие установленного Guzzle (требуется composer require guzzlehttp/guzzle), проблемы с сертификатами SSL, конфликты версий PHP.

Когда оправдано использование системной утилиты wget из PHP?

Если cURL отключён, а allow_url_fopen закрыт, можно вызвать внешнюю программу через exec или shell_exec.


exec('wget -O page.html https://example.com 2>&1', $output, $return_code);
if ($return_code === 0) {
    // успешно
}

Цель – экстренное решение на серверах с жёсткими ограничениями, где доступна только консольная утилита.

Безопасность: возможна инъекция команд при подстановке URL (обязательно экранирование), зависимость от установленного wget, медленная работа на каждом вызове.

Детальный пример с cURL: установка User-Agent, куки, таймаут, обработка редиректов

Пример

$url = 'https://httpbin.org/html';
$cookieFile = tempnam(sys_get_temp_dir(), 'CURLCOOKIE');
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_MAXREDIRS => 5,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    CURLOPT_COOKIEJAR => $cookieFile,
    CURLOPT_COOKIEFILE => $cookieFile,
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt'
]);
$html = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
    file_put_contents('page_with_cookies.html', $html);
    echo "Страница сохранена, код ответа: $httpCode";
} else {
    echo "Ошибка HTTP: $httpCode";
}
curl_close($ch);
unlink($cookieFile);
Страница сохранена, код ответа: 200

Пояснение:

массив параметров сокращает запись. Куки сохраняются во временный файл и отправляются при редиректах. Указание пути к CA сертификатам обеспечивает проверку SSL.

Потоковое сохранение с Guzzle и проверкой статуса

Пример

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

$client = new Client(['base_uri' => 'https://httpbin.org']);
try {
    $response = $client->get('/html', [
        'stream' => true, // возвращает поток
        'timeout' => 15
    ]);
    if ($response->getStatusCode() === 200) {
        $body = $response->getBody();
        $file = fopen('stream_page.html', 'w');
        while (!$body->eof()) {
            fwrite($file, $body->read(4096));
        }
        fclose($file);
        echo "Файл сохранён через поток";
    }
} catch (RequestException $e) {
    echo "Ошибка: " . $e->getMessage();
}
Файл сохранён через поток

Использование флага 'stream' => true позволяет читать тело ответа по частям, избегая загрузки всех данных в память.

Обработка ошибок при file_get_contents и контекст HTTPS

Пример

$context = stream_context_create([
    'http' => [
        'method' => 'GET',
        'timeout' => 10,
        'header' => "Accept: text/html\r\n"
    ],
    'ssl' => [
        'verify_peer' => true,
        'cafile' => '/path/to/cacert.pem'
    ]
]);
$html = @file_get_contents('https://self-signed.badssl.com/', false, $context);
if ($html === false) {
    $error = error_get_last();
    echo "Не удалось загрузить: " . $error['message'];
} else {
    file_put_contents('page_ssl.html', $html);
    echo "Успешно";
}
Не удалось загрузить: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed

Типичная ошибка – невалидный SSL сертификат. Решение: либо указать правильный cafile, либо временно отключить проверку (не рекомендуется).

Асинхронные запросы с Guzzle для массовой загрузки страниц

Пример

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['timeout' => 30]);
$urls = [
    'https://example.com',
    'https://httpbin.org/html',
    'https://google.com'
];
$promises = [];
foreach ($urls as $url) {
    $promises[$url] = $client->getAsync($url);
}
$results = Promise\settle($promises)->wait();
foreach ($results as $url => $result) {
    if ($result['state'] === 'fulfilled') {
        $html = $result['value']->getBody()->getContents();
        file_put_contents(basename($url) . '.html', $html);
    } else {
        echo "Ошибка загрузки $url: " . $result['reason'] . "\n";
    }
}
(файлы example.com.html, httpbin.org.html, google.com.html созданы)

Асинхронный подход позволяет одновременно отправлять несколько запросов, экономя общее время. Используется метод getAsync и ожидание через settle.

Сохранение HTML-страницы с помощью PHP - comments

En
сохранение html страницы php (php)