Bagaimana seseorang dapat memeriksa untuk melihat apakah ada file jarak jauh menggunakan PHP?

87

Yang terbaik yang bisa saya temukan, if fclose fopenjenis hal, membuat halaman memuat sangat lambat.

Pada dasarnya apa yang saya coba lakukan adalah sebagai berikut: Saya memiliki daftar situs web, dan saya ingin menampilkan favicon mereka di sebelahnya. Namun, jika situs tidak memilikinya, saya ingin menggantinya dengan gambar lain daripada menampilkan gambar yang rusak.


sumber
Saya pikir Anda dapat menggunakan CURL dan memeriksa kode pengembaliannya. Tetapi jika kecepatan yang menjadi masalah, lakukan saja secara offline dan cache.
Michał Tatarynowicz
Ya, tetapi saya tetap akan merekomendasikan menggunakan skrip offline (dijalankan dari cron) yang mem-parsing daftar situs web, memeriksa apakah mereka memiliki favicon dan menyimpan data tersebut untuk frontend. Jika Anda tidak / tidak dapat menggunakan cron, setidaknya hasil cache untuk setiap URL baru yang Anda periksa.
Michał Tatarynowicz
3
Untuk mengganti gambar rusak dengan gambar placeholder di browser, pertimbangkan solusi sisi klien menggunakan onerrorgambar misalnya solusi menggunakan jQuery
Kemungkinan duplikat PHP: Bagaimana cara memeriksa apakah file gambar ada?
Cees Timmerman

Jawaban:

136

Anda dapat menginstruksikan curl untuk menggunakan metode HTTP HEAD melalui CURLOPT_NOBODY.

Lebih atau kurang

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

Bagaimanapun, Anda hanya menghemat biaya transfer HTTP, bukan pembuatan dan penutupan koneksi TCP. Dan karena favicon kecil, Anda mungkin tidak melihat banyak peningkatan.

Menyimpan hasil secara lokal tampaknya merupakan ide yang bagus jika ternyata terlalu lambat. HEAD memeriksa waktu file, dan mengembalikannya di header. Anda dapat melakukan seperti browser dan mendapatkan CURLINFO_FILETIME dari ikon. Di cache Anda, Anda dapat menyimpan URL => [favicon, timestamp]. Anda kemudian dapat membandingkan stempel waktu dan memuat ulang favicon.

Ramon Poca
sumber
6
hanya sebuah catatan: retcodekesalahan pada semua 400 kode sehingga validasinya >=tidak hanya>
Justin Bull
4
Beberapa situs memblokir akses jika Anda tidak memberikan user agent string, jadi saya sarankan mengikuti panduan ini untuk menambahkan CURLOPT_USERAGENT selain CURLOPT_NOBODY: davidwalsh.name/set-user-agent-php-curl-spoof
rlorenzo
6
@Lyth 3XX kode ulang bukanlah kesalahan, tapi pengalihan. Itu harus ditangani secara manual atau menggunakan CURLOPT_FOLLOWLOCATION.
Ramon Poca
6
Gunakan curl_setopt ($ ch, CURLOPT_SSL_VERIFYPEER, false); juga untuk memastikan kode yang sama berfungsi untuk URL yang dimulai dengan HTTPS!
Krishan Gopal
61

Seperti yang dikatakan Pies, Anda dapat menggunakan cURL. Anda bisa mendapatkan cURL untuk hanya memberi Anda header, dan bukan isi, yang mungkin membuatnya lebih cepat. Domain yang buruk selalu membutuhkan waktu beberapa saat karena Anda akan menunggu permintaan waktu habis; Anda mungkin dapat mengubah durasi waktu tunggu menggunakan cURL.

Berikut contohnya:

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';   
}
Tom Haigh
sumber
3
remoteFileExists (' stackoverflow.com/' ) ini juga akan mengembalikan nilai true, tetapi ini hanya tautan. Fungsi ini tidak memeriksa adalah jenis konten tautan adalah file.
Donatas Navidonskis
36

Solusi CoolGoose bagus tetapi ini lebih cepat untuk file besar (karena hanya mencoba membaca 1 byte):

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}
luBar
sumber
+1. Apakah ada kekurangan dari solusi ini dibandingkan dengan CURL?
Adriano Varoli Piazza
1
Anda bisa menggunakan fopen- jika kode pengembalian permintaan adalah 404, fopen mengembalikan false.
s3v3n
ini sangat lambat dan tidak berhasil untuk saya (artinya masih menampilkan gambar rusak jika jalur file tidak benar)
Helmut
Pendekatan ini tidak berfungsi jika server melakukan pengalihan setiap kali gambar atau file tidak ada. Ini terjadi ketika situs menggunakan mod_rewrite atau semacam "aturan" lain bagaimana permintaan harus ditangani.
Erik Čerpnjak
28

Ini bukanlah jawaban atas pertanyaan awal Anda, tetapi cara yang lebih baik untuk melakukan apa yang Anda coba lakukan:

Daripada benar-benar mencoba mendapatkan favicon situs secara langsung (yang sangat merepotkan karena bisa jadi /favicon.png, /favicon.ico, /favicon.gif, atau bahkan /path/to/favicon.png), gunakan google:

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

Selesai.

Mala
sumber
4
Sintaksnya membuat sedikit kebingungan. Jadi di sini salah satu contohnya: <img src = " google.com/s2/favicons?domain=stackoverflow.com ">
Habeeb Perwad
19

Fungsi lengkap dari jawaban yang paling banyak dipilih:

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

Anda bisa menggunakannya seperti ini:

if(remote_file_exists($url))
{
    //file exists, do something
}
Pedro Lobito
sumber
Oh! Saya telah pergi selama beberapa hari terakhir tetapi awal bulan hampir 24/7. Terima kasih telah memberitahu saya!
Pedro Lobito
Ini tidak berfungsi jika server tidak menanggapi kode HTTP apa pun (atau cUrl tidak menangkapnya). Yang cukup sering terjadi pada saya. Misalnya. dalam kasus gambar.
Vaci
bagaimana jika url dialihkan ke URL lain atau versi https? Dalam hal ini kode curl tidak akan dapat melakukan pekerjaan itu. cara terbaik adalah mendapatkan informasi header dan mencari string case-insensitive "200 ok".
Infoconic
@Informasi Anda dapat menambahkan curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);. Saya telah memperbarui jawaban untuk menangani 302pengalihan.
Pedro Lobito
18

Jika Anda berurusan dengan gambar, gunakan getimagesize. Tidak seperti file_exists, fungsi bawaan ini mendukung file jarak jauh. Ini akan mengembalikan array yang berisi informasi gambar (lebar, tinggi, tipe..dll). Yang harus Anda lakukan adalah memeriksa elemen pertama dalam array (lebarnya). gunakan print_r untuk menampilkan konten larik

$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";
}
Eyad Fallatah
sumber
Menghasilkan peringatan 404 ketika sumber daya jarak jauh tidak tersedia. Untuk saat ini, saya menanganinya dengan menekan penggunaan kesalahan @di depan getimagesize, tetapi merasa bersalah atas peretasan ini.
Dalam kasus saya ini adalah pendekatan terbaik, karena saya dialihkan setiap kali gambar / file tidak ada. Saya setuju bahwa kesalahan penekanan dengan @ tidak boleh dilakukan tetapi dalam hal ini itu diperlukan.
Erik Čerpnjak
Saya menemukan bahwa kami juga dapat menggunakan exif_imagetype, dan ini jauh lebih cepat stackoverflow.com/a/38295345/1250044
yckart
7

Ini dapat dilakukan dengan mendapatkan kode Status HTTP (404 = tidak ditemukan) yang dimungkinkan dengan file_get_contentsDokumen yang menggunakan opsi konteks. Kode berikut memperhitungkan pengalihan dan akan mengembalikan kode status tujuan akhir ( Demo ):

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

Jika Anda tidak ingin mengikuti pengalihan, Anda dapat melakukannya serupa ( Demo ):

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

Beberapa fungsi, opsi, dan variabel yang digunakan dijelaskan lebih detail di postingan blog yang saya tulis: HEAD first with PHP Streams .

hakre
sumber
Untuk informasi lebih lanjut tentang PHP, $http_response_headerlihat php.net/manual/en/reserved.variables.httpresponseheader.php .
Big McLargeHuge
1
Varian kedua bekerja untuk saya dan dibandingkan dengan panggilan file_get_contents default (tidak ada stream_context kustom) itu 50% lebih cepat, yaitu dari 3,4 detik menjadi 1,7 detik untuk permintaan.
Erik Čerpnjak
@ ErikČerpnjak: Jika tidak ada stream_context "ubahsuaian", ini adalah yang default. Anda bisa mendapatkan opsi dari konteks default dan melihat bagaimana mereka bervariasi dari konteks kustom Anda. Ini akan memberi Anda beberapa wawasan mengapa pengaturan waktu berbeda. - php.net/stream-context-get-default dan php.net/stream-context-get-options
hakre
6
if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}

Harus bekerja;)

CoolGoose
sumber
add @ before function
Tebe
6

Fungsi bawaan PHP mungkin tidak berfungsi untuk memeriksa URL jika pengaturan allow_url_fopen dinonaktifkan untuk alasan keamanan. Curl adalah opsi yang lebih baik karena kami tidak perlu mengubah kode kami di tahap selanjutnya. Di bawah ini adalah kode yang saya gunakan untuk memverifikasi URL yang valid:

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

Mohon perhatikan opsi CURLOPT_SSL_VERIFYPEER yang juga memverifikasi URL yang dimulai dengan HTTPS.

Krishan Gopal
sumber
6

Untuk mengecek keberadaan gambar, exif_imagetypesebaiknya lebih diutamakangetimagesize , karena jauh lebih cepat.

Untuk menekannya E_NOTICE, cukup tambahkan operator kontrol kesalahan ( @).

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

Sebagai bonus, dengan nilai yang dikembalikan ( IMAGETYPE_XXX) dari exif_imagetypekita juga bisa mendapatkan tipe mime atau ekstensi file dengan image_type_to_mime_type/ image_type_to_extension.

yckart
sumber
4

Solusi radikal akan menampilkan favicon sebagai gambar latar belakang dalam div di atas ikon default Anda. Dengan begitu, semua overhead akan ditempatkan pada klien sementara masih tidak menampilkan gambar yang rusak (gambar latar yang hilang diabaikan di semua browser AFAIK).

truppo
sumber
1
+1 jika Anda tidak memeriksa beberapa lokasi untuk favicon mereka (favicon.ico, favicon.gif, favicon.png) tampaknya ini adalah solusi terbaik
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!!!";
    }
dr.linux
sumber
3

Anda bisa menggunakan yang berikut ini:

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

Bekerja untuk saya ketika mencoba memeriksa apakah ada gambar di URL

Rickus Harmse
sumber
2

Kamu dapat memakai :

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

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

Ini berfungsi bagi saya untuk memeriksa apakah file jarak jauh ada di 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';
        }
pengguna7018984
sumber
1

Anda harus mengeluarkan permintaan HEAD, bukan GET, karena Anda tidak memerlukan konten URI sama sekali. Seperti yang dikatakan Pies di atas, Anda harus memeriksa kode status (dalam rentang 200-299, dan secara opsional Anda dapat mengikuti pengalihan 3xx).

Pertanyaan jawaban berisi banyak contoh kode yang mungkin berguna: PHP / Curl: HEAD Permintaan membutuhkan waktu lama di beberapa situs

drdaeman
sumber
1

Ada alternatif yang lebih canggih. Anda dapat melakukan pengecekan semua sisi klien menggunakan trik 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); };
});

Dari http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/ (blog asli saat ini sedang tidak aktif)

S Pangborn
sumber
1

semua jawaban di sini yang menggunakan get_headers () melakukan permintaan GET. Jauh lebih cepat / lebih murah untuk hanya melakukan permintaan HEAD.

Untuk memastikan bahwa get_headers () melakukan permintaan HEAD daripada GET, Anda harus menambahkan ini:

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

jadi untuk memeriksa apakah ada file, kode Anda akan terlihat seperti ini:

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 akan mengembalikan salah atau benar, jelas.

Ludo - Tidak direkam
sumber
0

Tidak tahu apakah yang ini lebih cepat ketika file tidak ada dari jarak jauh, is_file () , tetapi Anda bisa mencobanya.

$favIcon = 'default FavIcon';
if(is_file($remotePath)) {
   $favIcon = file_get_contents($remotePath);
}
PatrikAkerstrand
sumber
Dari dokumen: "Mulai dari PHP 5.0.0, fungsi ini juga dapat digunakan dengan beberapa pembungkus URL. Lihat Protokol dan Pembungkus yang Didukung untuk menentukan pembungkus mana yang mendukung kelompok fungsionalitas stat ()."
PatrikAkerstrand
Apakah maksud Anda ini dapat berfungsi jika Anda mendaftarkan pembungkus streaming? Edit pertanyaan Anda untuk menunjukkan contoh yang berfungsi dan saya akan menghapus suara negatif saya (dan memberi suara positif jika saya bisa). Tetapi untuk saat ini, saya menguji is_file dari php cli dengan file jarak jauh, dan ternyata salah.
greg0ire
tidak ada contoh yang berfungsi:var_dump(is_file('http://cdn.sstatic.net/stackoverflow/img/sprites.png')); bool(false)
greg0ire
0

Jika file tidak dihosting secara eksternal, Anda dapat menerjemahkan URL jarak jauh ke Path absolut di server web Anda. Dengan begitu Anda tidak perlu memanggil CURL atau file_get_contents, dll.

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

Catatan: Server web Anda harus mengisi DOCUMENT_ROOT untuk menggunakan fungsi ini

Bastian Fießinger
sumber
0

Jika Anda menggunakan framework Symfony, ada juga cara yang jauh lebih sederhana menggunakan 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;
}

Dokumen untuk HttpClient juga sangat bagus dan mungkin layak untuk dilihat jika Anda membutuhkan pendekatan yang lebih spesifik: https://symfony.com/doc/current/http_client.html

Filnor
sumber
-1

Anda dapat menggunakan filesystem: gunakan Symfony \ Component \ Filesystem \ Filesystem; gunakan Symfony \ Component \ Filesystem \ Exception \ IOExceptionInterface;

dan periksa $ fileSystem = new Filesystem (); jika ($ fileSystem-> ada ('path_to_file') == true) {...

Lenwë Galathil
sumber