Vous avez à traiter le format Base64 ? Alors ce site est parfait pour vous ! Utilisez notre outil en ligne super pratique pour encoder ou décoder vos données.

Encodage Base64 en Perl : un guide complet

Vous avez des données qui doivent survivre à un canal qui ne les aime pas. Un blob binaire qui doit s'asseoir dans un champ JSON. Une image qui doit vivre à l'intérieur d'une balise HTML. Un certificat qui a sa place dans un fichier de configuration. Un token qui va voyager à travers des URL, des en-têtes et des chaînes de requête. Voilà le quotidien de l'encodage Base64 : il réécrit tous les trois octets de données brutes en quatre caractères tirés d'un alphabet de 64 lettres, avec un ou deux signes = pour finir la traîne, si bien que le résultat est du texte brut que n'importe quoi peut porter, typiquement environ 33 pour cent plus long que le point de départ. La page d'accueil de ce site détaille le format en profondeur, donc cet article se concentre sur ce que Perl vous donne, ce qu'il décide tranquillement à votre place, et où sont les pièges.

Les bonnes nouvelles d'abord : encode_base64 vit dans le core de Perl depuis 2002, il est implémenté en C, et il est confortablement rapide. La partie intéressante, c'est que la fonction a des opinions. Elle enveloppe sa sortie à 76 caractères, elle ajoute un retour à la ligne final, et elle refuse d'encoder des caractères Unicode que vous n'avez pas d'abord convertis en octets : au-dessus de la plage Latin-1, elle meurt carrément, et en dessous de cette ligne, elle suppose silencieusement des octets Latin-1. Ce guide parcourt toutes les saveurs de Base64 qu'un développeur Perl produit vraiment : le one-liner, le corps de courrier enveloppé en MIME, la clé enveloppée en PEM, le token sûr pour les URL, et la version en streaming pour les fichiers trop gros pour tenir en mémoire.

Une fonction, un retour à la ligne caché

L'API entière, exactement comme la documentation moderne la présente :

encode_base64( $bytes )
encode_base64( $bytes, $eol )

Relisez encore une fois. Deux arguments, dont un optionnel, une valeur de retour, pas de drapeaux. Le second argument optionnel est la séquence de fin de ligne, et sa valeur par défaut est un simple retour à la ligne, ce qui veut dire que l'appel de Perl le plus innocent en apparence produit une sortie enveloppée et terminée par un retour à la ligne :

use MIME::Base64 qw(encode_base64);
my $wrapped = encode_base64("Aladdin:open sesame");
print length($wrapped), "\n";  # 29 : les 28 caractères plus un retour à la ligne
my $single = encode_base64("Aladdin:open sesame", "");
print length($single), "\n";   # 28 : passez une chaîne vide pour ne pas envelopper

La taille de sortie suit un motif fixe que vous pouvez prédire avant d'appeler :

Octets d'entrée Caractères de sortie Padding
0 0 aucun
1 4 deux =
2 4 un =
3 4 aucun
100,000 133,336 aucun, sur une seule ligne
3,000,000 4,000,000 aucun

Le motif, c'est quatre caractères pour chaque groupe complet de trois octets, plus un groupe final partiel complété avec un ou deux signes =. Une conséquence à connaître : un octet et trois octets produisent tous les deux quatre caractères, donc la longueur encodée cache la taille exacte de l'entrée. Et si vous avez besoin de la taille sans faire le travail, le module a une fonction de longueur depuis la 3.10 en 2010. Elle n'est simplement pas exportée par défaut, donc vous l'appellez par son nom de paquet :

use MIME::Base64 ();
my $with_wrap   = MIME::Base64::encoded_base64_length($bytes);        # lignes de 76 caractères, eol par défaut
my $single_line = MIME::Base64::encoded_base64_length($bytes, "");    # pas d'enveloppe
my $mime_body   = MIME::Base64::encoded_base64_length($bytes, "\r\n");

Il y a une dernière règle à mémoriser, parce que c'est la seule façon dont l'encodeur crie jamais : si la chaîne que vous lui donnez contient des caractères avec un code au-dessus de 255, encode_base64 meurt avec Wide character in subroutine entry. En dessous de cette ligne, l'échec est plus silencieux : les caractères jusqu'à 255 sont rétrogradés silencieusement en leurs octets Latin-1, donc une chaîne de caractères accentuée qui a sauté la conversion s'encode en Latin-1 au lieu de UTF-8, et personne ne vous le dit. L'encodage Base64 n'est défini que pour les caractères mono-octet, et Perl 5.8 et mieux permettent des caractères étendus dans les chaînes, donc la conversion est une décision que vous prenez exprès, avec Encode, dans la section qui suit immédiatement.

Texte ou octets ? L'étape que la fonction ne peut pas faire

Les chaînes Perl portent un drapeau discret qui dit si elles contiennent des caractères ou des octets, et le Base64 vit du côté octets de cette ligne. Si votre texte est une chaîne de caractères, et c'est le moment où il vient d'un parseur JSON, d'un gabarit, ou d'un littéral avec des lettres accentuées dans un fichier source UTF-8, l'encodeur refuse de deviner quels octets vous vouliez pour les caractères au-dessus de la plage Latin-1, et il vous le dit ; en dessous de la plage, il suppose Latin-1 en silence. La correction est la même dans les deux cas, et c'est une fonction core du module Encode :

use MIME::Base64 qw(encode_base64);
use Encode qw(encode);
my $chars = "H\x{eb}llo W\x{f6}rld";  # une chaîne de caractères
my $utf8  = encode("UTF-8", $chars);  # maintenant : des octets
my $b64   = encode_base64($utf8, "");
print $b64, "\n";  # SMOrbGxvIFfDtnJsZA==

Cet appel encode est toute la danse : choisissez la représentation en octets, et UTF-8 pour tout ce qui est moderne, convertissez les caractères en ces octets, et seulement alors remettez les octets à l'encodeur. Pour le texte occidental legacy arrivé en Windows 1252, la conversion est la même fonction avec un autre nom, encode("Windows-1252", $legacy), qui vous rend la forme mono-octet d'origine. Le module Encode est core, donc tout ça ne coûte rien.

Maintenant le piège. Si les octets que vous avez sont déjà du UTF-8 et que vous les passez à nouveau dans encode("UTF-8", ...), en pensant les rendre UTF-8, vous n'obtenez pas une copie : vous obtenez un double encodage, où chaque caractère accentué gonfle en deux caractères de son propre chef. Le symptôme classique, c'est un texte qui se lisait Hëllo et qui se lit désormais Hëllo, et tous les décodeurs de l'internet le décoderont fidèlement pour vous :

use Encode qw(encode decode);
my $right = encode("UTF-8", "H\x{eb}llo");
my $wrong = encode("UTF-8", $right);  # re-encoder les octets comme des caractères
print decode("UTF-8", $right), "\n";  # Hëllo
print decode("UTF-8", $wrong), "\n";  # Hëllo

La règle de pouce qui l'empêche : les octets s'encode exactement une fois, et utf8::is_utf8() vous montre de quel côté de la ligne est une chaîne. Si le drapeau est posé, vous tenez des caractères et l'appel encode() est le bon mouvement ; s'il ne l'est pas, vous tenez des octets et vous êtes prêt pour le Base64.

Les retours à la ligne : trois dialectes, une règle

Comme la sortie par défaut est enveloppée et terminée par un retour à la ligne, la première décision de tout travail d'encodage est une question de destination : où vivra cette chaîne ? Le fait unificateur, c'est que les décodeurs ignorent les retours à la ligne tout court : la RFC 2045 dit au logiciel de décodage d'ignorer tous les retours à la ligne et les caractères hors alphabet, donc l'enveloppe est une politesse envers les outils ligne par ligne et les humains, pas une différence de sens. Les trois réponses en pratique :

Pas de retours à la ligne. La sortie de la fonction avec l'enveloppe désactivée, exactement une ligne. C'est ce qu'il vous faut pour les URL, les payloads JSON, les en-têtes, les valeurs de base de données, et tout le reste où un retour à la ligne serait un bogue. C'est aussi ce que la plupart des gens veulent dire quand ils demandent juste le Base64 :

my $single = encode_base64($bytes, "");

MIME : 76 caractères plus CRLF. La convention du courrier de la RFC 2045 : les lignes encodées ne doivent pas dépasser 76 caractères, et le monde MIME parle CRLF. Celui-ci est le propre travail du module, fait avec le second argument :

my $mime_body = encode_base64($bytes, "\r\n");

PEM : 64 caractères plus LF. Les clés et les certificats utilisent l'ancienne convention avec des lignes plus courtes de 64 caractères, et le module ne peut pas produire cette largeur tout seul, donc un aide de quatre lignes comble le trou :

sub wrap_lines {
  my ($text, $width) = @_;
  return join "\n", $text =~ /(.{1,$width})/g;
}
my $pem = "-----BEGIN CERTIFICATE-----\n"
        . wrap_lines(encode_base64($der, ""), 64) . "\n"
        . "-----END CERTIFICATE-----\n";

Le même aide sert les autres dialectes de 64 caractères aussi - l'encodage textuel PKIX de la RFC 7468 et l'armure OpenPGP, dont les lignes de données font 64 caractères de large et dont la ligne de somme de contrôle CRC24 finale est ajoutée par GnuPG plutôt que par vous. Un point de vigilance s'applique à tous : encode_base64 ajoute la fin de ligne tout à la fin du résultat, même quand la dernière ligne remplit sa largeur exactement. Si un consommateur en aval se prend au piège sur cette ligne vide finale, un appel rtrim sur le résultat règle ça.

Base64 sûr pour les URL : l'alphabet - et _

L'alphabet standard inclut + et /, et les deux sont des ennuis hors d'un fichier texte : un + dans une chaîne de requête encodée en formulaire devient une espace avant que votre application ne le voie, et / est un séparateur de chemin dans les URL. Les noms de fichiers et les tokens ont leurs propres doléances. La RFC 4648, section 5, règle ça avec l'alphabet sûr pour les URL et les noms de fichiers, où + devient -, / devient _, et le padding = final est généralement retiré. La RFC insiste : cet encodage ne doit pas être considéré comme identique à l'encodage base64, donc traitez-le comme un format distinct, couramment appelé base64url. Perl le produit en un seul appel depuis la version 3.11 en 2010 :

use MIME::Base64 qw(encode_base64url);
my $seg = encode_base64url("sunset-42");
print $seg, "\n";  # c3Vuc2V0LTQy: pas de padding, pas de retour à la ligne

Cet appel unique fait les trois changements : l'échange d'alphabet, pas de padding, pas de retours à la ligne. Si vous tenez déjà du Base64 standard et que la destination veut le dialecte sûr pour les URL, deux opérations sur chaînes le convertissent sur place :

sub to_urlsafe {
  my ($b64) = @_;
  $b64 =~ tr{+/}{-_};
  return $b64 =~ s/=+\z//r;
}
my $seg = to_urlsafe(encode_base64($bytes, ""));

Quand l'utiliser : les parties de JSON Web Token, les paramètres state et nonce d'OAuth, les IDs d'API que vous mettez dans des chemins d'URL, et les clés opaques qui doivent survivre à une barre d'adresse ou à un nom de fichier, où le Data::UUID::Base64URLSafe de CPAN existe exactement pour ça. Quand ne pas l'utiliser : les corps de courrier, l'armure PEM, et n'importe où un consommateur d'alphabet standard est de l'autre bout, parce que - et _ ne sont pas dans leur vocabulaire. Et ne mélangez pas les deux alphabets en silence : une valeur encodée en sûr pour les URL doit se décoder en sûr pour les URL, partout, toujours. Sur les Perls antérieurs à 3.11, le module autonome MIME::Base64::URLSafe de 2006, un port du codec urlsafe de Python, fournit urlsafe_b64encode ; sur tout ce qui est moderne, la fonction intégrée est le bon outil.

Construire un JWT : chaque partie à la main

Les JSON Web Token sont le consommateur vedette du Base64 dans les API modernes, et ils utilisent le dialecte sûr pour les URL sans padding de la section ci-dessus. Selon la RFC 7515, un JWT compact, ce sont trois parties base64url séparées par des points : l'en-tête protégé, le payload, et la signature. Construire un token à la main est un agréable moyen de voir toutes les pièces en mouvement :

use MIME::Base64 qw(encode_base64url);
use JSON::PP qw(encode_json);
use Digest::SHA qw(hmac_sha256);
my $secret  = "correct-horse-battery-staple";
my $head    = encode_base64url(encode_json({ alg => "HS256", typ => "JWT" }));
my $claims  = encode_base64url(encode_json({ sub => "homer", role => "admin" }));
my $sig     = encode_base64url(hmac_sha256("$head.$claims", $secret));
my $jwt     = "$head.$claims.$sig";
print $jwt, "\n";  # un token HS256 compact ; l'ordre des clés dans chaque partie JSON varie d'une exécution à l'autre

Trois détails qui méritent d'être remarqués. D'abord, encode_json du module core JSON::PP émet des octets UTF-8 compacts sans espaces, ce qui est exactement ce que les specs JOSE veulent dans un token. Deuxièmement, le payload est lisible par n'importe qui, et c'est voulu : un JWT est un billet signé, pas un secret, donc ne mettez jamais de valeurs confidentielles dans les claims. Troisièmement, la signature est l'encodage base64url d'octets HMAC bruts, c'est pourquoi hmac_sha256 part droit dans l'encodeur sans aucun formatage hexadécimal.

En production, vous ne fabriquez pas la signature à la main. Le module CPAN Crypt::JWT, qui se construit sur CryptX, implémente JWS et JWE avec toute la série d'algorithmes :

use Crypt::JWT qw(encode_jwt);
my $jwt = encode_jwt(
  payload => { sub => "homer", role => "admin" },
  alg     => "HS256",
  key     => $secret,
);

Et côté réception, fixez l'algorithme avec accepted_alg pour qu'un attaquant ne puisse pas basculer le token vers une variante plus faible : decode_jwt(token => $jwt, key => $secret, accepted_alg => "HS256") vérifie la signature et croak en cas d'échec. La version faite main convient pour comprendre ; la bibliothèque convient pour l'argent.

HTTP : en-têtes d'authentification, data URIs et le handshake WebSocket

L'en-tête Authorization: Basic est le cas d'usage live le plus ancien : le nom d'utilisateur et le mot de passe joints par un deux-points, encodés en une seule ligne, précédés du mot du schéma. Le second argument chaîne vide porte son poids ici, parce qu'un retour à la ligne final à l'intérieur d'un champ d'en-tête est un bogue :

use MIME::Base64 qw(encode_base64);
my $user = "alice";
my $pass = "s3cr3t";
my $header = "Basic " . encode_base64("$user:$pass", "");
print $header, "\n";  # Basic YWxpY2U6czNjcjN0

Les data URIs de la RFC 2397 appliquent la même idée aux images : le payload est directement dans l'URL, donc aucune seconde requête n'est nécessaire pour le récupérer. Les médias binaires utilisent le drapeau ;base64, donc le payload est exactement ce que encode_base64 produit avec l'enveloppe désactivée :

my $uri = "data:" . $mime_type . ";base64," . encode_base64($bytes, "");

Les compromis sont réels, cependant. Le payload encodé est environ 33 pour cent plus gros que le fichier, ce qui rend le document HTML lui-même plus gros. Les navigateurs ne mettent pas en cache une data URI comme ils mettent en cache une URL de fichier - il n'y a pas de récupération séparée à mettre en cache, donc chaque consultation de page renvoie les octets à nouveau en partie du document, et la RFC elle-même dit que les data URIs ne sont utiles que pour des valeurs courtes. Utilisez-les pour les avatars, les icônes, et les petits graphismes en ligne ; utilisez de vrais fichiers pour tout le reste. Il y a un troisième coin HTTP qui utilise le Base64 discrètement : le handshake WebSocket de la RFC 6455, où le client envoie un en-tête Sec-WebSocket-Key qui est le Base64 de seize octets aléatoires. Des frameworks comme Mojolicious le font pour vous, mais si vous le voyez un jour sur le fil, vous savez maintenant ce que c'est :

use MIME::Base64 qw(encode_base64);
my $key = encode_base64(pack("C16", map { int(rand 256) } 1 .. 16), "");
print length($key), "\n";  # 24: seize octets aléatoires, complétés au groupe de quatre caractères

Les fichiers : avalage, morceaux de 57 octets et la CLI

Le travail d'encodage le plus direct : un fichier devient du texte. Les chaînes Perl sont des octets, donc il n'y a pas de mode binaire à chercher - le calque :raw est tout. Ouvrir en raw, lire, encoder, écrire :

use MIME::Base64 qw(encode_base64);
open my $in, "<:raw", $ARGV[0] or die $!;
local $/;
my $bytes = <$in>;
close $in;
open my $out, ">:raw", $ARGV[1] or die $!;
print {$out} encode_base64($bytes);
close $out;

Les calques :raw comptent. Sans eux, Perl essaierait d'interpréter les octets comme du texte de la plateforme en entrant et en sortant, et sur un système avec un encodage par défaut différent, c'est précisément la corruption que vous ne voyez pas tant que le fichier n'est ouvert quelque part ailleurs. Et rappelez-vous la note de taille quand vous planifiez le stockage : une image de 500 Ko devient un fichier texte de 670 Ko, et une vidéo de 1 Go devient 1,33 Go.

Pour les fichiers trop gros pour tenir en mémoire, la documentation du module lui-même vous donne la règle : encoder par morceaux qui sont des multiples de 57 octets, parce que 57 octets de données remplissent exactement une ligne de 76 caractères, 76 étant 57 fois 4 divisé par 3. Coupez sur cette frontière et vous n'obtenez jamais de padding au milieu du flux :

use MIME::Base64 qw(encode_base64);
open my $in, "<:raw", $ARGV[0] or die $!;
while (read($in, my $buf, 57 * 10)) {
  print encode_base64($buf);
}
close $in;

Chaque morceau atterrit exactement sur des frontières de ligne, le dernier, éventuellement court, porte le padding final, et le résultat est identique à l'octet près à celui d'avaler le fichier entier et de l'encoder d'un coup, avec juste une empreinte mémoire constante. Et quand vous n'avez pas besoin d'un script du tout, le one-liner suffit, avec -0777 qui avale l'entrée et l'argument chaîne vide qui garde la sortie sur une ligne :

perl -MMIME::Base64 -0777 -ne 'print encode_base64($_, "")' < file > file.b64

Le courrier : corps MIME et pièces jointes

Le courrier est là que le Base64 a gagné son nom. La norme MIME dit que les données qui ne peuvent pas voyager en toute sécurité comme texte brut doivent être envoyées avec Content-Transfer-Encoding: base64, en lignes de 76 caractères maximum. Si vous construisez du courrier avec MIME::Lite, tout ça tient en un argument, et le module fait l'encodage, l'enveloppe, et l'en-tête pour vous :

use MIME::Lite;
my $mime = MIME::Lite->new(
  From    => 'me@example.com',
  To      => 'you@example.com',
  Subject => 'A file',
  Type    => 'text/plain',
  Data    => 'The body text.',
);
$mime->attach(
  Type     => 'application/octet-stream',
  Data     => $bytes,
  Encoding => 'base64',
  Filename => 'hello.txt',
);

L'argument Encoding est le déclencheur : MIME::Lite encode la pièce jointe en Base64 sur des lignes de 76 caractères (avec le simple retour à la ligne par défaut du module ; c'est le transport du courrier qui les transforme en CRLF) et tamponne la partie avec l'en-tête Content-Transfer-Encoding correspondant. Email::MIME prend la même position et encode en Base64 n'importe quelle pièce jointe que vous lui passez comme chaîne de données brutes (sa doc : « toutes les parties créées de cette façon sont encodées en base64, par précaution »). Si vous assemblez un message MIME brut à la main, l'équivalent, ce sont les deux lignes de la section enveloppes, encode_base64($bytes, "\r\n") plus la ligne d'en-tête, et c'est toute l'histoire côté protocole.

Bases de données, configuration et variables d'environnement

Les bases de données : les données binaires voyagent souvent dans une colonne TEXT en Base64, parce que la colonne ne peut pas promettre de laisser passer des octets arbitraires intacts. Stockez la forme sur une seule ligne, jamais la forme enveloppée, sinon votre prochain SELECT renverra une chaîne avec des retours à la ligne au milieu de la valeur :

use MIME::Base64 qw(encode_base64);
# $dbh est un handle DBI déjà connecté
my $stmt = $dbh->prepare(q{UPDATE photos SET data = ? WHERE id = ?});
$stmt->execute(encode_base64($bytes, ""), 42);

Les fichiers de configuration ont la même forme : un document JSON où le champ binaire ou secret est une chaîne Base64 sur une seule ligne, c'est exactement pour ça que le second argument existe :

use JSON::PP qw(encode_json);
my $config = {
  api_key  => encode_base64($key_bytes, ""),
  logo_png => encode_base64($png_bytes, ""),
};
open my $fh, ">:raw", "app.json" or die $!;
print {$fh} encode_json($config);
close $fh;

Les variables d'environnement méritent un mot d'avertissement. Le Base64 va bien pour de petits tokens dans l'environnement, mais la forme encodée est 33 pour cent plus grosse que l'original, et le système d'exploitation plafonne chaque argument. Sur Linux, la limite est de 128 Ko par chaîne, imposée par execve, et un gros blob dans une variable d'environnement n'échoue pas poliment : le processus enfant meurt avec une erreur cryptique le moment où il est créé. Petites valeurs dans l'environnement, grosses valeurs dans un fichier ou une base de données.

Performance : c'est du C qui fait le travail, pas du Perl

Le module core est implémenté en C, et ce C descend de code écrit pour metamail en 1991, ce qui est un fait amusant tant que vous ne remarquez pas la conséquence : l'encodeur a eu trois décennies d'ajustements. Sur une machine moderne, il traite les données au rythme des gigaoctets par seconde, c'est plus rapide que le disque ou le réseau qu'il alimente d'habitude, donc le Base64 lui-même est presque jamais le goulot d'étranglement. C'est l'E/S.

Pour le système curieux sans compilateur C, la jumelle purement Perl MIME::Base64::Perl sur CPAN fournit la même interface de base, quelques fois plus lente mais toujours confortable pour les charges de travail ordinaires. Et deux habitudes gardent les gros travaux prévisibles : streamer par morceaux de 57 octets au lieu d'avaler, et dimensionner vos buffers avec encoded_base64_length avant d'allouer, ce qui vous épargne à la fois la devinette et la réallocation.

Les pièges, classés par coût de l'après-midi

Les pièges, dans l'ordre où ils mordent, à peu près :

Piège Ce qui se passe Correction
Oublier le second argument la sortie arrive enveloppée à 76 caractères avec un retour à la ligne final, et votre URL, votre champ JSON, ou votre en-tête casse au milieu de la valeur passez "" pour une sortie sur une ligne, et gardez l'enveloppe pour les destinations qui l'attendent
Envelopper à la mauvaise largeur un consommateur PEM attend des lignes de 64 caractères et en reçoit de 76, ou un corps MIME dépasse la limite de 76 caractères alignez la largeur sur le dialecte : "" pour aucune, "\r\n" pour MIME, un aide pour PEM
Le croak de caractère large une chaîne de caractères avec des codes au-dessus de 255 meurt avec Wide character in subroutine entry au milieu d'une requête passez les caractères dans Encode d'abord, nommé exprès, avant l'appel encode_base64
Double encodage re-encoder des octets déjà UTF-8 à travers encode("UTF-8", ...) transforme Hëllo en Hëllo les octets s'encode exactement une fois ; vérifiez utf8::is_utf8() en cas de doute
Mélanger les alphabets en silence une valeur encodée avec - et _ atteint un décodeur d'alphabet standard et revient en n'importe quoi un dialecte par valeur, de bout en bout : choisissez base64url ou standard à la frontière
La fin de ligne finale encode_base64 ajoute l'eol même quand la dernière ligne est exactement pleine, et un consommateur strict voit une ligne vide chomp ou rtrim le résultat quand le consommateur est pointilleux
Des valeurs enveloppées dans une base de données des retours à la ligne atterrissent dans une colonne TEXT et le prochain SELECT renvoie un token cassé stockez la forme sur une seule ligne ; enveloppez seulement à la destination
Variables d'environnement avec de gros blobs la croissance de 33 pour cent plus la limite par argument du système d'exploitation tue le processus enfant à la création avec une erreur cryptique petites valeurs dans l'environnement, grosses valeurs dans un fichier ou une base de données
Penser que le Base64 est une protection le format ne cache rien, et le registre public documente des incidents réels où un utilisateur a collé un échange IMAP et a révélé un mot de passe par accident traitez la sortie comme confidentielle dès le moment où elle est produite, et gardez-la hors des logs
Planifier sans la note de taille une image de 500 Ko devient 670 Ko de texte, et la limite de stockage ou de payload que vous n'avez pas vérifiée mord budgetisez 4/3 de la taille d'origine avant de vous engager

Une histoire racontée par l'encodeur

L'encodeur Base64 de Perl a une carrière qui vaut la peine d'une minute, et elle commence dans la première boîte à outils web :

  • Né dans libwww perl. L'encodeur a vu le jour sous le nom de LWP::Base64, écrit par Martijn Koster et Joerg Reichelt, que Gisle Aas a absorbé dans libwww perl en tant que MIME::Base64 ; il a fait son entrée en distribution CPAN à part en avril 1997, version 2.00, avec une entrée de changelog qui dit simplement qu'il est basé sur libwww perl 5.08.
  • L'ère de la vitesse. La version 2.07 en 1998 a livré une implémentation C plus rapide et plus intelligente du décodeur, environ 25 pour cent plus vive sur les machines Linux alors modernes, et l'ajustement a continué pendant une décennie.
  • L'ère de l'Unicode. Perl 5.8 en 2002 a amené les caractères avec des codes au-dessus de 255 dans les chaînes ordinaires, et le module a répondu par étapes : la 2.12 en 2001 rétrogradait les chaînes UTF-8 avant l'encodage, et le croak moderne Wide character in subroutine entry est la façon de l'encodeur de tenir cette promesse. La synchronisation 2.13 avec le core la même année a apporté le support EBCDIC, un rappel que le Base64 dans Perl tourne encore sur mainframes.
  • L'ère de la ligne de commande. Les sorties de la 2.14 en 2003 à la 3.05 en 2004 incluaient une vraie commande encode-base64, avec ses jumelles décodage et quoted-printable ; la 3.06 en 2005 a déplacé les scripts dans une distribution séparée MIME Base64 Scripts.
  • L'arrivée du sûr pour les URL. La RFC 4648 a standardisé l'alphabet sûr pour les URL en 2006, un module autonome MIME::Base64::URLSafe est apparu la même année, et le module core a rattrapé le retard en 3.11 en 2010 avec encode_base64url en un seul appel.
  • La ligne moderne. La version 3.16 en 2020 a reconstruit l'emballage et a relevé le plancher à Perl 5.6 ; les Perls core actuels livrent la série 3.16, et le module est maintenu au sein de la distribution core, ce qui est à peu près le domicile le plus sûr qu'un module core puisse avoir.

Faits insolites, version Perl

Les trucs qui rendent cette histoire bonne :

  • L'exemple de la POD est une formule magique. Depuis 1997, la documentation du module elle-même encode Aladdin:open sesame, si bien que la chaîne QWxhZGRpbjpvcGVuIHNlc2FtZQ== est la carte de visite du module depuis près de trente ans.
  • La fin de ligne par défaut est celle que vous n'attendiez probablement pas. C'est un simple \n, pas le CRLF que le MIME parle. La convention propre de la RFC a besoin du second argument, et le module est livré avec la valeur par défaut du programmateur, pas celle du protocole.
  • La chaîne vide a une règle spéciale. Encodez rien et vous n'obtenez rien, pas de retour à la ligne ajouté : la seule exception documentée à la règle de l'eol final, et la raison pour laquelle un fichier vide fait un aller-retour propre.
  • Le cousin IMAP a une virgule. La variante des noms de boîte aux lettres de la RFC 3501 échange le / contre une virgule dans l'alphabet, donc une chaîne Base64 d'un serveur IMAP peut contenir une lettre que le décodeur standard traite comme du bruit.
  • La lignée de 1991 est réelle. L'implémentation C descend de metamail, le programme de courrier de Bellcore de 1991, trois ans avant la naissance de Perl 5, donc chaque appel encode_base64 est en partie du code des années 90.
  • La jumelle purement Perl a son propre histoire. Quand la version 3.00 en 2004 a retiré les implémentations purement Perl du module core, le changelog les a appelées de la graisse qui cache les vrais problèmes des implémentations XS, et les a re-livrées en tant que MIME::Base64::Perl, où elles vivent toujours.

Alors la prochaine fois que des octets bruts doivent voyager à travers un monde qui n'accepte que du texte, vous connaissez toute l'histoire. Un appel de fonction fait le travail, le retour à la ligne caché est une décision que vous prenez avec le second argument, le croak de caractère large est la façon de l'encodeur de garder votre Unicode honnête, le dialecte sûr pour les URL est en un seul appel depuis 2010, les fichiers circulent en morceaux de 57 octets, et la note de 33 pour cent est le prix d'entrée. Et si un jour vous devez faire le trajet dans l'autre sens, prendre une chaîne de lettres et en extraire les octets d'origine, l'article lié sur le décodage Base64 en Perl, ci-dessous, couvre ce rituel avec la même profondeur.

Dernière mise à jour : 2026-09-08

Article associé : Décodage Base64 en Perl : un guide complet