PHPを使用してリモートファイルが存在するかどうかを確認するにはどうすればよいですか?


86

私が見つけた最高のもの、 if fclose fopenもの、タイプのものは、ページの読み込みを本当に遅くします。

基本的に私がやろうとしていることは次のとおりです。Webサイトのリストがあり、その横にファビコンを表示したいと思います。ただし、サイトにない場合は、壊れた画像を表示するのではなく、別の画像に置き換えたいと思います。


CURLを使用して、その戻りコードを確認できると思います。ただし、速度が問題になる場合は、オフラインでキャッシュしてください。
のMichałTatarynowicz

はい。ただし、ウェブサイトのリストを解析し、ファビコンがあるかどうかを確認し、フロントエンド用にそのデータをキャッシュするオフラインスクリプト(cronから実行)を使用することをお勧めします。cronを使用しない/使用できない場合は、少なくとも、チェックする新しいURLごとに結果をキャッシュしてください。
のMichałTatarynowicz

3
壊れた画像をブラウザでプレースホルダー画像に置き換えるには、画像を使用したクライアント側のソリューションonerror、たとえばjQueryを使用したソリューションを

回答:


135

CURLOPT_NOBODYを介してHTTPHEADメソッドを使用するようにcurlに指示できます。

多かれ少なかれ

$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);

とにかく、TCP接続の確立と終了ではなく、HTTP転送のコストを節約するだけです。また、ファビコンが小さいため、あまり改善されない場合があります。

結果が遅すぎることが判明した場合は、結果をローカルにキャッシュすることをお勧めします。HEADはファイルの時刻をチェックし、それをヘッダーに返します。ブラウザのように実行して、アイコンのCURLINFO_FILETIMEを取得できます。キャッシュには、URL => [ファビコン、タイムスタンプ]を保存できます。次に、タイムスタンプを比較してファビコンをリロードできます。


6
注:retcode400個のコードすべてにエラーがあるため、検証>=だけではありません>
Justin Bull

4
一部のサイトでは、ユーザーエージェント文字列を指定しないとアクセスがブロックされるため、このガイドに従って、CURLOPT_NOBODYに加えてCURLOPT_USERAGENTを追加することをお勧めします。davidwalsh.name
user

6
@Lyth 3XX retcodeはエラーではなく、リダイレクトです。これらは手動で処理するか、CURLOPT_FOLLOWLOCATIONを使用して処理する必要があります。
ラモンポカ2013年

6
curl_setopt($ ch、CURLOPT_SSL_VERIFYPEER、false);を使用します。同様に、HTTPSで始まるURLでも同じコードが機能することを確認してください。
クリシュナゴパル2014

61

Piesが言うように、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';   
}

3
remoteFileExists( ' stackoverflow.com/')これもtrueを返しますが、これは単なるリンクです。チェックしないこの関数は、リンクコンテンツタイプがファイルです。
Donatas Navidonskis 2014

36

CoolGooseのソリューションは優れていますが、これは大きなファイルの場合は高速です(1バイトしか読み取ろうとしないため)。

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}

+1。CURLソリューションに対するこのソリューションの欠点は何ですか?
アドリアーノヴァロリピアッツァ2010

1
使用できますfopen-リクエストのリターンコードが404の場合、fopenはfalseを返します。
s3v3n

これは本当に遅く、私には機能しませんでした(つまり、ファイルパスが正しくない場合でも壊れた画像が表示されていました)
Helmut

このアプローチは、画像またはファイルが存在しないときにサーバーがリダイレクトを行う場合は機能しません。これは、サイトがmod_rewriteまたはその他の「ルール」を使用して、リクエストの処理方法を決定する場合に発生します。
エリックČerpnjak

28

これは元の質問に対する答えではありませんが、あなたがやろうとしていることを行うためのより良い方法です。

実際にサイトのファビコンを直接取得しようとする代わりに(/favicon.png、/favicon.ico、/favicon.gif、さらには/path/to/favicon.pngである可能性があることを考えると、これは非常に苦痛です)、googleを使用します。

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

完了。


4
構文は少し混乱します。したがって、ここに1つの例があります:<img src = " google.com/s2/favicons?domain=stackoverflow.com ">
Habeeb Perwad 2012年

19

最も投票された回答の完全な機能:

function remote_file_exists($url)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); # handles 301/2 redirects
    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
}

ああ!私はここ数日不在でしたが、月の初めはほぼ24時間年中無休でした。教えてくれてありがとう!
ペドロロビト2016年

サーバーがHTTPコードに応答しない場合(またはcUrlがHTTPコードをキャッチしない場合)、これは機能しません。それは私にかなり頻繁に起こっています。例えば。画像の場合。
ヴァーツィ

URLが別のURLまたはhttpsバージョンにリダイレクトされた場合はどうなりますか?その場合、このカールコードはその仕事をすることができません。最良の方法は、ヘッダー情報を取得して、大文字と小文字を区別しない文字列「200ok」を検索することです。
インフォコニック

@Infoconicを追加できcurl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);ます。302リダイレクトを処理するために回答を更新しました。
ペドロロビト

18

画像を扱っている場合は、getimagesizeを使用してください。file_existsとは異なり、この組み込み関数はリモートファイルをサポートします。画像情報(幅、高さ、タイプなど)を含む配列を返します。あなたがしなければならないのは、配列の最初の要素(幅)をチェックすることです。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";
}

リモートリソースが利用できない場合、404警告が発生します。とりあえず、@前を使ってエラーを抑えて対処しましたgetimagesizeが、このハックに罪悪感を覚えました。

私の場合、画像/ファイルが存在しないときはいつでもリダイレクトされるため、これが最善のアプローチでした。次に、@によるエラーの抑制はダメですが、この場合は必要でした。
エリックČerpnjak

私も使用できることがわかりましたexif_imagetype、そしてそれははるかに高速ですstackoverflow.com/a/38295345/1250044
yckart 2016

7

これは、コンテキストオプションを利用するfile_get_contentsドキュメントで可能なHTTPステータスコード(404 =見つかりません)を取得することで実行できます。次のコードはリダイレクトを考慮に入れて、最終的な宛先(デモ)のステータスコードを返します。

$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";

使用中の関数、オプション、変数のいくつかは、私が書いたブログ投稿でより詳細に説明されています:最初にPHPストリームでHEAD




PHPの$http_response_header詳細については、php.net / manual / en /reserved.variables.httpresponseheader.phpを参照してください。
Big McLargeHuge 2014年

1
2番目のバリアントは私のために機能し、デフォルトのfile_get_contents呼び出し(カスタムstream_contextなし)と比較して、50%高速でした。つまり、リクエストの場合は3,4秒から1,7秒でした。
エリックČerpnjak

@ErikČerpnjak:「カスタム」stream_contextがない場合、それがデフォルトです。デフォルトのコンテキストからオプションを取得し、それらがカスタムコンテキストとどのように異なるかを確認できます。これにより、タイミングが異なる理由についての洞察が得られるはずです。--php.net / stream
context

6
if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}

動作するはずです;)


関数の前に@を追加
Tebe 2016

6

セキュリティ上の理由からallow_url_fopen設定がoffに設定されている場合、PHPの組み込み関数はURLのチェックに機能しない可能性があります。後の段階でコードを変更する必要がないため、カールの方が適しています。以下は、有効な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; } 

URLがHTTPSで始まることも確認するCURLOPT_SSL_VERIFYPEERオプションに注意してください。


6

画像の存在を確認するには、がはるかに高速であるため、よりexif_imagetypeも優先する必要がありgetimagesizeます。

を抑制するにはE_NOTICE、エラー制御演算子(@)を前に付けるだけです。

if (@exif_imagetype($filename)) {
  // Image exist
}

ボーナスとして、IMAGETYPE_XXXからの戻り値()を使用しexif_imagetypeて、image_type_to_mime_type/を使用してmime-typeまたはfile-extensionを取得することもできますimage_type_to_extension


4

根本的な解決策は、ファビコンをデフォルトのアイコンの上のdivに背景画像として表示することです。そうすれば、壊れた画像を表示せずにすべてのオーバーヘッドがクライアントに配置されます(欠落している背景画像はすべてのブラウザで無視されます)。


1
複数の場所でファビコン(favicon.ico、favicon.gif、favicon.png)をチェックしていない場合は、これが最善の解決策のようです
Galen

3
function remote_file_exists($url){
   return(bool)preg_match('~HTTP/1\.\d\s+200\s+OK~', @current(get_headers($url)));
}  
$ff = "http://www.emeditor.com/pub/emed32_11.0.5.exe";
    if(remote_file_exists($ff)){
        echo "file exist!";
    }
    else{
        echo "file not exist!!!";
    }

3

次を使用できます。

$file = 'http://mysite.co.za/images/favicon.ico';
$file_exists = (@fopen($file, "r")) ? true : false;

URLに画像が存在するかどうかを確認しようとしたときに私のために働いた


2

あなたが使用することができます:

$url=getimagesize(“http://www.flickr.com/photos/27505599@N07/2564389539/”);

if(!is_array($url))
{
   $default_image =”…/directoryFolder/junal.jpg”;
}

2

これは、リモートファイルがPHPに存在するかどうかを確認するために機能します。

$url = 'https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico';
    $header_response = get_headers($url, 1);

    if ( strpos( $header_response[0], "404" ) !== false ) {
        echo 'File does NOT exist';
        } else {
        echo 'File exists';
        }

1

URIの内容はまったく必要ないため、GETではなくHEADリクエストを発行する必要があります。Piesが上で述べたように、ステータスコードを確認する必要があります(200〜299の範囲で、オプションで3xxリダイレクトに従うことができます)。

回答の質問には、役立つ可能性のあるコード例が多数含まれています。PHP/ Curl:一部のサイトではHEADリクエストに長い時間がかかります


1

さらに洗練された代替手段があります。JQueryのトリックを使用して、すべてのクライアント側のチェックを行うことができます。

$('a[href^="http://"]').filter(function(){
     return this.hostname && this.hostname !== location.hostname;
}).each(function() {
    var link = jQuery(this);
    var faviconURL =
      link.attr('href').replace(/^(http:\/\/[^\/]+).*$/, '$1')+'/favicon.ico';
    var faviconIMG = jQuery('<img src="favicon.png" alt="" />')['appendTo'](link);
    var extImg = new Image();
    extImg.src = faviconURL;
    if (extImg.complete)
      faviconIMG.attr('src', faviconURL);
    else
      extImg.onload = function() { faviconIMG.attr('src', faviconURL); };
});

http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/から(元のブログは現在ダウンしています)


1

get_headers()を使用するここでのすべての回答は、GETリクエストを実行しています。HEADリクエストを実行する方がはるかに高速/安価です。

get_headers()がGETではなくHEADリクエストを実行するようにするには、次を追加する必要があります。

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);

したがって、ファイルが存在するかどうかを確認するには、コードは次のようになります。

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);
$headers = get_headers('http://website.com/dir/file.jpg', 1);
$file_found = stristr($headers[0], '200');

$ file_foundは、明らかにfalseまたはtrueを返します。


0

ファイルがリモートに存在しない場合、is_file()の方が速いかどうかはわかりませんが、試してみることができます。

$favIcon = 'default FavIcon';
if(is_file($remotePath)) {
   $favIcon = file_get_contents($remotePath);
}

ドキュメントから:「PHP5.0.0以降、この関数は一部のURLラッパーでも使用できます。サポートされているプロトコルとラッパーを参照して、stat()ファミリーの機能をサポートするラッパーを確認してください。」
PatrikAkerstrand 2012年

ストリームラッパーを登録すると、これが機能する可能性があるということですか?質問を編集して実際の例を示してください。反対票を削除します(可能であれば賛成票を投じます)。しかし、今のところ、リモートファイルを使用してphp cliからis_fileをテストしたところ、falseになりました。
greg0ire 2012年

実用的な例はありません:var_dump(is_file('http://cdn.sstatic.net/stackoverflow/img/sprites.png')); bool(false)
greg0ire 2012年

0

ファイルが外部でホストされていない場合は、リモートURLをWebサーバー上の絶対パスに変換できます。そうすれば、CURLやfile_get_contentsなどを呼び出す必要はありません。

function remoteFileExists($url) {

    $root = realpath($_SERVER["DOCUMENT_ROOT"]);
    $urlParts = parse_url( $url );

    if ( !isset( $urlParts['path'] ) )
        return false;

    if ( is_file( $root . $urlParts['path'] ) )
        return true;
    else
        return false;

}

remoteFileExists( 'https://www.yourdomain.com/path/to/remote/image.png' );

注:この関数を使用するには、WebサーバーにDOCUMENT_ROOTを設定する必要があります


0

Symfonyフレームワークを使用している場合は、HttpClientInterface:を使用するはるかに簡単な方法もあります。

private function remoteFileExists(string $url, HttpClientInterface $client): bool {
    $response = $client->request(
        'GET',
        $url //e.g. http://example.com/file.txt
    );

    return $response->getStatusCode() == 200;
}

HttpClientのドキュメントも非常に優れており、より具体的なアプローチが必要な場合は調べる価値があります:https//symfony.com/doc/current/http_client.html


-1

ファイルシステムを使用できます:use Symfony \ Component \ Filesystem \ Filesystem; Symfony \ Component \ Filesystem \ Exception \ IOExceptionInterfaceを使用します;

$ fileSystem = new Filesystem();を確認します。if($ fileSystem-> exists( 'path_to_file')== true){..。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.