Как в PHP проверить, ведёт ли ссылка на реальную страницу

Раздел: PHP сеть -> Работа с URL

Проверка ссылки в PHP: основные подходы

Наиболее эффективное и гибкое решение для проверки доступности URL в PHP - использование библиотеки cURL. Она позволяет управлять таймаутами, обрабатывать редиректы, получать заголовки и тело ответа, а также работать с HTTPS и различными методами запросов.


$url = 'https://example.com';
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HEADER         => true,
    CURLOPT_NOBODY         => true,       // получаем только заголовки
    CURLOPT_TIMEOUT        => 10,         // таймаут в секундах
    CURLOPT_FOLLOWLOCATION => true,       // следовать редиректам
    CURLOPT_MAXREDIRS      => 5,
    CURLOPT_SSL_VERIFYPEER => true,       // проверка SSL сертификата
]);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);

if ($error) {
    echo 'Ошибка cURL: ' . $error;
} elseif ($httpCode >= 200 && $httpCode < 400) {
    echo 'Ссылка доступна. Код ответа: ' . $httpCode;
} else {
    echo 'Ссылка недоступна. Код ответа: ' . $httpCode;
}

Php проверить ссылку (проверить ссылку в php)

Типичные проблемы и их решение:

  • Ошибка SSL: если сертификат самоподписан или устарел, можно временно отключить проверку (CURLOPT_SSL_VERIFYPEER => false), но это снижает безопасность.
  • Таймаут: при медленных сайтах увеличить CURLOPT_TIMEOUT или использовать CURLOPT_CONNECTTIMEOUT отдельно.
  • Редиректы: если сайт делает много перенаправлений, увеличить CURLOPT_MAXREDIRS.
  • Заблокированный User-Agent: некоторые серверы требуют определённый заголовок; установить CURLOPT_USERAGENT.

Цель использования cURL - надёжная проверка любого HTTP/HTTPS URL с полным контролем параметров запроса.

Как проверить ссылку с помощью get_headers?

Функция get_headers() возвращает массив заголовков ответа сервера. Это простой способ, не требующий дополнительных расширений.


$url = 'https://example.com';
$headers = @get_headers($url);
if ($headers && strpos($headers[0], '200') !== false) {
    echo 'Ссылка работает (код 200 OK)';
} else {
    echo 'Ссылка не отвечает или вернула ошибку';
}

Id ссылки php (идентификатор ссылки в php)

Проблемы:

  • По умолчанию get_headers() не следует редиректам. Чтобы получить финальный код, нужно вызвать её с флагом stream_context_set_default или использовать обёртку.
  • На многих хостингах отключена директива allow_url_fopen, тогда функция вернёт false.
  • Нет контроля таймаута - может зависнуть надолго.

Применяется для быстрой проверки, когда не требуется тонкая настройка.

Как использовать file_get_contents с контекстом для проверки?

Можно создать потоковый контекст и прочитать только первые байты, чтобы не загружать весь контент.


$url = 'https://example.com';
$opts = [
    'http' => [
        'method' => 'HEAD',
        'timeout' => 5,
        'follow_location' => 1,
        'max_redirects' => 3,
    ],
    'ssl' => [
        'verify_peer' => true,
    ]
];
$context = stream_context_create($opts);
$result = @file_get_contents($url, false, $context);
if ($result !== false) {
    echo 'Ссылка доступна';
} else {
    echo 'Ошибка при открытии URL';
}

активная ссылка php (создание активной ссылки в php)

Ошибки:

  • allow_url_fopen должен быть включён.
  • При HEAD-запросе некоторые серверы могут отвечать некорректно, лучше использовать GET с небольшим лимитом на чтение.

Случай применения - когда cURL недоступен, но требуется минимальный контроль.

Как проверить существование домена через DNS?

Иногда достаточно убедиться, что домен разрешается в IP. Для этого используется checkdnsrr().


$domain = 'example.com';
if (checkdnsrr($domain, 'A')) {
    echo 'DNS запись найдена';
} else {
    echo 'Домен не существует или не имеет A-записи';
}

Php ссылки (работа с url и ссылками в php)

Нюансы:

  • Функция не проверяет, работает ли веб-сервер - только DNS.
  • На Windows до PHP 5.3 эта функция не поддерживалась.

Применение: предварительная фильтрация URL перед более дорогой проверкой.

Как проверить формат URL с помощью filter_var?

filter_var() с флагом FILTER_VALIDATE_URL проверяет синтаксис URL, но не его доступность.


$url = 'https://example.com';
if (filter_var($url, FILTER_VALIDATE_URL)) {
    echo 'URL корректен по формату';
} else {
    echo 'Некорректный URL';
}

Php адрес страницы (адрес страницы в php)

Ограничения:

  • Допускает несуществующие домены (например, https://nonexistent123456.com).
  • Не проверяет протокол - любая строка с :// может считаться валидной.

Используется для первичной валидации ввода пользователя.

Как выполнить проверку через сокет?

Можно открыть TCP-соединение к хосту на порт 80 или 443. Это низкоуровневый способ.


$url = 'example.com';
$host = parse_url($url, PHP_URL_HOST);
$port = 80;
$fp = @fsockopen($host, $port, $errno, $errstr, 5);
if ($fp) {
    echo 'Хост доступен по порту ' . $port;
    fclose($fp);
} else {
    echo 'Ошибка: ' . $errstr;
}

Недостатки:

  • Не проверяет HTTP-ответ, только TCP-соединение.
  • Не обрабатывает HTTPS автоматически - нужен отдельный поток с SSL.

Применяется для быстрой проверки, работает ли сервер вообще.

Расширенные примеры проверки ссылок

1. cURL с детальной обработкой ошибок и редиректов

Пример

function checkUrl($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER         => true,
        CURLOPT_NOBODY         => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_CAINFO         => '/path/to/cacert.pem', // путь к корневым сертификатам
        CURLOPT_USERAGENT      => 'Mozilla/5.0 (compatible; PHP Bot)',
    ]);
    $response = curl_exec($ch);
    $info = curl_getinfo($ch);
    $error = curl_error($ch);
    curl_close($ch);

    if ($error) {
        return ['success' => false, 'error' => $error];
    }
    $httpCode = $info['http_code'];
    $finalUrl = $info['url']; // конечный URL после редиректов
    return [
        'success'   => $httpCode >= 200 && $httpCode < 400,
        'code'      => $httpCode,
        'final_url' => $finalUrl,
        'redirect_count' => $info['redirect_count'],
    ];
}

// Пример вызова
$result = checkUrl('https://example.com/redirect');
print_r($result);
Array
(
    [success] => 1
    [code] => 200
    [final_url] => https://example.com/target
    [redirect_count] => 2
)

В примере функция возвращает не только булевый результат, но и конечный URL, что полезно для анализа редиректов.

2. Проверка с помощью get_headers и обработка редиректов через контекст

Пример

$url = 'https://example.com';
$opts = [
    'http' => [
        'method' => 'GET',
        'timeout' => 10,
        'follow_location' => 1,
        'max_redirects' => 3,
        'ignore_errors' => true, // не генерировать предупреждения при ошибках HTTP
    ]
];
$context = stream_context_create($opts);
$headers = @get_headers($url, 1, $context);
if ($headers && isset($headers[0])) {
    $statusLine = $headers[0];
    preg_match('/\d{3}/', $statusLine, $matches);
    $code = (int)$matches[0];
    echo 'HTTP код: ' . $code;
    if ($code >= 200 && $code < 400) {
        echo ' - ссылка рабочая';
    } else {
        echo ' - ссылка не отвечает';
    }
} else {
    echo 'Не удалось получить заголовки';
}
HTTP код: 200 - ссылка рабочая

Использование ignore_errors => true позволяет избежать предупреждений о кодах 4xx/5xx.

3. Многопоточная проверка нескольких URL с помощью curl_multi

Пример

$urls = [
    'https://example1.com',
    'https://example2.com',
    'https://example3.com',
];

$multi = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_NOBODY => true,
        CURLOPT_TIMEOUT => 5,
        CURLOPT_FOLLOWLOCATION => true,
    ]);
    curl_multi_add_handle($multi, $ch);
    $handles[$i] = $ch;
}

$active = null;
do {
    $status = curl_multi_exec($multi, $active);
} while ($status === CURLM_CALL_MULTI_PERFORM || $active);

foreach ($handles as $i => $ch) {
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    echo "URL $i: код $code, ошибка: $error\n";
    curl_multi_remove_handle($multi, $ch);
    curl_close($ch);
}
curl_multi_close($multi);
URL 0: код 200, ошибка: 
URL 1: код 404, ошибка: 
URL 2: код 0, ошибка: Connection timed out after 5000 milliseconds

Параллельная проверка ускоряет работу при большом количестве ссылок.

4. Проверка ссылки с использованием fsockopen для HTTPS

Пример

$url = 'https://example.com';
$host = parse_url($url, PHP_URL_HOST);
$port = 443;

$context = stream_context_create([
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
    ]
]);

$fp = @stream_socket_client(
    "ssl://$host:$port",
    $errno,
    $errstr,
    5,
    STREAM_CLIENT_CONNECT,
    $context
);

if ($fp) {
    // отправляем простой HEAD-запрос
    $request = "HEAD / HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n";
    fwrite($fp, $request);
    $response = fread($fp, 4096);
    fclose($fp);
    echo 'Ответ получен: ' . substr($response, 0, 50);
} else {
    echo 'Ошибка соединения: ' . $errstr;
}
Ответ получен: HTTP/1.1 200 OK
Date: Mon, 12 Feb 2024 12:00:00 GMT
Server: Apache

Такой метод может быть полезен, если нет cURL и allow_url_fopen отключён.

5. Валидация URL с учётом списка разрешённых доменов

Пример

$allowedHosts = ['example.com', 'sub.example.com'];
$url = 'https://example.com/page';

$parsed = parse_url($url);
if ($parsed === false || !isset($parsed['host'])) {
    echo 'Некорректный URL';
} elseif (!in_array($parsed['host'], $allowedHosts)) {
    echo 'Домен не разрешён';
} else {
    echo 'URL прошёл проверку домена';
    // далее можно проверить доступность с помощью cURL
}
URL прошёл проверку домена

Такой подход применяется, когда нужно ограничить проверку только доверенными источниками.

Проверить ссылку в PHP - comments

En
Php проверить ссылку (php)