Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

IMAGE BODY GUARD


Information sur la source

Description

Salut,

J'avais envie de faire une petite fonction qui gère l'affichage d'une image.
L'idée était de ne pas pouvoir appeler l'image directement, mais de passer forcément par un script. La raison était simple : permettre de limiter l'affichage au site web auquel elle appartient, gérer des permissions en fonction de critères divers et variés (que je n'ai pas implémentés et qui peuvent l'être grâce à une fonction de callback.

Je sais bien qu'on peut obtenir la même chose avec un fichier .htaccess, mais... là, on peut gérer les droits en fonction d'une session php. Par ailleurs, cette source n'empêche évidemment pas l'utilisateur d'enregistrer l'image sur son disque dur, hein...

Au final, j'ai fait une classe en PHP5, ce qui permet :
- d'avoir une fonction de callback pour gérer les autorisations (adresse IP, ses
- d'étendre la classe pour lui apporter des fonctionnalités en plus (rajouter un copyright, par exemple)
- de récupérer le contenu de l'image sans pour autant l'afficher (sous forme d'une chaine, je sais, c'est crade)
- d'avoir un code propre (c'est peut-être idiot ce que je dis) avec des Exceptions
- d'éviter les doublons dans le code
- de se passer de .htaccess sur Windows...

Le code est documenté au standard phpDoc et je pense assez clair, mais je vous fait quand même un petit topo.

Les méthodes publiques sont :
Setters :
- set_auth_handler : définit la fonction qui gère les autorisations. Si elle n'est pas utilisée, la fonctionnalité est désactivée.
- set_directory : définit le répertoire par défaut où piocher les images (peut être spécifié explicitement pour chaque image, si besoin)
- set_referer_check : même principe que session_referer_check. Il s'agit d'une sous-chaine recherchée dans le referer HTTP. Si elle n'est pas utilisée, la fonctionnalité n'est pas utilisée.
- set_forbidden_image : image à afficher à la place de l'image demandée en cas d'interdiction

Affichage d'image :
- display : affiche l'image en paramètre, se trouvant éventuellement dans le répertoire en paramètre
- get_image : récupère dans une chaine le contenu de l'image et stocke dans la propriété header l'entête à renvoyer (avec header() ) pour un affichage ultérieur
- display_forbidden : affiche l'image d'interdiction

Les messages renvoyés avec les exceptions qui sont levées peuvent être :
- IBG_Error_occured : erreur lors de l'accès au fichier (qui existe pourtant) : n'est pas censée se produire...
- IBG_Not_an_image : le fichier demandé n'est pas une image
- IG_File_not_exists : le fichier demandé n'existe pas
- IG_Forbidden : affichage interdit pour cette image. Ne survient que si aucune image d'interdiction n'est définie.

Voici donc la source :
 

Source

  • <?php
  • /**
  • * Project : Image Body Guard
  • * File : ImageGuard.class.php
  • *
  • * @author Neige < neige at orphyx dot net >
  • * @copyright &copy; 2007 - Neige
  • * @package Image Body Guard
  • * @version 1.0.0
  • * @licence http://creativecommons.org/licenses/by-nc-sa/2.0/fr/
  • */
  • /**
  • * @package Image Body Guard
  • */
  • class ImageBodyGuard
  • {
  • /**
  • * Callback function to check authorization to display image
  • * @var string
  • */
  • protected $_auth_handler;
  • /**
  • * Substring to check presence in HTTP Referer
  • * @var string
  • */
  • protected $_referer_check;
  • /**
  • * Default directory to use
  • * @var string
  • */
  • protected $_directory;
  • /**
  • * Image to display when display not authorized
  • * Contents : header (mime type) and image contents
  • * @var array
  • */
  • protected $_forbidden_image = array();
  • /**
  • * Header to be sent for image to display
  • * @var string
  • */
  • public $_header;
  • /**
  • * Instance of the object
  • * @var object
  • */
  • protected static $_instance;
  • /**
  • * Returns the unique instance of the class
  • * @return object
  • */
  • public static function getInstance()
  • {
  • if (empty(self::$_instance))
  • {
  • self::$_instance = new ImageGuard();
  • }
  • return self::$_instance;
  • }
  • /**
  • * Setter for $_auth_handler
  • * @param string The function name
  • */
  • public function set_auth_handler($function_name)
  • {
  • if (is_callable($function_name))
  • {
  • $this -> _auth_handler = $function_name;
  • }
  • }
  • /**
  • * Setter for $_referer_check
  • * @param string Substring to search for in HTTP Referer
  • */
  • public function set_referer_check($referer_check)
  • {
  • $this -> _referer_check = (string) $referer_check;
  • }
  • /**
  • * Setter for $_forbidden_image
  • * @param string Path to image
  • */
  • public function set_forbidden_image($image)
  • {
  • $image_size = $this -> _get_image_size($image);
  • $this -> _forbidden_image = array(
  • 'header' => 'Content-Type: ' . $image_size['mime'],
  • 'contents' => file_get_contents($image));
  • }
  • /**
  • * Setter for $_directory
  • * @param string Default directory
  • */
  • /**
  • * Checks if referer is ok
  • * @todo Allow multiple referers to display image
  • */
  • protected function _check_referer()
  • {
  • $referer_ok = TRUE;
  • if (!empty($this -> _referer_check))
  • {
  • if (array_key_exists('HTTP_REFERER', $_SERVER))
  • {
  • $referer = $_SERVER['HTTP_REFERER'];
  • if (stristr($referer, $this -> _referer_check) === FALSE)
  • {
  • $referer_ok = FALSE;
  • }
  • }
  • }
  • return $referer_ok;
  • }
  • /**
  • * Check if display is authorized according
  • * to auth callback function
  • */
  • protected function _check_auth()
  • {
  • if (!empty($this -> _auth_handler) && function_exists($this -> _auth_handler))
  • {
  • if (call_user_func($this -> _auth_handler))
  • {
  • return TRUE;
  • }
  • else
  • {
  • return FALSE;
  • }
  • }
  • else
  • {
  • return TRUE;
  • }
  • }
  • /**
  • * Check general auth
  • */
  • protected function _is_auth()
  • {
  • return ($this -> _check_auth() && $this -> _check_referer());
  • }
  • /**
  • * Display forbidden image if not authorized
  • * @todo Display a message if no default image file
  • */
  • protected function display_forbidden()
  • {
  • if (!empty($this -> _forbidden_image))
  • {
  • header($this -> _forbidden_image['header']);
  • echo $this -> _forbidden_image['contents'];
  • }
  • else
  • {
  • throw new Exception('IBG_Forbidden');
  • }
  • }
  • /**
  • * Display the image
  • * @param string $filename Image filename
  • * @param string $directory Directory where image is located
  • */
  • public function display($file_name, $directory = '')
  • {
  • if ($this -> _is_auth())
  • {
  • $image_content = $this -> get_image($file_name, $directory);
  • header($this -> _header);
  • echo $image_content;
  • }
  • else
  • {
  • $this -> display_forbidden();
  • }
  • }
  • /**
  • * Returns image contents and sets $this -> header
  • * @param string $image_file
  • * @param string $directory
  • */
  • public function get_image($image_file, $directory = '')
  • {
  • $image_size = $this -> _get_image_size($image_file, $directory);
  • $this -> _header = 'Content-Type: ' . $image_size['mime'];
  • $image_content = @file_get_contents($image_file);
  • if ($image_content === FALSE)
  • {
  • throw new Exception('IBG_Error_occured');
  • }
  • else
  • {
  • return $image_content;
  • }
  • }
  • /**
  • * Returns image size, mime type and other data provided
  • * by php native function getimagesize()
  • * @param string $image_file
  • * @param string $directory
  • */
  • protected function _get_image_size($image_file, $directory = '')
  • {
  • if (!empty($this -> directory) && empty($directory))
  • {
  • $directory = $this -> _directory;
  • }
  • if (is_file($directory . $image_file))
  • {
  • if (!$image_size = getimagesize($image_file))
  • {
  • throw new Exception('IBG_Not_an_image');
  • }
  • else
  • {
  • return $image_size;
  • }
  • }
  • else
  • {
  • throw new Exception('IBG_File_not_exists');
  • }
  • }
  • }
  • ?>
  • <?php
  • /*
  • * EXEMPLE D'UTILISATION
  • */
  • $imageBG = ImageBodyGuard::getInstance();
  • $imageBG -> set_auth_handler('auth');
  • $imageBG -> set_referer_check('domaine.tld');
  • $image = $_GET['image'];
  • $imageBG -> display($image);
  • ?>
<?php
/**
 * Project : Image Body Guard
 * File    : ImageGuard.class.php
 *
 * @author Neige < neige at orphyx dot net >
 * @copyright &copy; 2007 - Neige
 * @package Image Body Guard
 * @version 1.0.0
 * @licence http://creativecommons.org/licenses/by-nc-sa/2.0/fr/
 */

/**
 * @package Image Body Guard
 */
class ImageBodyGuard
{
	/**
	 * Callback function to check authorization to display image
	 * @var string
	 */
	protected $_auth_handler;

	/**
	 * Substring to check presence in HTTP Referer
	 * @var string
	 */
	protected $_referer_check;

	/**
	 * Default directory to use
	 * @var string
	 */
	protected $_directory;

	/**
	 * Image to display when display not authorized
	 * Contents : header (mime type) and image contents
	 * @var array
	 */
	protected $_forbidden_image = array();

	/**
	 * Header to be sent for image to display
	 * @var string
	 */
	public $_header;

	/**
	 * Instance of the object
	 * @var object
	 */
	protected static $_instance;

	/**
	 * Returns the unique instance of the class
	 * @return object
	 */
	public static function getInstance()
	{
		if (empty(self::$_instance))
		{
			self::$_instance = new ImageGuard();
		}
		return self::$_instance;
	}

	/**
	 * Setter for $_auth_handler
	 * @param string The function name
	 */
	public function set_auth_handler($function_name)
	{
		if (is_callable($function_name))
		{
			$this -> _auth_handler = $function_name;
		}
	}

	/**
	 * Setter for $_referer_check
	 * @param string Substring to search for in HTTP Referer
	 */
	public function set_referer_check($referer_check)
	{
		$this -> _referer_check = (string) $referer_check;
	}

	/**
	 * Setter for $_forbidden_image
	 * @param string Path to image
	 */
	public function set_forbidden_image($image)
	{
		$image_size = $this -> _get_image_size($image);
		$this -> _forbidden_image = array(
			'header' => 'Content-Type: ' . $image_size['mime'],
			'contents' => file_get_contents($image));
	}

	/**
	 * Setter for $_directory
	 * @param string Default directory
	 */

	/**
	 * Checks if referer is ok
	 * @todo Allow multiple referers to display image
	 */
	protected function _check_referer()
	{
		$referer_ok = TRUE;
		if (!empty($this -> _referer_check))
		{
			if (array_key_exists('HTTP_REFERER', $_SERVER))
			{
				$referer = $_SERVER['HTTP_REFERER'];
				if (stristr($referer, $this -> _referer_check) === FALSE)
				{
					$referer_ok = FALSE;
				}
			}
		}
		return $referer_ok;
	}

	/**
	 * Check if display is authorized according
	 * to auth callback function
	 */
	protected function _check_auth()
	{
		if (!empty($this -> _auth_handler) && function_exists($this -> _auth_handler))
		{
			if (call_user_func($this -> _auth_handler))
			{
				return TRUE;
			}
			else
			{
				return FALSE;
			}
		}
		else
		{
			return TRUE;
		}
	}

	/**
	 * Check general auth
	 */
	protected function _is_auth()
	{
		return ($this -> _check_auth() && $this -> _check_referer());
	}

	/**
	 * Display forbidden image if not authorized
	 * @todo Display a message if no default image file
	 */
	protected function display_forbidden()
	{
		if (!empty($this -> _forbidden_image))
		{
			header($this -> _forbidden_image['header']);
			echo $this -> _forbidden_image['contents'];
		}
		else
		{
			throw new Exception('IBG_Forbidden');
		}
	}

	/**
	 * Display the image
	 * @param string $filename Image filename
	 * @param string $directory Directory where image is located
	 */
	public function display($file_name, $directory = '')
	{
		if ($this -> _is_auth())
		{
			$image_content = $this -> get_image($file_name, $directory);
			header($this -> _header);
			echo $image_content;
		}
		else
		{
			$this -> display_forbidden();
		}
	}

	/**
	 * Returns image contents and sets $this -> header
	 * @param string $image_file
	 * @param string $directory
	 */
	public function get_image($image_file, $directory = '')
	{
		$image_size = $this -> _get_image_size($image_file, $directory);
		$this -> _header = 'Content-Type: ' . $image_size['mime'];
		$image_content = @file_get_contents($image_file);
		if ($image_content === FALSE)
		{
			throw new Exception('IBG_Error_occured');
		}
		else
		{
			return $image_content;
		}
	}

	/**
	 * Returns image size, mime type and other data provided
	 * by php native function getimagesize()
	 * @param string $image_file
	 * @param string $directory
	 */
	protected function _get_image_size($image_file, $directory = '')
	{
		if (!empty($this -> directory) && empty($directory))
		{
			$directory = $this -> _directory;
		}
		if (is_file($directory . $image_file))
		{
			if (!$image_size = getimagesize($image_file))
			{
				throw new Exception('IBG_Not_an_image');
			}
			else
			{
				return $image_size;
			}
		}
		else
		{
			throw new Exception('IBG_File_not_exists');
		}
	}
}
?>

<?php

/*
 * EXEMPLE D'UTILISATION
 */

$imageBG = ImageBodyGuard::getInstance();
$imageBG -> set_auth_handler('auth');
$imageBG -> set_referer_check('domaine.tld');

$image = $_GET['image'];

$imageBG -> display($image);

?>

Conclusion

J'ai fait ça sans trop me poser de question sur l'utilité ou les performances.
Question utilité, j'en ai déjà parlé un peu... J'attends vos avis éclairés et avisés sur la chose.
Concernant les performances, il est évident que traiter l'affichage d'une image consomme des ressources... J'ai essayé de ne pas trop abuser. J'attends aussi vos commentaires sur le sujet.

En ce qui concerne la sécurité, je ne sais pas trop ce que ça vaut non plus... Comme montré dans l'exemple, une utilisation typique est $image = $_GET['image'];
Faut-il faire ou non un traitement sur la variable GET malgré les tests effectués dans le code ? J'ai pas trop de recul à ce niveau là, donc là encore, tout commentaire est le bienvenu.

Evolution que j'envisage : possibilité d'autoriser plusieurs Referers
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Commentaires et avis

signaler à un administrateur
Commentaire de coucou747 le 29/05/2007 02:38:22

en fait, je ne vois pas vraiment l'interret de passer par une classe pour ca... tu fais une verif d'auth par un pointeur sur fonction, ca reviendrait au meme que de le faire directement avec un truc genre

if (auth() && refer()){
header(...);
echo file_get_contents(..);
}

sinon, tu pourrais proposer un header sans appeller getimagesize et autre car c'est pas toujours obligatoire

signaler à un administrateur
Commentaire de neigedhiver le 29/05/2007 08:26:46

Ben ouais, y'a peut-être pas d'intérêt...
Faut encore que j'y réfléchisse...

"sinon, tu pourrais proposer un header sans appeller getimagesize et autre car c'est pas toujours obligatoire"
=> Pas compris...

signaler à un administrateur
Commentaire de coucou747 le 29/05/2007 15:47:25

display affiche le header que lui donne getimage, or si moi j'ai que des .jpg, bah j'ai pas besoin de ca...

signaler à un administrateur
Commentaire de neigedhiver le 29/05/2007 17:03:58

Certes... Je n'avais pas vu les choses comme ça... Ben dans ce cas, j'utilise une autre méthode pour récupérer le header.

Sinon, j'ai pas réussi à déterminer si la classe était vraiment utile... Ah bravo...

signaler à un administrateur
Commentaire de malalam le 29/05/2007 18:33:49 administrateur CS

Hello,

c'est pas mal codé, mais j'ai, moi aussi, du mal à me décider sur l'intérêt réel de ton code, lol.
Je n'arrive pas à trouver dans quel cas je pourrais avoir besoin d'une telle "protection". Et si, dans un tel cas, je ne passerais en effet pas par un simple if ().
Mais ça reste intéressant quand même...sur le fond. Ca peut amener a des réflexions pour approfondir ça, je pense. Bon, y a des bémols hein : le HTTP_REFERER...par exemple...si il n'y est pas, par défaut, c'est ok. Donc, suffit de de le désactiver ou de le masquer (c'est faisable). IE par exemple, bien souvent, par défaut, le masque...

signaler à un administrateur
Commentaire de coucou747 le 29/05/2007 18:46:59

tu fais un site pour adultes, et seuls ceux qui ont payes accedent aux images, ca peut etre utile.... mais c'est clair que cette classe est disproportionee comparee a ce qu'elle fait...

signaler à un administrateur
Commentaire de neigedhiver le 29/05/2007 22:56:22

@malalam
"c'est pas mal codé,"
=> Merci. Venant de ta part, ça fait plaisir.

"Bon, y a des bémols hein : le HTTP_REFERER...par exemple...si il n'y est pas, par défaut, c'est ok."
=> Tiens oui, c'est idiot... Si le referer est nécessaire, ça ne devrait pas se comporter comme ça...

@coucou747
"mais c'est clair que cette classe est disproportionee comparee a ce qu'elle fait..."
Ben ouais, plus j'y pense, et plus c'est ce que je me dis.

En même temps, faut replacer les choses dans mon contexte actuel... J'ai récemment fait l'acquisition d'un bouquin sur PHP5 (PHP5 - Best practices chez Eyrolles) et du coup, je suis un peu à fond dans la POO, je vois des classes partout...
Quand j'ai pensé à cette fonctionnalité, j'ai commencé par une fonction et, assez naturellement, j'en suis venu à faire une classe, pour regrouper des fonctions au même endroit, sans me poser la question : "est-ce nécessaire ou bien est-ce démesuré" ?

Manifestement, ce n'était pas nécessaire.

Ca m'aura au moins permis de vérifier que je code pas trop dégueulasse, si j'en crois malalam...

On va dire que c'était de l'entrainement...

En tout cas merci pour vos commentaires, je vais peut-être réécrire tout ça avec de simples fonctions toutes bêtes...

signaler à un administrateur
Commentaire de coucou747 le 29/05/2007 23:17:31

eh, j'ai pas dit que c'etait crade... seulement voila, tu mets 150 lignes pour faire un truc reutilisable dans un seul cas... celui ou 5 lignes suffisent... c'est bien code, mais selon moi, pas utile

signaler à un administrateur
Commentaire de neigedhiver le 29/05/2007 23:29:49

Ah mais j'ai pas dit que t'avais dit que... C'était plutôt une réflexion à voix haute, pour moi... mais à voix haute...

Non mais de faire des trucs qui servent à rien, c'est au moins utile pour moi : je m'entraine, j'apprends à me poser les bonnes questions (est-ce que c'est vraiment la peine, etc).

Donc merci pour les commentaires, encore une fois, ça me permet d'y voir plus clair.

signaler à un administrateur
Commentaire de bugs74 le 04/06/2007 11:05:19

il me semble que qu'une protection par htaccess fait ca très bien.
google : hotlinking htaccess

signaler à un administrateur
Commentaire de neigedhiver le 04/06/2007 11:07:01

Ca fait plaisir de voir qu'on lit mes commentaires :

"Je sais bien qu'on peut obtenir la même chose avec un fichier .htaccess, mais... là, on peut gérer les droits en fonction d'une session php."

Donc merci de la précision inutile...

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Protection d' image original [ par overbrave ] Salut Dieu du code,Je sais qu'il existe toute sorte de script ou fonction permettant de bloquer le clique droit, etc ...Ces fonction sont senc&#233; n réécriture d'un script en POO, comment faire? [ par craso ] Bonjour,j'ai développé cette petite application http://pipcorp.free.fr/Il s'agit d'une image clicable, le personnage centrale se positionne a l'endroi Comment ca marche cette petite bete? [ par craso ] bonjour,en surfant, je suis tombé sur le site http://www.phpied.com/image-fun/ .Je souhaite qu'on m'explique comment trnsformer une image comme sur le Aide sur image anti-spam... [ par Tanaka56 ] Bonjour. J'ai intégré sur une page l'image anti-spam du lien :http://www.phpcs.com/codes/IMAGE-ANTI-SPAM_38969.aspxCependant, je rencontre un problème Envoi ftp - données base64 [ par franchu23 ] Salut, Mon fichier php reçoit les données pour afficher une image jpeg de la manière suivante : header('Content-type: image/jpeg'); header('Co récupérer image à partir de l'url [ par carter64s ] Mon probleme : j'aimerais pouvoir uploader une image sur mon serveur mais elle ne se trouve pas sur mon ordinateur, j'ai l'url , cette image change so Sessions sur 2 scripts [ par guill76 ] Salut,SI Quelqu'un pouvait m'expliquer le pb suivant et comment le résoudre:Dans le corps de mon script principal  index.php , j'insere une balise ima Upload d'image et post de commentaire lié avec mysql [ par Padaone91 ] Bonjour à tous ceux qui liront ce petit bout de texte, Voilà je souhaite créer une page qui permettra à mes visiteurs d'upload une image et ensuite d redimensionner une image à la taille de l'écran [ par jipe32 ] Bonjour à tous,j'ai uen image bg.jpg qui fait 2506x1920 et 1,77Moy'a t-il une silution pour la redimensionner exactement à la taille de l'écran de l'i resize image sous easyphp [ par ludovicanceaux ] Salut à tous, j'ai crée un code pour uploader une image puis la redimensionner avec une largeur de 160 pixels, seulement ca marche sur le net, mais en


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,468 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.