Как можно проверить, существует ли удаленный файл с использованием PHP? - PullRequest
81 голосов
/ 11 июня 2009

Лучшее, что я смог найти, вещь типа if fclose fopen, заставляет страницу загружаться очень медленно.

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

Ответы [ 20 ]

129 голосов
/ 11 июня 2009

Вы можете указать curl использовать метод HTTP HEAD через CURLOPT_NOBODY.

Больше или меньше

$ch = curl_init("http://www.example.com/favicon.ico");

curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// $retcode >= 400 -> not found, $retcode = 200, found.
curl_close($ch);

В любом случае вы сохраняете только стоимость передачи HTTP, а не установления и закрытия TCP-соединения. И, несмотря на то, что фавиконы маленькие, вы вряд ли заметите улучшение.

Кэширование результата локально кажется хорошей идеей, если оно оказывается слишком медленным. HEAD проверяет время файла и возвращает его в заголовках. Вы можете сделать как браузеры и получить CURLINFO_FILETIME иконы. В вашем кеше вы можете хранить URL => [favicon, timestamp]. Затем вы можете сравнить метку времени и перезагрузить значок.

60 голосов
/ 11 июня 2009

Как говорят Пироги, вы можете использовать cURL. Вы можете получить CURL только для заголовков, а не для тела, что может сделать его быстрее. Плохой домен всегда может занять некоторое время, потому что вы будете ожидать истечения времени ожидания запроса; Вы можете изменить длительность тайм-аута с помощью cURL.

Вот пример:

function remoteFileExists($url) {
    $curl = curl_init($url);

    //don't fetch the actual page, you only want to check the connection is ok
    curl_setopt($curl, CURLOPT_NOBODY, true);

    //do request
    $result = curl_exec($curl);

    $ret = false;

    //if request did not fail
    if ($result !== false) {
        //if request was ok, check response code
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);  

        if ($statusCode == 200) {
            $ret = true;   
        }
    }

    curl_close($curl);

    return $ret;
}

$exists = remoteFileExists('http://stackoverflow.com/favicon.ico');
if ($exists) {
    echo 'file exists';
} else {
    echo 'file does not exist';   
}
33 голосов
/ 23 января 2010

Решение CoolGoose хорошо, но оно быстрее для больших файлов (так как он пытается прочитать только 1 байт):

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}
27 голосов
/ 16 мая 2010

Это не ответ на ваш первоначальный вопрос, а лучший способ сделать то, что вы пытаетесь сделать:

Вместо того, чтобы на самом деле пытаться получить значок сайта напрямую (что является королевской болью, учитывая, что это может быть /favicon.png, /favicon.ico, /favicon.gif или даже /path/to/favicon.png), использовать Google:

<img src="http://www.google.com/s2/favicons?domain=[domain]">

Готово.

18 голосов
/ 04 мая 2012

Если вы имеете дело с изображениями, используйте getimagesize. В отличие от file_exists, эта встроенная функция поддерживает удаленные файлы. Он вернет массив, который содержит информацию об изображении (ширина, высота, type..etc). Все, что вам нужно сделать, это проверить первый элемент в массиве (ширина). используйте print_r для вывода содержимого массива

$imageArray = getimagesize("http://www.example.com/image.jpg");
if($imageArray[0])
{
    echo "it's an image and here is the image's info<br>";
    print_r($imageArray);
}
else
{
    echo "invalid image";
}
13 голосов
/ 19 мая 2016

Полная функция ответа наиболее проголосовавших:

function remote_file_exists($url)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if( $httpCode == 200 ){return true;}
}

Вы можете использовать его так:

if(remote_file_exists($url))
{
    //file exists, do something
}
7 голосов
/ 17 сентября 2011

Это можно сделать, получив код статуса HTTP (404 = не найден), что возможно при file_get_contents Документах с использованием параметров контекста , Следующий код учитывает перенаправления и возвращает код состояния конечного пункта назначения ( Демо ):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1
);

$body = file_get_contents($url, NULL, stream_context_create($options));

foreach($http_response_header as $header)
    sscanf($header, 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";

Если вы не хотите следовать перенаправлениям, вы можете сделать это аналогично ( Демо ):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1,
    'max_redirects' => 0
);

$body = file_get_contents($url, NULL, stream_context_create($options));

sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";

Некоторые из используемых функций, опций и переменных объясняются более подробно в блоге, который я написал: Сначала HEAD с PHP Streams .

6 голосов
/ 23 апреля 2014

Встроенные функции PHP могут не работать для проверки URL, если для обеспечения безопасности для параметра allow_url_fopen установлено значение off. Curl - лучший вариант, поскольку нам не нужно менять наш код при поздняя стадия. Ниже приведен код, который я использовал для подтверждения действительного URL:

$url = str_replace(' ', '%20', $url);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);  
curl_close($ch);
if($httpcode>=200 && $httpcode<300){  return true; } else { return false; } 

Пожалуйста, обратите внимание на параметр CURLOPT_SSL_VERIFYPEER , который также проверяет URL-адрес, начинающийся с HTTPS.

6 голосов
/ 11 июня 2009
if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}

Должен работать;)

4 голосов
/ 11 июня 2009

Радикальным решением было бы отображение значков в качестве фоновых изображений в div над значком по умолчанию. Таким образом, все накладные расходы будут размещены на клиенте, но при этом не будут отображаться битые изображения (отсутствующие фоновые изображения игнорируются во всех браузерах AFAIK).

...