PHP kullanılarak uzak bir dosyanın var olup olmadığı nasıl kontrol edilebilir?


87

Bulabildiğim en iyi if fclose fopenşey, bir tür şey, sayfanın gerçekten yavaş yüklenmesini sağlıyor.

Temel olarak yapmaya çalıştığım şey şudur: Web sitelerinin bir listesi var ve bunların yanında faviconlarını görüntülemek istiyorum. Bununla birlikte, bir sitede bir tane yoksa, bozuk bir resim göstermek yerine onu başka bir resimle değiştirmek isterim.


Bence CURL'yi kullanabilir ve dönüş kodlarını kontrol edebilirsiniz. Ancak sorun olan hızsa, bunu çevrimdışı yapın ve önbelleğe alın.
Michał Tatarynowicz

Evet, ancak yine de web sitelerinin listesini ayrıştıran, faviconları olup olmadığını kontrol eden ve bu verileri ön uç için önbelleğe alan bir çevrimdışı komut dosyası (cron'dan çalıştırma) kullanmanızı öneririm. Cron kullanmıyorsanız / kullanamıyorsanız, en azından kontrol ettiğiniz her yeni URL için sonuçları önbelleğe alın.
Michał Tatarynowicz

3
Kırık bir görüntüyü tarayıcıda bir yer tutucu görüntü ile değiştirmek için lütfen onerrorgörüntü kullanan bir istemci tarafı çözümü düşünün, örneğin jQuery kullanan bir çözüm

Yanıtlar:


136

Curl'ye CURLOPT_NOBODY aracılığıyla HTTP HEAD yöntemini kullanma talimatı verebilirsiniz.

Az çok

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

Her neyse, yalnızca HTTP aktarım maliyetinden tasarruf edersiniz, TCP bağlantısı kurma ve kapatma işleminden değil. Ve faviconlar küçük olduğundan, çok fazla gelişme göremeyebilirsiniz.

Sonucu yerel olarak önbelleğe almak, çok yavaş çıkarsa iyi bir fikir gibi görünür. HEAD, dosyanın zamanını kontrol eder ve onu başlıklarda döndürür. Tarayıcıları beğenebilir ve simgenin CURLINFO_FILETIME değerini alabilirsiniz. Önbelleğinizde URL => [favicon, timestamp] saklayabilirsiniz. Daha sonra zaman damgasını karşılaştırabilir ve favicon'u yeniden yükleyebilirsiniz.


6
sadece bir not: retcode400 kodun tümünde hatalar, böylece doğrulama >=sadece olmaz>
Justin Bull

4
Kullanıcı aracısı dizesi sağlamazsanız bazı siteler erişimi engeller, bu nedenle CURLOPT_NOBODY'ye ek olarak CURLOPT_USERAGENT eklemek için bu kılavuzu
izlemenizi öneririm

6
@Lyth 3XX retcodes bir hata değil, bir yönlendirme. Bunlar manuel olarak veya CURLOPT_FOLLOWLOCATION kullanılarak işlenmelidir.
Ramon Poca

6
Curl_setopt ($ ch, CURLOPT_SSL_VERIFYPEER, false) kullanın; aynı kodun HTTPS ile başlayan URL'ler için çalıştığından emin olmak için!
Krishan Gopal

61

Pies'in dediği gibi cURL kullanabilirsiniz. Vücudu değil, yalnızca başlıkları vermek için cURL alabilirsiniz, bu da onu daha hızlı hale getirebilir. Hatalı bir etki alanı, isteğin zaman aşımına uğramasını bekleyeceğiniz için her zaman biraz zaman alabilir; muhtemelen zaman aşımı süresini cURL kullanarak değiştirebilirsiniz.

İşte örnek:

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/' ) bu da true değerini döndürür, ancak bu yalnızca bir bağlantıdır. Bu işlev, bağlantı içerik türünün dosya olduğunu kontrol etmez.
Donatas Navidonskis

36

CoolGoose'un çözümü iyidir, ancak bu büyük dosyalar için daha hızlıdır (yalnızca 1 bayt okumaya çalıştığı için):

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

+1. CURL çözümüne karşı bu çözümün dezavantajları nelerdir?
Adriano Varoli Piazza

1
sadece kullanabilirsiniz fopen- eğer istek dönüş kodu 404 ise, fopen yanlış döndürür.
s3v3n

Bu gerçekten yavaş ve (dosya yolunun doğru değilse hala bir kırık görüntü görüntülenen anlamında) benim için çalışmalarını vermedi
Helmut

Bu yaklaşım, bir görüntü veya dosya mevcut olmadığında sunucu yeniden yönlendirme yaparsa işe yaramaz. Bu, bir site, mod_rewrite veya isteklerin nasıl işleneceği başka "kurallar" kullandığında gerçekleşir.
Erik Čerpnjak

28

Bu, asıl sorunuzun cevabı değil, yapmaya çalıştığınız şeyi yapmanın daha iyi bir yoludur:

Aslında sitenin favicon'unu doğrudan almaya çalışmak yerine (bu, /favicon.png, /favicon.ico, /favicon.gif veya hatta /path/to/favicon.png olabilir), google'ı kullanın:

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

Bitti.


4
Sözdizimi biraz kafa karıştırıyor. Öyleyse burada bir örnek: <img src = " google.com/s2/favicons?domain=stackoverflow.com ">
Habeeb Perwad

19

En çok oylanan cevabın eksiksiz bir işlevi:

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

Bunu şu şekilde kullanabilirsiniz:

if(remote_file_exists($url))
{
    //file exists, do something
}

Oh! Son birkaç gündür uzaktaydım ama ayın başı neredeyse 24/7 idi. Bana bildirdiğiniz için teşekkür ederim!
Pedro Lobito

Sunucu herhangi bir HTTP kodunu yanıtlamazsa (veya cUrl onu yakalamazsa) bu çalışmaz. Bu bana oldukça sık geliyor. Örneğin. görüntüler durumunda.
Vaci

ya url başka bir URL'ye veya https sürümüne yönlendirilirse? Bu durumda bu curl kodu işi yapamayacaktır. en iyi yol, başlık bilgilerini almak ve büyük / küçük harfe duyarlı olmayan "200 ok" dizesini aramaktır.
Infoconic

@Infoconic ekleyebilirsiniz curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);. 302Yönlendirmeleri işlemek için yanıtı güncelledim .
Pedro Lobito

18

Görüntülerle uğraşıyorsanız, getimagesize kullanın. File_exists'ten farklı olarak, bu yerleşik işlev uzak dosyaları destekler. Görüntü bilgilerini (genişlik, yükseklik, tür..vb) içeren bir dizi döndürür. Tek yapmanız gereken dizideki ilk öğeyi (genişlik) kontrol etmektir. dizinin içeriğini çıktı almak için print_r kullanın

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

Uzak kaynak mevcut olmadığında 404 uyarısıyla sonuçlanır. Şimdilik, @önünde kullanarak hatayı bastırarak getimagesizeancak bu hack için kendimi suçlu hissederek hallettim .

Benim durumumda bu en iyi yaklaşımdı, çünkü bir resim / dosya olmadığında yeniden yönlendirilirim. İkincisi, @ ile ilgili hataları bastırmak yok ama bu durumda gerekliydi.
Erik Čerpnjak

Ayrıca kullanabileceğimizi anladım exif_imagetypeve çok daha hızlı stackoverflow.com/a/38295345/1250044
yckart

7

Bu, file_get_contentsDokümanlar'ın bağlam seçeneklerinden yararlanmasıyla mümkün olan HTTP Durum kodunu (404 = bulunamadı) alarak yapılabilir . Aşağıdaki kod, yönlendirmeleri hesaba katar ve son hedefin ( Demo ) durum kodunu döndürür :

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

Yönlendirmeleri takip etmek istemiyorsanız, benzer şekilde yapabilirsiniz ( 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";

Kullanımdaki bazı işlevler, seçenekler ve değişkenler yazdığım bir blog yazısında daha ayrıntılı olarak açıklanmıştır: HEAD önce PHP Streams ile .




PHP hakkında daha fazla bilgi $http_response_headeriçin php.net/manual/en/reserved.variables.httpresponseheader.php adresine bakın .
Big McLargeHuge

1
İkinci varyant benim için çalıştı ve varsayılan file_get_contents çağrısıyla karşılaştırıldığında (özel akış_ bağlamı yok)% 50 daha hızlıydı, yani bir istek için 3,4 saniyeden 1,7 saniyeye.
Erik Čerpnjak

@ ErikČerpnjak: "Özel" stream_context yoksa, bu varsayılandır. Seçenekleri varsayılan bağlamdan alabilir ve özel bağlamınızdan nasıl farklılaştıklarına bir göz atabilirsiniz. Bu size zamanlamaların neden farklı olduğu konusunda biraz fikir vermelidir. - php.net/stream-context-get-default ve php.net/stream-context-get-options
hakre

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

Çalışmalı ;)


@ işlevinden önce ekle
Tebe

6

Güvenlik nedeniyle allow_url_fopen ayarı kapalı olarak ayarlanmışsa PHP'nin yerleşik işlevleri URL'yi kontrol etmek için çalışmayabilir . Curl, daha sonraki aşamada kodumuzu değiştirmemiz gerekmeyeceğinden daha iyi bir seçenektir. Geçerli bir URL'yi doğrulamak için kullandığım kod aşağıdadır:

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

Lütfen URL'nin HTTPS ile başladığını doğrulayan CURLOPT_SSL_VERIFYPEER seçeneğine dikkat edin .


6

Görüntülerin varlığını kontrol etmek için çok daha hızlı olduğu exif_imagetypeiçin tercih edilmelidir getimagesize.

E_NOTICEÖğesini bastırmak için hata kontrol operatörünü ( @) başa ekleyin .

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

Bonus olarak, döndürülen değerle ( IMAGETYPE_XXX), / exif_imagetypeile mime türünü veya dosya uzantısını da alabiliriz .image_type_to_mime_typeimage_type_to_extension


4

Radikal bir çözüm, faviconları varsayılan simgenizin üzerindeki bir div'de arka plan resimleri olarak görüntülemek olacaktır. Bu şekilde, tüm ek yük istemciye yerleştirilirken hala bozuk görüntüler görüntülenmez (eksik arka plan resimleri tüm AFAIK tarayıcılarında göz ardı edilir).


1
Favicon (favicon.ico, favicon.gif, favicon.png) için birden fazla konumu kontrol etmiyorsanız +1 bu en iyi çözüm gibi görünüyor
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

Aşağıdakileri kullanabilirsiniz:

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

URL'de bir resim olup olmadığını kontrol etmeye çalışırken benim için çalıştı


2

Kullanabilirsiniz :

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

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

2

Bu, PHP'de uzak bir dosya olup olmadığını kontrol etmem için çalışıyor:

$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

GET değil HEAD istekleri göndermelisiniz çünkü URI içeriğine hiç ihtiyacınız yoktur. Pies'in yukarıda söylediği gibi, durum kodunu kontrol etmelisiniz (200-299 aralığında ve isteğe bağlı olarak 3xx yönlendirmelerini takip edebilirsiniz).

Cevaplar sorusu, yardımcı olabilecek birçok kod örneği içerir: PHP / Curl: HEAD İsteği bazı sitelerde uzun sürüyor


1

Daha da sofistike bir alternatif var. Bir JQuery numarası kullanarak tüm istemci tarafını kontrol edebilirsiniz.

$('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); };
});

Gönderen http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/ (orijinal blog aşağı anda olduğu)


1

get_headers () kullanan tüm yanıtlar bir GET isteği yapıyor. HEAD isteği yapmak çok daha hızlı / daha ucuzdur.

Get_headers () 'ın bir GET yerine HEAD isteği yaptığından emin olmak için şunu eklemelisiniz:

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

bu nedenle, bir dosyanın var olup olmadığını kontrol etmek için kodunuz şuna benzer:

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 açıkça yanlış veya doğru döndürür.


0

Dosya uzaktan var olmadığında bunun daha hızlı olup olmadığını bilmiyorum, is_file () , ama bir şans verebilirsiniz.

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

Dokümanlardan: "PHP 5.0.0'dan itibaren, bu işlev bazı URL sarmalayıcılarla da kullanılabilir. Hangi sarmalayıcıların stat () işlev ailesini desteklediğini belirlemek için Desteklenen Protokoller ve Sarmalayıcılar'a bakın."
PatrikAkerstrand

Bir akış sarmalayıcı kaydederseniz bunun işe yarayacağını mı söylüyorsunuz? Sorunuzu çalışan bir örnek gösterecek şekilde düzenleyin ve olumsuz oyumu kaldıracağım (ve yapabiliyorsam size olumlu oy vereceğim). Ama şu an için is_file dosyasını uzak bir dosya ile php cli'dan test ettim ve yanlış aldım.
greg0ire

çalışmayan örnek:var_dump(is_file('http://cdn.sstatic.net/stackoverflow/img/sprites.png')); bool(false)
greg0ire

0

Dosya harici olarak barındırılmıyorsa, uzak URL'yi web sunucunuzdaki mutlak Yola çevirebilirsiniz. Bu şekilde CURL veya file_get_contents, vb. Çağırmanıza gerek kalmaz.

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

Not: Bu işlevi kullanmak için web sunucunuzun DOCUMENT_ROOT'u doldurması gerekir


0

Symfony çerçevesini kullanıyorsanız, HttpClientInterfaceaşağıdakileri kullanmanın çok daha basit bir yolu vardır :

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 için belgeler de çok iyidir ve daha spesifik bir yaklaşıma ihtiyacınız varsa araştırmaya değer olabilir: https://symfony.com/doc/current/http_client.html


-1

Dosya sistemini kullanabilirsiniz: Symfony \ Component \ Filesystem \ Filesystem kullanın; Symfony \ Component \ Filesystem \ Exception \ IOExceptionInterface'i kullanın;

ve $ fileSystem = new Filesystem (); eğer ($ fileSystem-> varsa ('path_to_file') == true) {...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.