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

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

Ответ 1

Вы можете использовать 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-запросы. Поэтому перед reset контекстом по умолчанию используйте GET снова, когда закончите.

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

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

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

Ответ 2

@Gordon - вот более полная библиотека, основанная на вашем ответе. Он включает в себя некоторую предварительную проверку правильности 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 - если вы ожидаете ошибок на основе пользовательского ввода, метод "@и error_get_last" кажется мне совершенно разумным - я не вижу, что что-то более правильное в использовании set_error_handler.

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

Ответ 3

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;
}

Ответ 4

Я использую эту функцию, поскольку она также проверяет и возвращает протокол 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));