Il y a plusieurs méthodes possibles pour raccourcir une URL. Vous pouvez vous amuser à créer une algorithme de compression de chaine, mais il y a plus simple. Sur une base plus ou moins aléatoire, un nombre quelconque, vous allez récupérer une chaine de caractères.

L'idée est d'encoder le nombre sur une base de 62 caractères (de "a" à "Z" et de "0" à "9"), soit comme en hexadécimal, mais avec les majuscules en plus. On pourrait rajouter un caractère ou l'autre, mais j'ai choisi de rester dans les caractères alphanumériques.

Pourquoi ne pas encoder en Base64

Base64 est conçu pour gérer tout type de caractères, du coup l'encodage prend plus d'espace et ne nous est d'aucune utilité.

Méthodologie

C'est bien de pouvoir obtenir une chaine sur base d'un nombre, mais comment on l'utilise. Trois options s'offrent à vous.

La première consisterait à récupérer l'ID de votre URL enregistrée en base de données, et de le convertir en Base62. Ca permet d'avoir une chaine unique à chaque enregistrement, mais ne rend pas la génération de la chaine aléatoire.

Une autre méthode consiste à générer un nombre sur une base connue. Par exemple un Timestamp accompagné d'un nombre aléatoire, en vous assurant que le nombre soit bel et bien unique. Avec cette méthode, il est possible que votre chaine raccourcie ne soit pas aussi courte qu'elle pourrait l'être.

La dernière méthode consiste à générer une chaine aléatoirement, et de vérifier ensuite qu'elle n'a pas déjà été utilisée. Cette méthode peut nuire aux performances du serveur si plusieurs fois de suite la chaine a déjà été utilisée.

Fonctions de compression de nombre

Voici la fonction toute simple d'encodage (et décodage) en Base62.

Base62 en PHP

function base62e($n, $chr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ) {
	$n = intval($n);
	$base = strlen($chr);
	$chars = "";
	while ($n > 0) {
		$mod = $n % $base;
		$n = intval($n / $base);
		$chars = $chr[$mod] . $chars;
	}
	return $chars;
}

function base62d($chars, $chr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
	$base = strlen($chr);
	$nb = strlen($chars);
	$puis = $nb -1;
	$sum = 0;
	for($i = 0; $i < $nb; $i++) {
		$char = $chars[$i];
		$val = strpos($chr, $char);
		$sum += $val * pow($base, $puis--);
	}
	return $sum;
}

Base62 en Python


chr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

def base62e(n):
	n = int(n)
	base = len(chr)
	chars = ""
	while n > 0:
		mod = n % base
		n = n / base
		chars = chr[mod] + chars
	return chars

def base62d(chars):
	chars = str(chars)
	base = len(chr)
	puis = len(chars) - 1
	sum = 0
	for c in chars:
		val = chr.find(c)
		sum += val * (base ** puis)
		puis -= 1
	return sum

Remarques

J'ai fait ça vite fait, il existe peut-être des fonctions existantes permettant d'arriver au même résultat, je n'en sais rien mais je serais ravi de l'apprendre. De même pour la méthodologie, si vous avez d'autres pistes ou idées, faites-m'en part !