web-dev-qa-db-fra.com

meilleure façon de déterminer si une URL est une image PHP

À l'aide de PHP, à partir d'une URL, comment puis-je déterminer s'il s'agit d'une image? 

Il n'y a pas de contexte pour l'URL - c'est juste au milieu d'un fichier texte brut, ou peut-être juste une chaîne par elle-même.

Je ne veux pas de surcharge (par exemple, la lecture du contenu de l'URL), car cela pourrait être appelé pour plusieurs URL sur une page. Compte tenu de cette restriction, il n’est pas essentiel que toutes les images soient identifiées, mais j’aimerais bien deviner. 

Pour le moment, je ne fais que regarder l'extension du fichier, mais il me semble qu'il devrait y avoir un meilleur moyen que celui-ci.

Voici ce que j'ai actuellement:

  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: Au cas où cela serait utile à quelqu'un d'autre, voici la dernière fonction utilisant la technique de la réponse d'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

Vous pouvez utiliser une requête HTTP HEAD et vérifier le type de contenu. Cela pourrait être un bon compromis. Cela peut être fait en utilisant PHP Streams . Wez Furlong a un article qui montre comment utiliser cette approche pour envoyer des demandes de publication, mais il peut être facilement adapté pour envoyer des demandes HEAD à la place. Vous pouvez récupérer les en-têtes d'une réponse http en utilisant stream_get_meta_data () .

Bien sûr, ce n'est pas vraiment à 100%. Certains serveurs envoient des en-têtes incorrects. Toutefois, il traitera les cas où les images sont livrées via un script et que l'extension de fichier appropriée n'est pas disponible. Le seul moyen d'être vraiment certain est de récupérer l'image - la totalité ou les quelques premiers octets, comme suggéré par thomasrutter.

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

Il y a quelques approches différentes.

  • Reniflez le contenu en recherchant un nombre magique au début du fichier. Par exemple, GIF utilise GIF87 ou GIF89 comme les cinq premiers octets du fichier (en ascii). Malheureusement, cela ne peut pas vous dire s'il y a une erreur dans l'image ou si l'image contient un contenu malveillant. Voici quelques chiffres magiques pour différents types de fichiers image (n'hésitez pas à les utiliser):

     "\ xff\xd8\xff" => 'image/jpeg', 
     "\ x89PNG\x0d\x0a\x0a\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', 
    

    Renifler le contenu comme cela va probablement répondre à vos besoins; vous n'aurez qu'à lire et donc télécharger les premiers octets du fichier (au-delà de l'en-tête).

  • Chargez l'image à l'aide de la bibliothèque Gd pour voir si elle se charge sans erreur. Cela peut vous dire si l'image est valide, sans erreur ou non. Malheureusement, cela ne correspond probablement pas à vos besoins, car il faut télécharger l'image complète.

  • Si vous ne voulez vraiment pas faire de requête HTTP pour l'image, cela exclut à la fois de rechercher et d'obtenir des en-têtes HTTP. Vous pouvez toutefois essayer de déterminer si quelque chose est une image en fonction du contexte dans lequel elle est liée. Quelque chose lié à l'aide d'un attribut src dans un élément <img est presque certainement une image (ou une tentative de XSS, mais c'est une autre histoire). Cela vous dira si quelque chose est conçu comme une image. Cela ne vous dira pas si l'image est réellement disponible ou valide; vous devez récupérer au moins la première petite partie (en-tête ou nombre magique) de l'URL de l'image pour le trouver.

Malheureusement, il est possible qu'un fichier soit à la fois une image valide et un fichier Zip contenant un contenu préjudiciable pouvant être exécuté au format Java par un site nuisible - voir l'exploit GIFAR . Vous pouvez certainement éviter cette vulnérabilité en chargeant l'image dans une bibliothèque telle que Gd et en effectuant un filtrage non trivial, comme l'adoucir ou la rendre plus nette (utilisez un filtre de convolution, par exemple), puis enregistrez-la dans un nouveau fichier sans transférer aucune métadonnée.

Essayer de déterminer si quelque chose est une image uniquement par son type de contenu est tout à fait peu fiable, presque aussi fiable que la vérification de l'extension de fichier. Lors du chargement d'une image à l'aide d'un élément <img, les navigateurs recherchent une chaîne magique.

13
thomasrutter

En plus de la réponse d'Emil H:

Utilisation de get_headers() pour vérifier le type de contenu d'une URL sans télécharger l'intégralité du fichier avec 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

Éditer: Pour les images statiques avec une extension d'image populaire. 

<?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

Semblable à certaines réponses données mais avec une logique légèrement différente.

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

@ est un opérateur de contrôle error .

Notez que nous avons utilisé l'opérateur "strict" === FALSE dans la condition car strpos($headers['Content-Type'], 'image/') renvoie 0 dans notre cas d'utilisation si l'aiguille se trouve dans la botte de foin. Avec le transtypage utilisant ==, cela serait interprété à tort comme FALSE.

2
Martin Postma

nous pouvons utiliser exif_imagetype pour vérifier le type d'image, afin qu'il ne soit pas autorisé pour d'autres types de contenu. Il n'autorise que les images et nous pouvons les limiter à quelques types d'image. Les exemples de code suivants montrent comment autoriser le type d'image GIF.

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

Vous pouvez utiliser les types d’image suivants,

 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

plus de détails: link

1
Janith Chinthana

Solution rapide pour les images brisées ou non trouvées link  
Je vous recommande de ne pas utiliser getimagesize () car cela permettra de télécharger la première image puis de vérifier la taille de l'image + si cela ne crée pas d'image, une exception sera renvoyée. 

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

Remarque: Ce code actuel vous aide à identifier l’image URL brisée ou introuvable. Elle ne vous aidera pas à identifier le type d’image ou les en-têtes.

0
Hassan Saeed