Каков наилучший способ проверить, существует ли URL в PHP? - PullRequest
12 голосов
/ 14 декабря 2010

Каков наилучший способ увидеть, что URL существует, а ответ не 404?

Ответы [ 4 ]

24 голосов
/ 14 декабря 2010

Вы можете использовать get_headers($url)

Пример 2 из Вручную:

<?php
// By default get_headers uses a GET request to fetch the headers. If you
// want to send a HEAD request instead, you can do so using a stream context:
stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);
print_r(get_headers('http://example.com'));

// gives
Array
(
    [0] => HTTP/1.1 200 OK 
    [Date] => Sat, 29 May 2004 12:28:14 GMT
    [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
    [ETag] => "3f80f-1b6-3e1cb03b"
    [Accept-Ranges] => bytes
    [Content-Length] => 438
    [Connection] => close
    [Content-Type] => text/html
)

Первый элемент массива будет содержать код состояния ответа HTTP.Вы должны проанализировать это.

Обратите внимание, что функция get_headers в примере выдаст запрос HTTP HEAD, что означает, что он не будет извлекать тело URL.Это более эффективно, чем использование запроса GET, который также возвращает тело.

Также обратите внимание, что при установке контекста по умолчанию любые последующие вызовы, использующие контекст потока http, теперь будут вызывать HEADЗапросы.Поэтому убедитесь, что вы сбросили контекст по умолчанию для использования GET снова.

PHP также предоставляет переменную $ http_response_header

Массив $http_response_header аналогиченк функции get_headers().При использовании HTTP-оболочки , $http_response_header будет заполняться заголовками HTTP-ответа.$http_response_header будет создано в локальной области видимости.

Если вы хотите загрузить содержимое удаленного ресурса, вам не нужно делать два запроса (один, чтобы увидеть, существует ли ресурс, и один, чтобы его извлечь), но только один.В этом случае используйте что-то вроде file_get_contents, чтобы извлечь содержимое, а затем проверить заголовки из переменной.

0 голосов
/ 20 июня 2019

Я использую эту функцию, поскольку она также проверяет и возвращает протокол URL, если не найден.

$theUrl = 'google.com';

function isValidURL($url) { 
    $urlRegex = '@(http(s)?)?(://)?(([a-zA-Z])([-\w]+\.)+([^\s\.]+[^\s]*)+[^,.\s])@';
    if(preg_match($urlRegex, $url)){
        return preg_replace($urlRegex, "http$2://$4", $url);
    } else {
        return false;
    }
}

var_dump(isValidURL($theUrl));
0 голосов
/ 22 июня 2015
public function isLink($url)
{
    $result = false;
    if (!filter_var($url, FILTER_VALIDATE_URL) === false) {
        $getHeaders = get_headers($url);
        $result = strpos($getHeaders[0], '200') !== false;
    }
    return $result;
}
0 голосов
/ 27 марта 2014

@ Гордон - Вот более полная библиотека, основанная на вашем ответе. Он включает в себя некоторую предварительную проверку правильности URL-адреса, дополнительную обработку ошибок и анализ возвращаемых заголовков. Это также следует за любыми цепями перенаправления в течение разумного количества шагов.

class cLib {
    static $lasterror = 'No error set yet';
    /**
     * @brief See with a URL is valid - i.e. a page can be successfully retrieved from it without error
     * @param string $url The URL to be checked
     * @param int $nredirects The number of redirects check so far
     * @return boolean True if OK, false if the URL cannot be fetched
     */
    static function checkUrl($url, $nredirects = 0) {
        // First, see if the URL is sensible
        if (filter_var($url, FILTER_VALIDATE_URL) === false) {
            self::$lasterror = sprintf('URL "%s" did not validate', $url);
            return false;
        }
        // Now try to fetch it
        $headers = @get_headers($url);
        if ($headers == false) {
            $error = error_get_last();
            self::$lasterror = sprintf('URL "%s" could not be read: %s', $url, $error['message']);
            return false;
        }
        $status = $headers[0];
        $rbits = explode(' ', $status);
        if (count($rbits) < 2) {
            self::$lasterror = sprintf('Cannot parse status "%s" from URL "%s"', $status, $url);
            return false;
        }
        if (in_array($rbits[1], array(301, 302, 304, 307, 308))) {
            // This URL has been redirected. Follow the redirection chain
            foreach ($headers as $header) {
                if (cLib::startsWith($header, 'Location:')) {
                    if (++$nredirects > 10) {
                        self::$lasterror = sprintf('URL "%s" was redirected over 10 times: abandoned check', $url);
                        return false;
                    }
                    return self::checkUrl(trim(substr($header, strlen('Location:'))), $nredirects);
                }
            }
            self::$lasterror = sprintf('URL "%s" was redirected but location could not be identified', $url);
            return false;
        } 
        if ($rbits[1] != 200) {
            self::$lasterror = sprintf('URL "%s" returned status "%s"', $url, $status);
            return false;
        }
        return true;
    }
}

С извинениями перед @FranciscoLuz - если вы ожидаете ошибок, основанных на вводе данных пользователем, метод "@ and error_get_last" кажется мне совершенно разумным - я не вижу ничего более правильного в использовании set_error_handler.

Кстати, я не уверен, что мне следовало сделать это как изменение ответа @ Гордона, а не как отдельный ответ. Может кто-нибудь посоветовать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...