MySQL et MariaDB : TO_BASE64 et FROM_BASE64
SELECT TO_BASE64('héllo wörld');
-- aMOpbGxvIHfDtnJsZA== (connection charset utf8mb4)
SELECT CONVERT(FROM_BASE64('aMOpbGxvIHfDtnJsZA==') USING utf8mb4);
-- héllo wörld
TO_BASE64 encode les octets de la chaîne dans son jeu de caractères. Avec utf8mb4, vous obtenez de l’UTF-8 ; une colonne latin1 donne des octets Latin-1, si bien que TO_BASE64(CONVERT('héllo' USING latin1)) renvoie aOlsbG8= au lieu de aMOpbGxv. FROM_BASE64 renvoie une chaîne binaire ; CONVERT(... USING utf8mb4) la retransforme en texte.
TO_BASE64 coupe les lignes à 76 caractères, comme MIME :
SELECT LENGTH(TO_BASE64(REPEAT('x', 60))); -- 81 (80 chars + 1 newline)
SELECT REPLACE(TO_BASE64(REPEAT('x', 60)), '\n', ''); -- single line, 80 chars
Une entrée invalide ne provoque pas d’erreur. FROM_BASE64 renvoie NULL :
| Entrée | Résultat |
|---|---|
aGk= | hi |
aGk | NULL (sans remplissage) |
aGk=!! | NULL |
PDw_Pz8-Pg== | NULL (URL-safe) |
a | NULL |
aGl= | hi (bits de remplissage non nuls acceptés) |
'aGVs\nbG8K', 'aGVs bG8K' | hello\n (espaces ignorés) |
Conversion URL-safe avec les fonctions de chaîne :
SELECT TRIM(TRAILING '=' FROM REPLACE(REPLACE(TO_BASE64('<<???>>'), '+', '-'), '/', '_'));
-- PDw_Pz8-Pg
SELECT FROM_BASE64(CONCAT(
REPLACE(REPLACE('PDw_Pz8-Pg', '-', '+'), '_', '/'),
REPEAT('=', (4 - LENGTH('PDw_Pz8-Pg') % 4) % 4)));
-- <<???>>
Pour des valeurs plus longues, enveloppez aussi l’encodeur dans REPLACE(..., '\n', ''). Les deux fonctions existent depuis MySQL 5.6 et dans MariaDB.
PostgreSQL : encode et decode
PostgreSQL travaille sur bytea. Convertissez le texte avec convert_to et revenez en arrière avec convert_from :
SELECT encode(convert_to('héllo wörld', 'UTF8'), 'base64');
-- aMOpbGxvIHfDtnJsZA==
SELECT convert_from(decode('aMOpbGxvIHfDtnJsZA==', 'base64'), 'UTF8');
-- héllo wörld
Comme MySQL, encode(..., 'base64') coupe à 76 caractères ; psql affiche le saut de ligne sous la forme d’un + en fin de ligne. Supprimez-le avec replace(encode(x, 'base64'), E'\n', '').
Contrairement à MySQL, une entrée invalide déclenche une erreur :
decode('aGk', 'base64')
ERROR: invalid base64 end sequence
HINT: Input data is missing padding, is truncated, or is otherwise corrupted.
decode('PDw_Pz8-Pg==', 'base64')
ERROR: invalid symbol "_" found while decoding base64 sequence
aGk=!! échoue avec invalid symbol "!" et a avec invalid base64 end sequence. Les espaces, sauts de ligne compris, sont ignorés, et aGl= est accepté.
PostgreSQL 17 et 18 n’ont pas de format base64url (unrecognized encoding: "base64url") : convertissez donc avec translate.
SELECT translate(rtrim(encode('<<???>>'::bytea, 'base64'), '='), '+/', '-_');
-- PDw_Pz8-Pg
SELECT convert_from(decode(
rpad(translate('PDw_Pz8-Pg', '-_', '+/'), (length('PDw_Pz8-Pg') + 3) / 4 * 4, '='),
'base64'), 'UTF8');
-- <<???>>
Pour valider sans faire échouer une transaction, enveloppez decode dans une fonction PL/pgSQL avec un bloc EXCEPTION WHEN others qui renvoie NULL.
SQL Server : l’astuce XML base64Binary
Avant SQL Server 2025, il n’y a pas de fonction Base64. Le type XML convertit entre varbinary et xs:base64Binary, qui n’est autre que du Base64 :
-- encode
DECLARE @bin varbinary(max) = CAST('hi' AS varbinary(max));
SELECT CAST('' AS xml).value('xs:base64Binary(sql:variable("@bin"))', 'varchar(max)');
-- aGk=
-- decode
DECLARE @b64 varchar(max) = 'aGk=';
SELECT CAST('' AS xml).value('xs:base64Binary(sql:variable("@b64"))', 'varbinary(max)');
-- 0x6869
FOR XML ... BINARY BASE64 et FOR JSON émettent aussi les colonnes varbinary en Base64 : SELECT CAST('hi' AS varbinary(max)) AS bin FOR JSON PATH renvoie [{"bin":"aGk="}]. La conversion XML ne coupe pas les lignes : 60 octets ont donné une seule chaîne de 80 caractères.
Les méthodes XML exigent QUOTED_IDENTIFIER ON. Par défaut, sqlcmd le désactive, ce qui donne Msg 1934: SELECT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'. Passez -I ou exécutez SET QUOTED_IDENTIFIER ON.
Encodage du texte dans SQL Server
nvarchar est en UTF-16LE : CAST(N'héllo wörld' AS varbinary(max)) s’encode donc en aADpAGwAbABvACAAdwD2AHIAbABkAA==, que les autres systèmes décodent avec des blancs entre les lettres. Pour de l’UTF-8 (SQL Server 2019+), passez d’abord par un classement UTF-8 :
DECLARE @bin varbinary(max) = CAST(CAST(N'héllo wörld'
COLLATE Latin1_General_100_CI_AS_SC_UTF8 AS varchar(max)) AS varbinary(max));
-- encodes to aMOpbGxvIHfDtnJsZA==
Pour redécoder de l’UTF-8, il faut une cible UTF-8. Un simple CAST(@raw AS varchar(max)) dans une base qui utilise le classement par défaut SQL_Latin1_General_CP1_CI_AS affiche héllo wörld. Insérer les octets dans une colonne déclarée varchar(max) COLLATE Latin1_General_100_CI_AS_SC_UTF8 donne héllo wörld. Pour des données UTF-16, CAST(@raw AS nvarchar(max)) suffit.
Erreurs
Avec un littéral de chaîne, un Base64 invalide échoue dès la compilation : Msg 9319: XQuery [value()]: Static simple type validation: Invalid simple type value 'aGk'. La même entrée passée via sql:variable renvoie NULL à la place. Le remplissage manquant, les caractères URL-safe (PDw_Pz8-Pg==) et les bits de remplissage non nuls (aGl=) ont tous été rejetés ; un saut de ligne à l’intérieur de la chaîne a été accepté.
SQL Server 2025 : BASE64_ENCODE et BASE64_DECODE
SQL Server 2025 (17.x) et Azure SQL ajoutent de vraies fonctions, avec une option URL-safe :
SELECT BASE64_ENCODE(0x3C3C3F3F3F3E3E); -- PDw/Pz8+Pg==
SELECT BASE64_ENCODE(0x3C3C3F3F3F3E3E, 1); -- PDw_Pz8-Pg (url_safe, no padding)
SELECT BASE64_DECODE('PDw_Pz8-Pg'); -- 0x3C3C3F3F3F3E3E
BASE64_ENCODE n’accepte que du varbinary ; lui passer du varchar échoue avec Msg 8116: Argument data type varchar(max) is invalid for argument 1 of base64_encode function. BASE64_DECODE accepte les deux alphabets, avec ou sans remplissage, ainsi que aGl=. Une entrée invalide comme aGk=!! ou a déclenche Msg 9803: Invalid data for type "Base64Decode".
Pièges communs à toutes les bases
- Le jeu de caractères de l’entrée. Le même texte donne un Base64 différent dans une colonne
latin1, une colonneutf8mb4et une colonnenvarchar. Fixez-vous sur des octets UTF-8 et convertissez explicitement. - Les sauts de ligne cachés. MySQL et PostgreSQL coupent à 76 caractères. Les consommateurs de JSON et les en-têtes HTTP cassent sur le
\nintégré. - Les
NULLsilencieux. MySQL et l’astuce XML de SQL Server renvoientNULLpour une entrée invalide, qu’unJOINou unWHEREécarte sans bruit. - Les grosses valeurs. Encoder un BLOB dans une requête fait transiter 33 % de données en plus sur le réseau. Pour vérifier une valeur stockée à la main, sélectionnez son Base64 et ouvrez-le avec Base64 en fichier ou Base64 en hex.
FAQ
Pourquoi FROM_BASE64 de MySQL renvoie-t-il NULL ?
MySQL renvoie NULL au lieu d’une erreur pour une entrée invalide : remplissage manquant, - ou _ URL-safe, caractères parasites. Vérifiez l’entrée avec le validateur Base64, et corrigez les chaînes URL-safe avec REPLACE avant de décoder.
Pourquoi la sortie de TO_BASE64 dans MySQL contient-elle des sauts de ligne ?
TO_BASE64 suit la convention MIME et insère un saut de ligne tous les 76 caractères. Enveloppez-la dans REPLACE(TO_BASE64(x), '\n', '') pour une sortie sur une seule ligne.
SQL Server a-t-il une fonction Base64 ?
SQL Server 2025 et Azure SQL proposent BASE64_ENCODE et BASE64_DECODE. Les versions plus anciennes n’ont pas de fonction, mais la conversion XML xs:base64Binary fait l’affaire.
Faut-il stocker des fichiers en Base64 dans la base de données ?
En général, non. Une colonne binaire (BLOB, bytea, varbinary) stocke les mêmes données en occupant environ 25 % de moins et évite la conversion. N’encodez qu’au moment d’envoyer les données à un système qui a besoin de texte. Voir le surcoût de taille de Base64.