wake-up-neo.net

bester Weg um festzustellen, ob eine URL ein Bild ist PHP

Wie kann ich bei Verwendung einer URL mit einer URL feststellen, ob es sich um ein Bild handelt? 

Es gibt keinen Kontext für die URL - sie befindet sich nur in der Mitte einer einfachen Textdatei oder möglicherweise nur in einer Zeichenfolge.

Ich möchte keinen hohen Overhead (z. B. Lesen des Inhalts der URL), da dies für viele URLs auf einer Seite aufgerufen werden kann. Angesichts dieser Einschränkung ist es nicht wesentlich, dass alle Bilder identifiziert werden, aber ich möchte eine ziemlich gute Vermutung. 

Im Moment schaue ich mir nur die Dateierweiterung an, aber es scheint, als sollte es einen besseren Weg geben.

Folgendes habe ich momentan:

  function isImage( $url )
  {
    $pos = strrpos( $url, ".");
    if ($pos === false)
      return false;
    $ext = strtolower(trim(substr( $url, $pos)));
    $imgExts = array(".gif", ".jpg", ".jpeg", ".png", ".tiff", ".tif"); // this is far from complete but that's always going to be the case...
    if ( in_array($ext, $imgExts) )
      return true;
    return false;
  }

Edit: Falls es für alle anderen nützlich ist, ist hier die endgültige Funktion mit der Technik aus der Antwort von Emil H.:

  function isImage($url)
  {
     $params = array('http' => array(
                  'method' => 'HEAD'
               ));
     $ctx = stream_context_create($params);
     $fp = @fopen($url, 'rb', false, $ctx);
     if (!$fp) 
        return false;  // Problem with url

    $meta = stream_get_meta_data($fp);
    if ($meta === false)
    {
        fclose($fp);
        return false;  // Problem reading data from url
    }

    $wrapper_data = $meta["wrapper_data"];
    if(is_array($wrapper_data)){
      foreach(array_keys($wrapper_data) as $hh){
          if (substr($wrapper_data[$hh], 0, 19) == "Content-Type: image") // strlen("Content-Type: image") == 19 
          {
            fclose($fp);
            return true;
          }
      }
    }

    fclose($fp);
    return false;
  }
50
danio

Sie können eine HTTP HEAD -Anforderung verwenden und den Inhaltstyp überprüfen. Dies könnte ein guter Kompromiss sein. Dies kann mit PHP Streams erfolgen. Wez Furlong hat einen article , der zeigt, wie dieser Ansatz zum Senden von Post-Requests verwendet werden kann. Er kann jedoch einfach für den Versand von HEAD-Requests angepasst werden. Sie können die Header von einer http-Antwort mit stream_get_meta_data () abrufen.

Natürlich ist das nicht wirklich 100%. Einige Server senden falsche Header. Es behandelt jedoch Fälle, in denen Bilder über ein Skript bereitgestellt werden und die korrekte Dateierweiterung nicht verfügbar ist. Der einzige Weg, um wirklich sicher zu sein, besteht darin, das Bild tatsächlich abzurufen - entweder alles oder die ersten Bytes, wie von thomasrutter vorgeschlagen.

28
Emil H
if(is_array(getimagesize($urlImg)))
    echo 'Yes it is an image!';
13
Pedro Soares

Es gibt verschiedene Ansätze.

  • Ermitteln Sie den Inhalt, indem Sie am Anfang der Datei nach einer magischen Zahl suchen. Beispielsweise verwendet GIF GIF87 oder GIF89 als die ersten fünf Bytes der Datei (in ASCII). Leider kann dies nicht feststellen, ob ein Fehler im Bild vorliegt oder ob das Bild schädliche Inhalte enthält. Hier sind einige magische Zahlen für verschiedene Arten von Bilddateien (verwenden Sie diese gerne):

     "\ xff\xd8\xff" => 'image/jpeg', 
     "\ x89PNG\x0d\x0a\x1a\x0a" => 'image/png', 
     "II *\x00 "=> 'image/tiff', 
    " MM\x00 * "=> 'image/tiff', 
    "\x00\x00\x01\x00 "=> 'image/ico', 
     "\ x00\x00\x02\x00" => 'image/ico', 
     "GIF89a" => 'image/gif', 
     "GIF87a" => 'image/gif', 
     " BM "=> 'image/bmp', 
    

    Wenn Sie den Inhalt so schnüffeln, wird er wahrscheinlich Ihren Anforderungen am besten entsprechen. Sie müssen nur die ersten Bytes der Datei (hinter dem Header) lesen und herunterladen.

  • Laden Sie das Image mit der Gd-Bibliothek, um zu sehen, ob es fehlerfrei geladen wird. Dies kann Ihnen sagen, ob das Bild fehlerfrei ist oder nicht. Leider entspricht dies wahrscheinlich nicht Ihren Anforderungen, da das vollständige Bild heruntergeladen werden muss.

  • Wenn Sie wirklich keine HTTP-Anfrage für das Image erstellen möchten, ist sowohl das Sniffing als auch das Abrufen von HTTP-Headern ausgeschlossen. Sie können jedoch anhand des Kontextes, in dem es verlinkt ist, feststellen, ob etwas ein Bild ist. Etwas, das mit einem src-Attribut in einem <img-Element verknüpft ist, ist fast sicher ein Bild (oder ein Versuch bei XSS, aber das ist eine andere Geschichte). Dadurch erfahren Sie, ob etwas als Bild gedacht ist. Sie erfahren nicht, ob das Bild tatsächlich verfügbar oder gültig ist. Sie müssen mindestens den ersten kleinen Teil (Header- oder Magic-Nummer) der Bild-URL abrufen, um diesen zu finden.

Leider ist es möglich, dass eine Datei sowohl ein gültiges Bild als auch eine Zip-Datei ist, die schädlichen Inhalt enthält, der von einer schädlichen Site als Java ausgeführt werden kann - siehe den GIFAR-Exploit . Sie können diese Sicherheitsanfälligkeit mit großer Wahrscheinlichkeit verhindern, indem Sie das Bild in eine Bibliothek wie Gd laden und einen nicht trivialen Filter ausführen, z. B. ein wenig weichzeichnen oder schärfen (dh einen Faltungsfilter verwenden) und in einer neuen Datei speichern. ohne die Übertragung von Metadaten.

Der Versuch herauszufinden, ob etwas ein Bild ist, und zwar allein anhand des Inhaltstyps, ist ziemlich unzuverlässig, fast so unzuverlässig wie das Überprüfen der Dateierweiterung. Beim Laden eines Bildes mit einem <img-Element suchen Browser nach einer magischen Zeichenfolge.

13
thomasrutter

Neben Emil Hs Antwort:

Verwendung von get_headers() zum Überprüfen des Inhaltstyps einer URL ohne Herunterladen der gesamten Datei mit getimagesize()

    $url_headers=get_headers($url, 1);

    if(isset($url_headers['Content-Type'])){

        $type=strtolower($url_headers['Content-Type']);

        $valid_image_type=array();
        $valid_image_type['image/png']='';
        $valid_image_type['image/jpg']='';
        $valid_image_type['image/jpeg']='';
        $valid_image_type['image/jpe']='';
        $valid_image_type['image/gif']='';
        $valid_image_type['image/tif']='';
        $valid_image_type['image/tiff']='';
        $valid_image_type['image/svg']='';
        $valid_image_type['image/ico']='';
        $valid_image_type['image/icon']='';
        $valid_image_type['image/x-icon']='';

        if(isset($valid_image_type[$type])){

            //do something

        }
    }
10
RafaSashi

Bearbeiten: Für statische Bilder mit beliebter Bilderweiterung. 

<?php
$imgExts = array("gif", "jpg", "jpeg", "png", "tiff", "tif");
$url ='path/to/image.png';
$urlExt = pathinfo($url, PATHINFO_EXTENSION);
if (in_array($urlExt, $imgExts)) {
    echo 'Yes, '.$url.' is an Image';
}

?>
6
TheMonkeyKing

Ähnlich wie bei einer gegebenen Antwort, jedoch mit einer etwas anderen Logik.

$headers = @get_headers($url, 1); // @ to suppress errors. Remove when debugging.
if (isset($headers['Content-Type'])) {
  if (strpos($headers['Content-Type'], 'image/') === FALSE) {
    // Not a regular image (including a 404).
  }
  else {
    // It's an image!
  }
}
else {
  // No 'Content-Type' returned.
}

@ ist ein Fehlersteuerungsoperator .

Beachten Sie, dass wir den "strengen" Operator === FALSE in der Bedingung verwendet haben, da strpos($headers['Content-Type'], 'image/') in unserem Anwendungsfall 0 zurückgibt, wenn die Nadel im Heuhaufen gefunden wird. Bei der Typumwandlung mit == würde dies irrtümlicherweise als FALSE interpretiert werden.

2
Martin Postma

wir können exif_imagetype verwenden, um den Bildtyp zu überprüfen, sodass andere Inhaltstypen nicht zulässig sind. Es lassen nur Bilder zu und wir können sie auf wenige Bildtypen beschränken. Der folgende Beispielcode zeigt, wie GIF-Bildtypen zugelassen werden.

if (exif_imagetype('image.gif') != IMAGETYPE_GIF) {
    echo 'The picture is not a gif';
}

Sie können folgende Bildtypen verwenden:

 IMAGETYPE_GIF
 IMAGETYPE_JPEG
 IMAGETYPE_PNG
 IMAGETYPE_SWF
 IMAGETYPE_PSD
 IMAGETYPE_BMP
 IMAGETYPE_TIFF_II (intel byte order)
 IMAGETYPE_TIFF_MM (Motorola byte order)
 IMAGETYPE_JPC
 IMAGETYPE_JP2
 IMAGETYPE_JPX
 IMAGETYPE_JB2
 IMAGETYPE_SWC
 IMAGETYPE_IFF
 IMAGETYPE_WBMP
 IMAGETYPE_XBM
 IMAGETYPE_ICO

weitere Details: link

1

Schnelle Lösung für defekte oder nicht gefundene Bilder link  
Ich empfehle Ihnen, dass Sie getimagesize () nicht verwenden, da das Bild zuerst heruntergeladen wird und dann die Bildgröße überprüft wird. Wenn dies nicht der Fall ist, wird eine Ausnahme ausgelöst 

if(checkRemoteFile($imgurl))
{
//found url, its mean
echo "this is image";
}

function checkRemoteFile($url)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$url);
    // don't download content
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    curl_setopt($ch, CURLOPT_FAILONERROR, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if(curl_exec($ch)!==FALSE)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Hinweis: Dieser aktuelle Code hilft Ihnen, beschädigte oder nicht gefundene URL-Images zu identifizieren. Dies hilft Ihnen nicht, Image-Typ oder Header zu identifizieren

0
Hassan Saeed