Version en ligne

Tutoriel : Créer un avatar aléatoire

Table des matières

Créer un avatar aléatoire
Pourquoi ce tuto ?
Un avatar aléatoire et un serveur qui dort : renommer ses fichiers
L'avatar semi-aléatoire et le cache
Deux avatars en un
Feinter les protections : faire croire que son image aléatoire est une vraie image

Créer un avatar aléatoire

Pourquoi ce tuto ?

Vous désirez avoir un avatar aléatoire, différent à chaque affichage, comme le mien ?
Vous estimez que les dizaines de scripts sur le sujet que l'on trouve sur Internet sont horriblement compliqués pour quelque chose qui a l'air simple ?

Ce tutoriel est là pour vous !

Pourquoi ce tuto ?

Un avatar aléatoire et un serveur qui dort : renommer ses fichiers

Les avatars aléatoires, c'est-à-dire qui affichent une image différente à chaque rafraîchissement (ou selon tout autre paramètre) sont très à la mode, et on trouve énormément de scripts sur Internet qui permettent d'en faire.

Malheureusement, la très grande majorité de ces scripts sont des horreurs finies, des choses de dizaines et dizaines de lignes, avec des variables dans tous les sens, des constantes, etc.
À la limite, le problème n'est pas tellement là : on colle le script, il marche, on n'a pas besoin de savoir comment il fonctionne.

Non, le problème est que beaucoup de ces scripts utilisent des fonctions beaucoup trop lourdes pour le serveur par rapport à ce dont on a réellement besoin.
On commence avec un petit array(), puis on passe à glob(), et on finit par utiliser l'extension GD pour afficher une image qui se trouve à l'identique sur le disque dur… GD est une librairie très pratique, mais très lourde en calculs pour un serveur.
Et comme on va le voir, on n'en a pratiquement jamais besoin.


Un avatar aléatoire et un serveur qui dort : renommer ses fichiers

Un avatar aléatoire et un serveur qui dort : renommer ses fichiers

Pourquoi ce tuto ? L'avatar semi-aléatoire et le cache

L'avatar aléatoire le plus simple du monde

La solution pour avoir un avatar aléatoire super simple, et super léger pour le serveur, est tellement simple qu'on se demande pourquoi personne ne la choisit : il suffit de renommer ses images. Ou plus exactement de les numéroter. Démonstration.

L'avatar aléatoire aux fichiers à noms « normaux »

L'algorithme de cet avatar est le suivant :

— Lister tous les fichiers du répertoire où il y a les images à afficher.
— Compter le nombre d'items de la liste.
— Choisir un nombre aléatoire, et récupérer le nom du fichier correspondant.
— Afficher le fichier choisi.

Et encore, c'est un cas simple : je pars du principe que toutes les images dont on a besoin sont sagement rangées dans un même dossier, où il n'y a que des images et que celles que l'on veut afficher.
De plus, il suffit qu'il y ait un caractère spécial un peu merdique, un fichier parasite qui n'a rien à faire dans le dossier, et hop ! plus rien ne fonctionne correctement.
En outre, la recherche des noms de fichiers est un processus lent (il faut faire un accès disque).

L'avantage de cette solution est qu'elle est extrêmement simple à faire fonctionner, une fois que le script est fait : on uploade le script, on uploade les fichiers, ça marche. Si on veut changer les images affichées, on change les images et ça marche tout seul, une fois de plus, et quel que soit le format de l'image.

Solution à images nommées

Ici, toutes nos images que l'on veut afficher s'appellent avatar-1.jpg à avatar-n.jpg, où n est le nombre d'images.

Dans ce cas, l'algorithme devient le suivant :

— Choisir un nombre i entre 1 et n.
— Afficher l'image avatar-i.jpg.

Simple, efficace.

De plus, c'est totalement insensible aux autres fichiers qui pourraient traîner dans le répertoire.
L'inconvénient est qu'il faut renommer ses fichiers, et changer le nombre n dans le script à chaque fois qu'on ajoute ou enlève des images à notre avatar.

Afficher l'image choisie

Là encore, on voit beaucoup d'horreurs.
La technique la plus répandue consiste à dire que notre fichier PHP renvoie une image (grâce aux headers()), puis à charger l'image dans le fichier pour l'afficher.

La solution consiste donc à dire au navigateur : « L'image que tu veux afficher, elle se trouve à cette adresse. »
Est-ce qu'il existe une fonction qui nous permet de faire ça ?
Oui, toujours notre fameuse fonction headers() !

... et du fond des cieux vint le Script

Maintenant, vous devez être capables de faire votre avatar aléatoire en trois lignes de code, en tout et pour tout. Voici la solution (ici avec 21 images) :

<?php
	header('Location: avatar-'.mt_rand(1,21).'.jpg');
?>

Le fichier .php ne contient absolument rien d'autre.

Notez que l'on peut encore réduire ce script à une seule ligne :

<?php header('Location: avatar-'.mt_rand(1,21).'.jpg'); ?>
Image utilisateur

L'image ci-contre fonctionne exactement sous ce principe. Le script PHP est à l'adresse suivante :
http://kisai.info/avatar/avatar_renard.php
Cliquez sur le lien, ou copiez-collez-le dans une autre fenêtre, et vous verrez dans la barre d'URL l'adresse se muer en la véritable adresse de l'image, tandis qu'un superbe renard s'affichera dans votre navigateur : tout fonctionne.

Ce sont des variables utilisées une seule fois, on peut donc les remplacer directement par leur valeur.
Le concept de « variable utilisée une seule fois pour rendre le code plus lisible » peut se comprendre sur un projet de plusieurs centaines de lignes, mais là… non.

Avantages de cette méthode

Bien, et si on compliquait un peu tout ça ?


Pourquoi ce tuto ? L'avatar semi-aléatoire et le cache

L'avatar semi-aléatoire et le cache

Un avatar aléatoire et un serveur qui dort : renommer ses fichiers Deux avatars en un

D'accord, je vois le concept. Mais si je veux faire quelque chose de plus compliqué, avec un traitement sur l'image ?

L'idée de base est de faire le traitement à chaque fois. Sauf que qui dit « traitement », dit en général « librairie GD », donc lourd… C'est là qu'intervient le système de cache !

L'avatar en deux (ou plusieurs) parties

Image utilisateur

Imaginons que j'aie toute une collection de charmantes demoiselles, dont vous avez un exemple sur votre gauche, et que je veuille en faire mon avatar.
Rien de plus simple, je prends la technique indiquée au-dessus.

Image utilisateur

Sauf que… je veux aussi que mon pseudo apparaisse avec une police classe, en gros, en dessous de mon avatar. Très exactement de la façon dont vous pouvez le voir à droite. Eh bien là, ma méthode ne marche plus !
Il va falloir combiner les deux images, mettre la demoiselle au-dessus du pseudo. Problème : l'image de la demoiselle est aléatoire… Il va donc falloir le faire pour chaque demoiselle. Tout ça sent l'utilisation de PHP GD à plein nez, donc plein de calculs et de difficultés pour votre pauvre serveur.

Combiner les deux images

Mes images de demoiselles font 150 x 150 pixels, le pseudo 150 x 50 pixels, le tout pour une image finale de 150 x 200 pixels.
J'ai 72 demoiselles différentes, dans les fichiers haut-1.png à haut-72.png ; et mon pseudo est dans le fichier bas.png.

Si vous connaissez un minimum PHP GD, ça ne pose aucun problème. La variable $haut va nous servir un peu plus loin, c'est sa raison d'être.
Le code qui permet de combiner les deux images ressemble donc à ceci :

<?php
// Tirage de l'image aléatoire
$haut = mt_rand(1, 72);

// L'image finale
$iFinale = imagecreatetruecolor(150,200);

// Récupération des images sources
$iHaut = imagecreatefrompng('haut-'.$haut.'.png');
$iBas = imagecreatefrompng('bas.png');

// Collage de l'image haute dans l'image finale
imagecopy($iFinale,
	  $iHaut,
	  0, 0,
	  0, 0,
	  150, 150);
// Collage de l'image basse dans l'image finale
imagecopy($iFinale,
	  $iBas,
	  0, 150,
	  0, 0,
	  150, 50);
?>

Il ne me reste plus qu'à afficher l'image $iFinale.

Sauf que… Il n'y a que moi que ça chagrine, de refaire les calculs à chaque fois ? Après tout, on n’a que 72 images possibles, or notre avatar va être affiché bien plus que 72 fois…

Cachez-moi ces images que je ne saurais voir

C'est exactement ça. Et là, deux solutions s'offrent à vous.

Récapitulons : j'ai toujours mes 72 images de demoiselles, mon pseudo, et j'ai à ma disposition un dossier intelligemment appelé « cache ».
De plus, PHP GD dispose d'une fonction qui permet d'enregistrer les images sur le disque dur. Que demande le peuple ?
Si on combine tout ça, on obtient un script PHP qui ressemble à ça :

<?php
// Tirage de l'image aléatoire
$haut = mt_rand(1, 72);
// Génération du nom de l'image pré-calculée :
$imgCache = 'cache/h'.$haut.'_b1.jpg';

// Est-ce que mon image existe déjà dans le cache ?
if (!file_exists($imgCache)) {

	// Visiblement, non. Alors on la génère :

	// L'image finale
	$iFinale = imagecreatetruecolor(150,200);

	// Récupération des images sources
	$iHaut = imagecreatefrompng('haut_'.$haut.'.png');
	$iBas = imagecreatefrompng('bas.png');

	// Collage de l'image haute dans l'image finale
	imagecopy($iFinale,
		  $iHaut,
		  0, 0,
		  0, 0,
		  150, 150);
	// Collage de l'image basse dans l'image finale
	imagecopy($iFinale,
		  $iBas,
		  0, 150,
		  0, 0,
		  150, 50);

	// Sauvegarde de l'image
	imagejpeg($iFinale, $imgCache, 90);
}
// Maintenant, on est sûrs que notre image existe, donc on peut l'afficher :
header('Location: '.$imgCache);
?>
Image utilisateur

Le résultat de ce script se trouve à votre droite.
Au bout d'un moment, on va se retrouver avec 72 images dans le dossier « cache », de h1_b1.jpg à h72_b1.jpg, il n'y aura alors plus rien à générer, et votre serveur pourra se la couler douce !
Et mieux, si on ajoute une image 73 (et qu'on pense bien à changer le nombre maximum d'images dans le script), elle va se rajouter toute seule à la liste.

Contre-indications

Hélas, la technique du cache ne fonctionne pas avec tous les types d'avatars aléatoires. En fait, je vois deux raisons principales qui empêchent d'utiliser cette technique :

L'avatar trop aléatoire

Votre avatar affiche des informations différentes à chaque fois (typiquement : l'heure, l'IP du visiteur…). Là, vous n'avez pas le choix, vous devez recalculer l'image à chaque fois.

L'avatar produit trop d'images

Image utilisateur

C'est un simple problème de multiplications. L'image que vous avez à votre droite est un de mes anciens avatars. Il est constitué de :

Un petit calcul m'indique donc que dans mon cache, il y avait au bout d'un moment :
3 x 13 x 64 = 2 496 images différentes.
Chaque image me prend environ 63 kio, j'ai donc environ 150 Mio de cache pour cet avatar.


Un avatar aléatoire et un serveur qui dort : renommer ses fichiers Deux avatars en un

Deux avatars en un

L'avatar semi-aléatoire et le cache Feinter les protections : faire croire que son image aléatoire est une vraie image

Image utilisateur

Cet avatar est très sympathique, et j'aimerais beaucoup pouvoir l'utiliser ailleurs, sur le Site du Zéro par exemple.

En effet, le site pour lequel j'ai conçu cet avatar accepte des avatars de 150 x 200 pixels, et le Site du Zéro est limité à 100 x 100 pixels. Zut. Voilà qui est bien gênant. Que faire ?

Tu peux redimensionner toutes les images de demoiselles (qui sont déjà carrées), et utiliser la première technique pour le Site du Zéro.

Certes, mais :

Évidemment, il faut utiliser un système de cache ici aussi, pas question de redimensionner « à la volée ». Je vous donne directement le script :

<?php
$id = mt_rand(1, 72);
$imgCache = 'cachesdz/'.$id.'.jpg';

if (!file_exists($imgCache)) {
	$iFinale = imagecreatetruecolor(100,100);	
	imagecopyresampled($iFinale,
			   imagecreatefrompng('haut_'.$id.'.png'),
			   0, 0,
			   0, 0,
			   100, 100,
			   150, 150);
	
	imagejpeg($iFinale, $imgCache, 90);
}
header('Location: '.$imgCache);
?>

Et voilà comment on obtient deux avatars différents avec un seul set d'images.
L'inconvénient de ce genre de méthodes est qu'il faut modifier les deux fichiers PHP à chaque fois qu'on change le nombre d'images.
Notez que l'on peut toujours contourner ce « problème » en déclarant le nombre d'images dans une constante dans un fichier de configuration (si j'ose dire), qui sera inclus dans tous les avatars.

Dans config.php :

<?php define('NB_DEMOISELLES', 72); ?>

Puis dans tous les scripts d'avatar :

<?php
require('config.php');
$id = mt_rand(1, NB_DEMOISELLES);
// Suite du code spécifique à chaque avatar...
?>

Ou tout autre système de non-redondance que vous pourriez imaginer. Toutefois, n'oubliez pas que la simplicité est le maître mot de ce tutoriel…


L'avatar semi-aléatoire et le cache Feinter les protections : faire croire que son image aléatoire est une vraie image

Feinter les protections : faire croire que son image aléatoire est une vraie image

Deux avatars en un

Donc vous avez votre script qui marche impec, testé sur votre serveur, et tout. Vous indiquez l'adresse de votre avatar dans votre forum préféré, et…

Pas de panique ! Il existe deux manières de contourner ce problème !

La manière « barbare » : le paramètre inutile

Elle s'appelle ainsi parce qu'elle n'est ni subtile, ni délicate, mais très simple très efficace. Disons, dans 9 cas sur 10.

Il s'agit de passer un paramètre inutile à votre script, et de lui donner la valeur .jpg, .png ou .gif. Au lieu d'indiquer :
exemple.com/avatar.php
comme adresse d'image, ce qui ne va pas fonctionner, on passe :
exemple.com/avatar.php?inutile=.jpg

Et là, tout le monde est content :

Le gros avantage de cette méthode, c'est qu'elle se fait en 10 secondes sans rien toucher sur votre serveur.

La manière « agent double » : le dossier déguisé en fichier

Elle s'appelle ainsi parce qu'elle fonctionne comme un agent double : le dossier se fait passer pour un fichier pour obtenir ce qu'il veut, et c'est très efficace.

Ici, on va se servir de cette propriété intéressante des serveurs web :

Citation : Les règles des serveurs web

Quand on donne l'adresse d'un dossier à un serveur web, il va automatiquement chercher le fichier index.php ou index.html qu'il y a dedans.

Et qu'est-ce qui m'empêche d'appeler mon dossier avatar.jpg ? Eh bien… rien !
On va devoir toucher un peu à la structure de notre avatar. Il faut :

Puis vous indiquez à votre site l'adresse suivante : exemple.com/avatar.jpg
Le site va voir une image, donc va être content et accepter votre avatar. Le serveur, lui, va regarder ce qu'est avatar.jpg et comme c'est un dossier, il va automatiquement appeler :
exemple.com/avatar.jpg/index.php
ce qui va renvoyer votre image.

L'avantage de cette solution, c'est qu'elle marche sur n'importe quel serveur ; l'inconvénient est qu'elle ne fonctionne plus, ou plus exactement qu'elle nécessite de sérieuses modifications du code, quand on veut faire plusieurs avatars à partir du même set d'images.

La manière « ninja » : le fichier .htaccess

Elle s'appelle ainsi parce qu'elle est subtile, discrète et très, très efficace. En fait, elle ne peut pas échouer.

La première étape, c'est de déclarer qu'on utilise un vrai fichier image, on indique comme adresse quelque chose du genre :
exemple.com/avatar.jpg

Sauf qu'on va dire à Apache que ce fichier avatar.jpg n'est pas une image, mais notre fichier avatar.php, et ce grâce aux directives htaccess.
Pour ce faire, il faut créer un fichier nommé .htaccess dans le même dossier que votre fichier PHP, qui contient les deux lignes :

RewriteEngine on
RewriteRule ^avatar\.jpg$ avatar.php [L]

En fait, on se sert du module de réécriture d'URL d'Apache (ligne 1), et on lui demande de réécrire avatar.jpg (ce que voit le client) en avatar.php (ce qui va être fait sur le serveur).
Je ne détaillerai pas ceci en profondeur, vous pouvez trouver les informations de base sur les fichiers .htaccess ici et trouver les informations sur la réécriture d'URL un peu partout sur Internet.

L'avantage de cette technique est qu'elle est imparable : le client, donc le système de protection, n'a aucun moyen de savoir que vous ne lui passez pas une « vraie » image.
Les inconvénients sont que la technique nécessite le ModRewrite activé sur le serveur Apache, et qu'il faut créer le .htaccess en plus.

Les cas pathologiques

Il existe quelques administrateurs paranoïaques, qui ont entendu parler des failles CSRF et qui ont mis en place des techniques un peu violentes pour s'en prémunir.
Nous allons voir ici deux de ces techniques, et ce qu'on peut faire face à de tels cas.

Le site télécharge l'image et ne se sert que de la version locale

Tout est dans le titre : quand vous donnez une URL, le site télécharge une copie de l'image, et la stocke sur son propre serveur. L'image que voient les visiteurs est celle stockée sur le serveur.

A priori c'est le cas :

Les signatures ne semblent pas affectées : je n'ai pas essayé personnellement mais, si j'ai bien compris, la « technique ninja » fonctionne.

Si quelqu'un a plus d'informations, merci de les partager dans les commentaires. De même, si quelqu'un connaît d'autres plates-formes ou sites connus qui fonctionnent de cette manière, signalez-le-moi que je puisse tenir cette liste à jour.

Le site vérifie qu'il n'y a pas de redirection

Et sa variante : le site enregistre l'URL sur laquelle on redirige au lieu de l'URL que l'on donne.
Or, tout le fonctionnement repose sur ces fameuses redirections, d'où : problème.

La parade fonctionne donc en deux étapes :

  1. On fournit une vraie image exemple.com/avatar.jpg au formulaire. Le site la vérifie, et enregistre l'URL telle quelle dans sa base, puisqu'il a vérifié qu'il s'agissait bien d'une vraie image.

  2. Une fois l'enregistrement effectué, on supprime notre vraie image exemple.com/avatar.jpg et on se sert de la « technique ninja » pour faire correspondre exemple.com/avatar.jpg à notre fichier .php.

Personnellement je n'ai jamais vu ce genre de cas ; si quelqu'un connaît des plates-formes / sites connus qui fonctionnent de cette manière, merci de me le signaler en commentaire, que je puisse en faire une liste ici.

Voilà, maintenant vous savez à peu près tout ce qu'il y a à savoir sur la création d'avatars aléatoires. En résumé :

Mais surtout, vous savez que si vous prenez la peine de nommer correctement vos fichiers, vous épargnez beaucoup de douleurs à votre serveur, et accessoirement simplifiez vos scripts.
Un peu de travail pour vous, beaucoup moins pour votre serveur.

En cadeau pour finir, et parce que vous êtes de bons programmeurs, donc de vraies feignasses qui refusent de nommer plein de fichiers à la main, dans l'ordre et sans se tromper, je vous offre ce logiciel qui le fait pour vous : AntRenamer.
Un petit logiciel bien pratique qui permet de numéroter une liste de fichiers, mais aussi de les renommer de plein de manières différentes.

Si vous avez des questions, commentaires, réflexions, etc., n'hésitez pas, les commentaires sont là pour ça !


Deux avatars en un