Comment pouvez-vous encoder une chaîne en Base64 en JavaScript?

810

J'ai un script PHP qui peut encoder une image PNG en une chaîne Base64.

Je voudrais faire la même chose en utilisant JavaScript. Je sais comment ouvrir des fichiers, mais je ne sais pas comment faire l'encodage. Je n'ai pas l'habitude de travailler avec des données binaires.

Nom d'utilisateur
la source
2
Voici le meilleur moyen d'utiliser base64_encode et base64_decode en utilisant javascript. Voir les liens ci-dessous. phpjs.org/functions/base64_encode:358 phpjs.org/functions/base64_decode:357
gautamlakum
voici un autre plugin jquery pour encoder / décoder en base64
zahid9i
Vérifiez microjs: microjs.com/#base64
Vinod Srivastav
Référencé dans la méta-question Réponses fondamentalement identiques - Seule différence: correction des erreurs .
Peter Mortensen

Réponses:

866

Vous pouvez utiliser btoa()et atob()pour convertir vers et depuis l'encodage base64.

Il semble y avoir une certaine confusion dans les commentaires concernant ce que ces fonctions acceptent / renvoient, donc…

  • btoa()accepte une «chaîne» où chaque caractère représente un octet de 8 bits - si vous passez une chaîne contenant des caractères qui ne peuvent pas être représentés sur 8 bits, elle se cassera probablement . Ce n'est pas un problème si vous traitez réellement la chaîne comme un tableau d'octets, mais si vous essayez de faire autre chose, vous devrez d'abord la coder.

  • atob()renvoie une «chaîne» où chaque caractère représente un octet de 8 bits - c'est-à-dire que sa valeur sera comprise entre 0et 0xff. Cela ne signifie pas que c'est ASCII - probablement si vous utilisez cette fonction, vous vous attendez à travailler avec des données binaires et non du texte.

Voir également:

Shog9
la source
47
Notez que cela fonctionne également pour les navigateurs webkit, tels que Safari.
Daniel Von Fange
5
mais cela ne fonctionne pas sur iPhone3G avec iOS 4.1. Il fonctionne sur le simulateur du simulateur iPhone lorsqu'il est réglé sur iPhone4 ou iPhone.
Grant M
29
Veuillez noter la considération particulière pour les chaînes Unicode: developer.mozilla.org/En/DOM/Window.btoa#Unicode_Strings btoa et atob ne fonctionnent correctement que pour les chaînes ASCII. En tant qu'américain, vous ne remarquerez probablement pas de différence ... mais la première fois que vous utilisez un caractère accentué, votre code se cassera.
Dan Esparza
70
vous devez utiliser btoa(unescape(encodeURIComponent(str))))si str est UFT8
SET
4
Voir mon montage, @Triynko. Ceux-ci ne sont pas destinés à être utilisés pour traiter du texte , point final.
Shog9
289

D'ici :

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/
var Base64 = {

// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

// public method for encoding
encode : function (input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    input = Base64._utf8_encode(input);

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output = output +
        this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
        this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

    }

    return output;
},

// public method for decoding
decode : function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

        enc1 = this._keyStr.indexOf(input.charAt(i++));
        enc2 = this._keyStr.indexOf(input.charAt(i++));
        enc3 = this._keyStr.indexOf(input.charAt(i++));
        enc4 = this._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }

    }

    output = Base64._utf8_decode(output);

    return output;

},

// private method for UTF-8 encoding
_utf8_encode : function (string) {
    string = string.replace(/\r\n/g,"\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

        var c = string.charCodeAt(n);

        if (c < 128) {
            utftext += String.fromCharCode(c);
        }
        else if((c > 127) && (c < 2048)) {
            utftext += String.fromCharCode((c >> 6) | 192);
            utftext += String.fromCharCode((c & 63) | 128);
        }
        else {
            utftext += String.fromCharCode((c >> 12) | 224);
            utftext += String.fromCharCode(((c >> 6) & 63) | 128);
            utftext += String.fromCharCode((c & 63) | 128);
        }

    }

    return utftext;
},

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }

    }

    return string;
}

}

De plus, la recherche sur "l'encodage javascript base64" donne lieu à de nombreuses autres options, la précédente était la première.

Sunny Milenov
la source
3
Ceci est également utile lorsque l'encodage base64 n'est pas standard; dans mon cas, le caractère "/" n'a pas été utilisé et le "?" Le caractère a été utilisé à la place, ce qui signifie que même dans Chrome, atob () n'allait pas décoder les chaînes base64 qui étaient entrantes.
Chris Moschini
21
Soyez prudent avec ce code - il tente d'interpréter votre chaîne comme une chaîne codée UTF-8. Nous avons eu un cas où nous avions une chaîne binaire (c'est-à-dire que chaque caractère de la chaîne devrait être interprété comme un octet), et ce code a corrompu les données. Lisez la source, Luke.
Daniel Yankowsky
11
Tout ce qui est nécessaire pour le rendre sûr pour la plupart des encodages / décodages binaires, il supprime l' string = string.replace(/\r\n/g,"\n");instruction discutable dans la méthode de codage utf8.
Marius
7
@Marius: Je me demande pourquoi ils incluraient-ils même string = string.replace(/\r\n/g,"\n");en premier lieu, lol. C'est comme "oh, laisse encoder cette chaîne, mais d'abord, pourquoi ne normalisons-nous pas au hasard tous les sauts de ligne sans aucune bonne raison". Cela devrait absolument être retiré de la classe en toutes circonstances.
Triynko
2
Je ne suis pas un gourou de javascript, mais ce code semble contenir un bug: si chr2 est NaN, sa valeur est toujours utilisée dans l'instruction enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);. Dans mon navigateur, cela fonctionne bien, NaN>>4est égal à 0, mais je ne sais pas si tous les navigateurs le font (également, NaN/16égal à NaN).
Jan
117

Internet Explorer 10+

// Define the string
var string = 'Hello World!';

// Encode the String
var encodedString = btoa(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"

// Decode the String
var decodedString = atob(encodedString);
console.log(decodedString); // Outputs: "Hello World!"

Navigateur croisé

// Create Base64 Object
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}

// Define the string
var string = 'Hello World!';

// Encode the String
var encodedString = Base64.encode(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"

// Decode the String
var decodedString = Base64.decode(encodedString);
console.log(decodedString); // Outputs: "Hello World!"

jsFiddle


avec Node.js

Voici comment vous encodez du texte normal en base64 dans Node.js:

//Buffer() requires a number, array or string as the first parameter, and an optional encoding type as the second parameter. 
// Default is utf8, possible encoding types are ascii, utf8, ucs2, base64, binary, and hex
var b = new Buffer('JavaScript');
// If we don't use toString(), JavaScript assumes we want to convert the object to utf8.
// We can make it convert to other formats by passing the encoding type to toString().
var s = b.toString('base64');

Et voici comment décoder les chaînes encodées en base64:

var b = new Buffer('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString();

avec Dojo.js

Pour coder un tableau d'octets à l'aide de dojox.encoding.base64:

var str = dojox.encoding.base64.encode(myByteArray);

Pour décoder une chaîne codée en base64:

var bytes = dojox.encoding.base64.decode(str)

bower install angular-base64

<script src="bower_components/angular-base64/angular-base64.js"></script>

angular
    .module('myApp', ['base64'])
    .controller('myController', [

    '$base64', '$scope', 
    function($base64, $scope) {

        $scope.encoded = $base64.encode('a string');
        $scope.decoded = $base64.decode('YSBzdHJpbmc=');
}]);
davidcondrey
la source
3
Cette réponse est basée sur le code d'origine et N'INCLUT PAS les mises à jour de ce code publiées dans d'autres réponses ici.
Eugene Ryabtsev
La solution NodeJS proposée est obsolète.
Vladimir Nul
94

Le code de Sunny est génial sauf qu'il casse dans IE7 à cause des références à "ceci". Corrigé en remplaçant ces références par "Base64":

var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

// public method for encoding
encode : function (input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    input = Base64._utf8_encode(input);

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output = output +
        Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
        Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);

    }

    return output;
},

// public method for decoding
decode : function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

        enc1 = Base64._keyStr.indexOf(input.charAt(i++));
        enc2 = Base64._keyStr.indexOf(input.charAt(i++));
        enc3 = Base64._keyStr.indexOf(input.charAt(i++));
        enc4 = Base64._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }

    }

    output = Base64._utf8_decode(output);

    return output;

},

// private method for UTF-8 encoding
_utf8_encode : function (string) {
    string = string.replace(/\r\n/g,"\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

        var c = string.charCodeAt(n);

        if (c < 128) {
            utftext += String.fromCharCode(c);
        }
        else if((c > 127) && (c < 2048)) {
            utftext += String.fromCharCode((c >> 6) | 192);
            utftext += String.fromCharCode((c & 63) | 128);
        }
        else {
            utftext += String.fromCharCode((c >> 12) | 224);
            utftext += String.fromCharCode(((c >> 6) & 63) | 128);
            utftext += String.fromCharCode((c & 63) | 128);
        }

    }

    return utftext;
},

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }

    }
    return string;
}
}
user850789
la source
4
ooh mon mauvais, je prenais l'entrée de l'URL du navigateur; où | est converti en% 7C; d'où l'encodage aussi mal.
Kanagavelu Sugumar
Je sais que c'est vraiment vieux, mais j'ai vu cette fonction utilisée à plus d'un endroit, la chaîne de clé est en fait à 65 caractères, pas 64. La chaîne n'est pas une spécification standard, je ne suis pas sûr que cela soit important, mais je me demandais simplement si c'est le cas?
Jonathan Wagner
"utiliser strict"; est ce qui rompt le «ceci» et d'autres éléments de type comme «avec» et d'après ce que j'ai lu, «eval» est critiqué. Toutes les idées mal placées sur les abus. Personnellement, je ne vois pas pourquoi JavaScript doit suivre son cours, il n'a jamais été conçu comme un programme étroitement lié et rendu plus complexe qu'il ne l'est déjà. Si vous voulez être lié, faites un compilateur pour javascript.
Mark Giblin
J'essaie d'utiliser cette fonction et je reçois l'erreur: Causée par: org.mozilla.javascript.EcmaError: TypeError: Impossible de trouver la fonction à remplacer dans l'objet teste teste teste J'essaie de coder .txt avec "teste teste teste". Quelqu'un sait pourquoi cette erreur?
PRVS
@JonathanWagner - 64 caractères sont utilisés pour l'encodage normal. Le 65ème caractère est utilisé comme remplissage entre eux, la chaîne d'entrée n'a pas un nombre de caractères divisible par 3.
Kickstart
90

Vous pouvez utiliser btoa(à base-64) et atob(à partir de base-64).

Pour IE 9 et versions antérieures , essayez le plugin jquery-base64 :

$.base64.encode("this is a test");
$.base64.decode("dGhpcyBpcyBhIHRlc3Q=");
Vitalii Fedorenko
la source
133
Pourquoi tout doit-il être un plugin jQuery: c c'est juste une fonctionnalité JavaScript de base qui n'a rien à voir avec le DOM ou jQuery
EaterOfCode
38
Ce n'est pas une fonctionnalité de base ou il n'y aurait pas autant de réponses différentes avec un vote élevé (y compris le bricolage tl; le code dr). Donc, à mon humble avis, c'est en fait un bon cas d'utilisation pour jQuery (un liner, censé fonctionner même dans WebView d'Android) - encore plus s'il s'agit déjà d'une dépendance.
Risadinha
1
J'aime installer des extraits de code comme celui-ci dans jQuery principalement parce qu'ils existeront dans un espace de noms contrôlé. Si vous n'utilisez pas AMD ou CommonJS ou un modèle de conception similaire, il est facile pour votre espace de noms global de devenir vraiment compliqué avec un tas de fonctions aléatoires.
sffc
9
@Risadinha - sauf que sa fonctionnalité ne dépend pas du jQuery ou ne l'étend pas du tout ... littéralement, les seules références à jQuery dans son code sont l'attachement à l'objet jQuery ... alors à quoi bon l'attacher à jQuery et donc nécessiter jQuery à utiliser? Il suffit de lui faire son propre liner base64.encode(...)et base64.decode(...)... de l'attacher à jQuery quand il n'a aucune fonctionnalité spécifique à jQuery n'a absolument aucun sens ...
Jimbo Jonny
1
jQuery n'a pas été demandé. Pas une réponse valide à une vieille question ordinaire de JS.
metaColin
34

À partir des commentaires (par SET et Stefan Steiger) sous la réponse acceptée, voici un bref résumé de la façon d'encoder / décoder une chaîne vers / depuis base64 sans avoir besoin d'une bibliothèque.

str = "The quick brown fox jumps over the lazy dog";
b64 = btoa(unescape(encodeURIComponent(str)));
str = decodeURIComponent(escape(window.atob(b64)));

Démo

(utilise la bibliothèque jQuery, mais pas pour encoder / décoder)

crashwap
la source
Pour confirmer, cela prend-il en charge les caractères UTF-8?
Crashalot
1
@Crashalot Je me rends compte que c'est deux ans trop tard, mais oui. Je suis également en train de réaliser en tapant ceci que vous avez fourni une modification qui a peut-être fait fonctionner UTF8.
tycrek
Pour tous ceux qui recherchent ici une bonne solution à utiliser avec Node.js, je peux confirmer que cela fonctionne. Pour le décodage dans Node, j'ai utilisé:Buffer.from(b64data, 'base64').toString();
tycrek
26

Il y a quelques bogues dans les deux implémentations de _utf8_decode. c1et c2sont affectés en tant que variables globales en raison d'une utilisation non conforme de l' varinstruction, et c3ne sont pas du tout initialisés ou déclarés.

Cela fonctionne, mais ces variables remplaceront toutes celles existantes avec le même nom en dehors de cette fonction.

Voici une version qui ne fera pas ça:

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = 0, c1 = 0, c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c1 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
            i += 2;
        }
        else {
            c1 = utftext.charCodeAt(i+1);
            c2 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
            i += 3;
        }

    }
    return string;
}
vole
la source
9
@Daan Je n'avais pas assez de représentants pour éditer les réponses quand j'ai écrit cette réponse ... en 2011.
vole
2
IE7? je suppose que nous devrions arrêter de perdre du temps pour écrire du code pour cela, les gens n'arrêteront pas d'utiliser cette ancienne technologie à moins que nous les développeurs ne les y obligions!
Rami Dabain
@RonanDejhero ne fonctionne-t-il pas dans IE7? Je ne me souviens pas si j'ai testé dans ce navigateur particulier.
vole le
1
Qu'est-ce que je voulais dire que si cela ne fonctionne pas dans IE7, personne ne devrait s'en soucier!. je n'ai pas testé et je ne le
testerai
16

J'ai + 1 la réponse de Sunny, mais je voulais apporter quelques modifications que j'ai apportées à mon propre projet au cas où quelqu'un le trouverait utile. Fondamentalement, je viens de nettoyer un peu le code d'origine afin que JSLint ne se plaigne pas autant, et j'ai rendu les méthodes marquées comme privées dans les commentaires réellement privées. J'ai également ajouté deux méthodes dont j'avais besoin dans mon propre projet, à savoir decodeToHexet encodeFromHex.

Le code:

var Base64 = (function() {
    "use strict";

    var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    var _utf8_encode = function (string) {

        var utftext = "", c, n;

        string = string.replace(/\r\n/g,"\n");

        for (n = 0; n < string.length; n++) {

            c = string.charCodeAt(n);

            if (c < 128) {

                utftext += String.fromCharCode(c);

            } else if((c > 127) && (c < 2048)) {

                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);

            } else {

                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);

            }

        }

        return utftext;
    };

    var _utf8_decode = function (utftext) {
        var string = "", i = 0, c = 0, c1 = 0, c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {

                string += String.fromCharCode(c);
                i++;

            } else if((c > 191) && (c < 224)) {

                c1 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
                i += 2;

            } else {

                c1 = utftext.charCodeAt(i+1);
                c2 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
                i += 3;

            }

        }

        return string;
    };

    var _hexEncode = function(input) {
        var output = '', i;

        for(i = 0; i < input.length; i++) {
            output += input.charCodeAt(i).toString(16);
        }

        return output;
    };

    var _hexDecode = function(input) {
        var output = '', i;

        if(input.length % 2 > 0) {
            input = '0' + input;
        }

        for(i = 0; i < input.length; i = i + 2) {
            output += String.fromCharCode(parseInt(input.charAt(i) + input.charAt(i + 1), 16));
        }

        return output;
    };

    var encode = function (input) {
        var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

        input = _utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output += _keyStr.charAt(enc1);
            output += _keyStr.charAt(enc2);
            output += _keyStr.charAt(enc3);
            output += _keyStr.charAt(enc4);

        }

        return output;
    };

    var decode = function (input) {
        var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output += String.fromCharCode(chr1);

            if (enc3 !== 64) {
                output += String.fromCharCode(chr2);
            }
            if (enc4 !== 64) {
                output += String.fromCharCode(chr3);
            }

        }

        return _utf8_decode(output);
    };

    var decodeToHex = function(input) {
        return _hexEncode(decode(input));
    };

    var encodeFromHex = function(input) {
        return encode(_hexDecode(input));
    };

    return {
        'encode': encode,
        'decode': decode,
        'decodeToHex': decodeToHex,
        'encodeFromHex': encodeFromHex
    };
}());
Joe Dyndale
la source
Au début, je pensais que votre déroulement de la concaténation de sortie dans des instructions distinctes serait plus optimal, mais après y avoir réfléchi pendant une seconde, cela devrait être plus inefficace car les chaînes Javascript sont immuables et cela provoquerait 4 copies d'obstacles de données potentiellement énormes lors du travail avec de gros fichiers de données binaires. C'est un pari plus sûr de concaténer les 4 caractères ensemble d'abord, puis de construire une nouvelle chaîne. J'aurais aimé savoir avec certitude une meilleure méthode de construction de chaînes qui serait sûre d'être efficace sur toutes les plateformes. (même IE6)
Marius
Je n'ai pas pris en compte les performances dans mon nettoyage du code initialement publié. Je viens de le rendre plus lisible et de rendre les méthodes marquées comme privées dans les commentaires dans l'original réellement privées en utilisant le modèle de module révélateur. Je suis sûr qu'il peut également être optimisé en termes de performances. Je ne sais pas exactement quand la collecte des ordures démarrera ici, et le hachage de gros fichiers via Javascript n'est pas très courant (ou en fait, ce n'est probablement pas la solution optimale dans tous les cas).
Joe Dyndale
C'est drôle comment ce code vit ici. Il en existe déjà 3 versions différentes sur cette page.
gregn3
16

Pour les navigateurs plus récents, encoder Uint8Array en chaîne et décoder la chaîne en Uint8Array.

const base64 = {
    decode: s => Uint8Array.from(atob(s), c => c.charCodeAt(0)),
    encode: b => btoa(String.fromCharCode(...new Uint8Array(b)))
};

Pour Node.js, vous pouvez utiliser ce qui suit pour coder une chaîne, un tampon ou Uint8Array en chaîne et décoder de chaîne, tampon ou Uint8Array en tampon.

const base64 = {
    decode: s => Buffer.from(s, 'base64'),
    encode: b => Buffer.from(b).toString('base64')
};
Rix
la source
13

Pour rendre une URL de chaîne encodée en Base64 conviviale, en JavaScript, vous pouvez faire quelque chose comme ceci:

// if this is your Base64 encoded string
var str = 'VGhpcyBpcyBhbiBhd2Vzb21lIHNjcmlwdA=='; 

// make URL friendly:
str = str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');

// reverse to original encoding
str = (str + '===').slice(0, str.length + (str.length % 4));
str = str.replace(/-/g, '+').replace(/_/g, '/');

Voir aussi ce violon: http://jsfiddle.net/magikMaker/7bjaT/

magikMaker
la source
9
Je suggérerais humblement que l'utilisation de encodeURIComponentpourrait bien aboutir à un résultat supérieur avec moins de dépenses d'effort de la part du développeur.
Pablo Fernandez
11
encodeURIComponent changera la longueur des chaînes encodées en base64, et remplacer '-' et '_' par '+' et '/' est une pratique standard lors de l'utilisation de base64 dans les URL (par exemple docs.python.org/library/base64.html#base64 .urlsafe_b64encode ). Pas besoin de s'énerver.
natevw
12

Veuillez noter que cela ne convient pas aux chaînes Unicode brutes! Voir la section Unicode ici .

Syntaxe de codage

var encodedData = window.btoa(stringToEncode);

Syntaxe de décodage

var decodedData = window.atob(encodedData);

Kathir
la source
1
Lien direct vers la section unicode: developer.mozilla.org/en-US/docs/Web/API/…
TomTasche
12

J'ai réécrit à la main ces méthodes d'encodage et de décodage à l'exception de la méthode hexadécimale dans un format modulaire pour la compatibilité multiplateforme / navigateur et également avec une portée privée réelle, et utilise btoaetatob si elles existent en raison de la vitesse plutôt que d'utiliser son propre encodage:

https://gist.github.com/Nijikokun/5192472

Usage:

base64.encode(/* String */);
base64.decode(/* String */);

utf8.encode(/* String */);
utf8.decode(/* String */);
Nijikokun
la source
12

Cette question et ses réponses m'ont indiqué la bonne direction.
Surtout avec unicode atob et btoa ne peuvent pas être utilisés "vanille" et de nos jours TOUT est unicode ..

Directement depuis Mozilla, deux belles fonctions à cet effet (testées avec des balises unicode et html à l'intérieur)

function b64EncodeUnicode(str) {
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode('0x' + p1);
    }));
}

b64EncodeUnicode('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64EncodeUnicode('\n'); // "Cg=="



function b64DecodeUnicode(str) {
    return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}

b64DecodeUnicode('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
b64DecodeUnicode('Cg=='); // "\n"

Ces fonctions seront rapides comme l'éclair par rapport au décodage brut en base64 en utilisant une fonction javascript personnalisée car btoa et atob sont exécutés en dehors de l'interpréteur.

Si vous pouvez ignorer les anciens IE et les anciens téléphones portables (comme l'iphone 3?), Cela devrait être une bonne solution.

John
la source
10

si vous avez besoin de coder un objet image HTML, vous pouvez écrire une fonction simple comme:

function getBase64Image(img) {  
  var canvas = document.createElement("canvas");  
  canvas.width = img.width;  
  canvas.height = img.height;  
  var ctx = canvas.getContext("2d");  
  ctx.drawImage(img, 0, 0);  
  var dataURL = canvas.toDataURL("image/png");  
  // escape data:image prefix
  return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");  
  // or just return dataURL
  // return dataURL
}  

Pour obtenir une base64 d'image par identifiant:

function getBase64ImageById(id){  
  return getBase64Image(document.getElementById(id));  
} 

plus ici

Nedudi
la source
Oui, et var img = new Image (); img.src = "../images/myPic.png";
pdschuller
7

Contribuer avec un polyfill minifié pour window.atob+ window.btoaque j'utilise actuellement.

(function(){function t(t){this.message=t}var e="undefined"!=typeof exports?exports:this,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=Error(),t.prototype.name="InvalidCharacterError",e.btoa||(e.btoa=function(e){for(var o,n,a=0,i=r,c="";e.charAt(0|a)||(i="=",a%1);c+=i.charAt(63&o>>8-8*(a%1))){if(n=e.charCodeAt(a+=.75),n>255)throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");o=o<<8|n}return c}),e.atob||(e.atob=function(e){if(e=e.replace(/=+$/,""),1==e.length%4)throw new t("'atob' failed: The string to be decoded is not correctly encoded.");for(var o,n,a=0,i=0,c="";n=e.charAt(i++);~n&&(o=a%4?64*o+n:n,a++%4)?c+=String.fromCharCode(255&o>>(6&-2*a)):0)n=r.indexOf(n);return c})})();
Johan
la source
6

Je préfère utiliser les méthodes d'encodage / décodage bas64 de CryptoJS , la bibliothèque la plus populaire pour les algorithmes cryptographiques standard et sécurisés implémentés en JavaScript en utilisant les meilleures pratiques et modèles.

Dan Dascalescu
la source
6

Voici une version AngularJS Factory de celle de @ user850789:

'use strict';

var ProjectNameBase64Factory = angular.module('project_name.factories.base64', []);

ProjectNameBase64Factory.factory('Base64', function () {
    var Base64 = {
        // private property
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

        // public method for encoding
        encode: function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            input = Base64._utf8_encode(input);

            while (i < input.length) {

                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output +
                         Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
                         Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);

            }

            return output;
        },

        // public method for decoding
        decode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            while (i < input.length) {

                enc1 = Base64._keyStr.indexOf(input.charAt(i++));
                enc2 = Base64._keyStr.indexOf(input.charAt(i++));
                enc3 = Base64._keyStr.indexOf(input.charAt(i++));
                enc4 = Base64._keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }

            }

            output = Base64._utf8_decode(output);

            return output;

        },

        // private method for UTF-8 encoding
        _utf8_encode: function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";

            for (var n = 0; n < string.length; n++) {

                var c = string.charCodeAt(n);

                if (c < 128) {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            }

            return utftext;
        },

        // private method for UTF-8 decoding
        _utf8_decode: function (utftext) {
            var string = "";
            var i = 0;
            var c = 0, c2 = 0, c3 = 0;

            while (i < utftext.length) {

                c = utftext.charCodeAt(i);

                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                }
                else if ((c > 191) && (c < 224)) {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                }
                else {
                    c2 = utftext.charCodeAt(i + 1);
                    c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }

            }
            return string;
        }
    };
    return Base64;
});
À
la source
6

J'avais besoin d'encodage d'une chaîne UTF-8 en base64 pour un de mes projets. La plupart des réponses ici ne semblent pas gérer correctement les paires de substitution UTF-16 lors de la conversion en UTF-8, donc, pour terminer, je publierai ma solution:

function strToUTF8Base64(str) {

    function decodeSurrogatePair(hi, lo) {
        var resultChar = 0x010000;
        resultChar += lo - 0xDC00;
        resultChar += (hi - 0xD800) << 10;
        return resultChar;
    }

    var bytes = [0, 0, 0];
    var byteIndex = 0;
    var result = [];

    function output(s) {
        result.push(s);
    }

    function emitBase64() {

        var digits =
                'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
                'abcdefghijklmnopqrstuvwxyz' +
                '0123456789+/';

        function toDigit(value) {
            return digits[value];
        }

        // --Byte 0--    --Byte 1--    --Byte 2--
        // 1111  1122    2222  3333    3344  4444

        var d1 = toDigit(bytes[0] >> 2);
        var d2 = toDigit(
            ((bytes[0] & 0x03) << 4) |
            (bytes[1] >> 4));
        var d3 = toDigit(
            ((bytes[1] & 0x0F) << 2) |
            (bytes[2] >> 6));
        var d4 = toDigit(
            bytes[2] & 0x3F);

        if (byteIndex === 1) {
            output(d1 + d2 + '==');
        }
        else if (byteIndex === 2) {
            output(d1 + d2 + d3 + '=');
        }
        else {
            output(d1 + d2 + d3 + d4);
        }
    }

    function emit(chr) {
        bytes[byteIndex++] = chr;
        if (byteIndex == 3) {
            emitBase64();
            bytes[0] = 0;
            bytes[1] = 0;
            bytes[2] = 0;
            byteIndex = 0;
        }
    }

    function emitLast() {
        if (byteIndex > 0) {
            emitBase64();
        }
    }

    // Converts the string to UTF8:

    var i, chr;
    var hi, lo;
    for (i = 0; i < str.length; i++) {
        chr = str.charCodeAt(i);

        // Test and decode surrogate pairs in the string
        if (chr >= 0xD800 && chr <= 0xDBFF) {
            hi = chr;
            lo = str.charCodeAt(i + 1);
            if (lo >= 0xDC00 && lo <= 0xDFFF) {
                chr = decodeSurrogatePair(hi, lo);
                i++;
            }
        }

        // Encode the character as UTF-8.
        if (chr < 0x80) {
            emit(chr);
        }
        else if (chr < 0x0800) {
            emit((chr >> 6) | 0xC0);
            emit(((chr >> 0) & 0x3F) | 0x80);
        }
        else if (chr < 0x10000) {
            emit((chr >> 12) | 0xE0);
            emit(((chr >>  6) & 0x3F) | 0x80);
            emit(((chr >>  0) & 0x3F) | 0x80);
        }
        else if (chr < 0x110000) {
            emit((chr >> 18) | 0xF0);
            emit(((chr >> 12) & 0x3F) | 0x80);
            emit(((chr >>  6) & 0x3F) | 0x80);
            emit(((chr >>  0) & 0x3F) | 0x80);
        }
    }

    emitLast();

    return result.join('');
}

Notez que le code n'est pas complètement testé. J'ai testé certaines entrées, y compris des choses comme strToUTF8Base64('衠衢蠩蠨')et comparées à la sortie d'un outil de codage en ligne ( https://www.base64encode.org/ ).

Ricardo Machado
la source
5

Pour mon projet, j'ai encore besoin de prendre en charge IE7 et de travailler avec une grande entrée pour encoder.

Basé sur le code proposé par Joe Dyndale et comme suggéré dans le commentaire de Marius, il est possible d'améliorer les performances avec IE7 en construisant le résultat avec un tableau au lieu d'une chaîne.

Voici l'exemple d'encodage:

var encode = function (input) {
    var output = [], chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

    input = _utf8_encode(input);

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output.push(_keyStr.charAt(enc1));
        output.push(_keyStr.charAt(enc2));
        output.push(_keyStr.charAt(enc3));
        output.push(_keyStr.charAt(enc4));

    }

    return output.join("");
};
Nico
la source
5

Bien qu'un peu plus de travail, si vous voulez une solution native haute performance, vous pouvez utiliser certaines fonctions HTML5.

Si vous pouvez obtenir vos données dans un Blob, vous pouvez utiliser la fonction FileReader.readAsDataURL () pour obtenir une data://URL et la couper en avant pour obtenir les données base64.

Cependant, vous devrez peut-être effectuer un traitement supplémentaire pour décoder les données, car je ne sais pas si les +caractères sont échappés ou non pour l' data://URL, mais cela devrait être assez trivial.

Malvineous
la source
5

Eh bien, si vous utilisez dojo, cela nous donne un moyen direct d'encoder ou de décoder en base64.

Essaye ça:-

Pour coder un tableau d'octets à l'aide de dojox.encoding.base64:

var str = dojox.encoding.base64.encode(myByteArray);

Pour décoder une chaîne codée en base64:

var bytes = dojox.encoding.base64.decode(str);
Vikash Pandey
la source
3

Vous pouvez utiliser window.btoaet window.atob...

const encoded = window.btoa('Alireza Dezfoolian'); // encode a string
const decoded = window.atob(encoded); // decode the string

Utiliser probablement la façon dont MDN est peut faire votre meilleur travail ... Accepter également unicode ... en utilisant ces deux fonctions simples:

// ucs-2 string to base64 encoded ascii
function utoa(str) {
    return window.btoa(unescape(encodeURIComponent(str)));
}
// base64 encoded ascii to ucs-2 string
function atou(str) {
    return decodeURIComponent(escape(window.atob(str)));
}
// Usage:
utoa('✓ à la mode'); // 4pyTIMOgIGxhIG1vZGU=
atou('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"

utoa('I \u2661 Unicode!'); // SSDimaEgVW5pY29kZSE=
atou('SSDimaEgVW5pY29kZSE='); // "I ♡ Unicode!"
Alireza
la source
3

Voici une démo en direct de JS atob()et des btoa()fonctions intégrées:

<!DOCTYPE html>
<html>
  <head>
    <style>
      textarea{
        width:30%;
        height:100px;
      }
    </style>
    <script>
      // encode string to base64
      function encode()
      {
        var txt = document.getElementById("txt1").value;
        var result = btoa(txt);
        document.getElementById("txt2").value = result;
      }
      // decode base64 back to original string
      function decode()
      {
        var txt = document.getElementById("txt3").value;
        var result = atob(txt);
        document.getElementById("txt4").value = result;
      }
    </script>
  </head>
  <body>
    <div>
      <textarea id="txt1">Some text to decode
      </textarea>
    </div>
    <div>
      <input type="button" id="btnencode" value="Encode" onClick="encode()"/>
    </div>
    <div>
      <textarea id="txt2">
      </textarea>
    </div>
    <br/>
    <div>
      <textarea id="txt3">U29tZSB0ZXh0IHRvIGRlY29kZQ==
      </textarea>
    </div>
    <div>
      <input type="button" id="btndecode" value="Decode" onClick="decode()"/>
    </div>
    <div>
      <textarea id="txt4">
      </textarea>
    </div>
  </body>
</html>
jonathana
la source
2

Utilisez la bibliothèque js-base64 comme

btoa () ne fonctionne pas avec les emojis

var str = "I was funny 😂";
console.log("Original string:", str);

var encodedStr = Base64.encode(str)
console.log("Encoded string:", encodedStr);

var decodedStr = Base64.decode(encodedStr)
console.log("Decoded string:", decodedStr);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/base64.min.js"></script>

Shivaji Mutkule
la source