Codificação e decodificação Base64 em Javascript do lado do cliente

Respostas:

214

Alguns navegadores como Firefox, Chrome, Safari, Opera e IE10 + podem lidar com o Base64 nativamente. Dê uma olhada nesta pergunta do Stackoverflow . Está usando btoa()e atob()funções .

Para JavaScript do lado do servidor (Nó), você pode usar Buffers para decodificar.

Se você está procurando uma solução entre navegadores, existem bibliotecas existentes como o CryptoJS ou código como:

http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

Com o último, você precisa testar minuciosamente a função para compatibilidade entre navegadores. E o erro já foi relatado .

Ranhiru Jude Cooray
fonte
1
Eu usei esse método para codificar um SVG na base64 com o esquema URI da data. Surpresa: essa função codifica cada caractere, para obter o XML malformado no destino:% 3C% 3Fxml% 20version% 3D% 271,0% 27% 20% 3F% 3E% 3Csvg% 20xmlns% 3D% 27http% ...
Dereckson
21
Node.js pode fazer Base64 nativamente: new Buffer('Hello, world!').toString('base64'); new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii'); (fonte)
nyuszika7h
E se eu quisesse fazê-lo com URL seguro?
anddero 18/09/19
1
no nó 5+, use Buffer.from, pois new Buffer(string)está obsoleto. Buffer.from(jwt.split('.')[1], 'base64').toString()
Ray Foss
63

Nos navegadores baseados no Gecko / WebKit (Firefox, Chrome e Safari) e no Opera, você pode usar btoa () e atob () .

Resposta original: Como você pode codificar uma string para Base64 em JavaScript?

nyuszika7h
fonte
Este é um salva-vidas. Usei algumas implementações diferentes para decodificar cadeias muito grandes codificadas em base64 e o resultado sempre estava errado. atob () funciona muito bem!
2222848
15
Nitpick pequeno: o Opera não é baseado no Gecko ou no Webkit, ele usa seu próprio mecanismo de renderização chamado Presto.
31812 Peter Olson
Uau, obrigado por isso. Não sabia que havia um codificador base64 nativo nesses navegadores!
Rob Porter
5
@PeterOlson Not anymore :)
Mustafa
1
Sei que essa é uma postagem antiga, mas sobre a preocupação de @ b2238488, você pode dividir a sequência base64 para que o comprimento de cada token seja um múltiplo de 4 e decodificá-los separadamente. O resultado será o mesmo que decodificar a sequência inteira de uma só vez.
usar o seguinte código
56

Internet Explorer 10 ou superior

// 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!"

Navegador Cruzado

Bibliotecas / módulos de codificação e decodificação UTF-8 e Base64 Javascript reescritos e modularizados para AMD, CommonJS, Nodejs e navegadores. Compatível com vários navegadores.


com Node.js

Aqui está como você codifica o texto normal para base64 no 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');

E aqui está como você decodifica cadeias codificadas em base64:

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

com Dojo.js

Para codificar uma matriz de bytes usando dojox.encoding.base64:

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

Para decodificar uma sequência codificada em 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=');
}]);

Mas como?

Se você quiser saber mais sobre como a base64 é codificada em geral e em JavaScript em particular, eu recomendaria este artigo: Ciência da computação em JavaScript: codificação Base64

davidcondrey
fonte
1
FYI: A versão cross-browser tem alguns vazamentos desagradáveis com c2e provável c1e c3por isso não irá trabalhar com "use strict"como definido acima.
Campbeln
41

Aqui está uma versão mais rigorosa do post de Sniper. Ele pressupõe uma string base64 bem formada, sem retornos de carro. Esta versão elimina alguns loops, adiciona a &0xffcorreção de Yaroslav, elimina valores nulos à direita, além de um pouco de código de golfe.

decodeBase64 = function(s) {
    var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
    var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    for(i=0;i<64;i++){e[A.charAt(i)]=i;}
    for(x=0;x<L;x++){
        c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
        while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
    }
    return r;
};
broc.seib
fonte
5
Ainda menos bytes; DdecodeBase64=function(f){var g={},b=65,d=0,a,c=0,h,e="",k=String.fromCharCode,l=f.length;for(a="";91>b;)a+=k(b++);a+=a.toLowerCase()+"0123456789+/";for(b=0;64>b;b++)g[a.charAt(b)]=b;for(a=0;a<l;a++)for(b=g[f.charAt(a)],d=(d<<6)+b,c+=6;8<=c;)((h=d>>>(c-=8)&255)||a<l-2)&&(e+=k(h));return e};
Der Hochstapler
Sim, mas funciona apenas com ASCII. Os personagens Cyr são mutilados, por exemplo.
Martin Kovachev
@MartinKovachev, você pode postar um novo comentário com texto de exemplo com caracteres Cyr e a codificação base64 correspondente? Talvez possamos corrigir o código para acomodar.
Broc.seib 17/09/2015
Aqui: algo assim: фраза тестова
Martin Kovachev
2
@OliverSalzburg Menos ainda gera tabela de códigos :):var g={},k=String.fromCharCode,i;for(i=0;i<64;)g[k(i>61?(i&1)*4|43:i+[65,71,-4][i/26&3])]=i++;
Mike
34

Função de decodificação de JavaScript Base64 curta e rápida, sem falhas:

function decode_base64 (s)
{
    var e = {}, i, k, v = [], r = '', w = String.fromCharCode;
    var n = [[65, 91], [97, 123], [48, 58], [43, 44], [47, 48]];

    for (z in n)
    {
        for (i = n[z][0]; i < n[z][1]; i++)
        {
            v.push(w(i));
        }
    }
    for (i = 0; i < 64; i++)
    {
        e[v[i]] = i;
    }

    for (i = 0; i < s.length; i+=72)
    {
        var b = 0, c, x, l = 0, o = s.substring(i, i+72);
        for (x = 0; x < o.length; x++)
        {
            c = e[o.charAt(x)];
            b = (b << 6) + c;
            l += 6;
            while (l >= 8)
            {
                r += w((b >>> (l -= 8)) % 256);
            }
         }
    }
    return r;
}
Atirador de elite
fonte
6
O Opera 11.62 parece ter problema com a parte '% 256'. Substituí-lo por '& 0xff' faz com que funcione.
Yaroslav Stavnichiy
O código javascript do terminal virtual Tyk parece ter um problema com a parte '\ x00'. Substituí-lo por r = r.replace (/ \ x00 / g, '') faz com que funcione
Panupong Kongarn 14/02
11

O projeto php.js possui implementações em JavaScript de muitas das funções do PHP. base64_encodee base64_decodeestão incluídos.

ceejayoz
fonte
O php.js é a encarnação de todo o mal e pertence à sua própria camada no inferno. Evite como uma praga. (Mais informações: softwareengineering.stackexchange.com/questions/126671/… )
Coreus 03/04/19
Não vejo muito apoio a essa afirmação geral nesse link, @Coreus. Usada criteriosamente, ou como ponto de partida, é uma maneira perfeitamente aceitável de descobrir a lógica equivalente em JS para algo que você já deve saber fazer em PHP.
ceejayoz
9

Alguém disse código de golfe? =)

A seguir, é minha tentativa de melhorar minha desvantagem enquanto acompanho os horários. Fornecido para sua conveniência.

function decode_base64(s) {
  var b=l=0, r='',
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  s.split('').forEach(function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
  });
  return r;
}

Na verdade, o que eu procurava era uma implementação assíncrona e, para minha surpresa, ao forEachcontrário da $([]).eachimplementação do método JQuery, é muito síncrona.

Se você também tiver em mente essas noções malucas, um atraso 0 window.setTimeoutexecutará a decodificação da base64 de forma assíncrona e executará a função de retorno de chamada com o resultado quando terminar.

function decode_base64_async(s, cb) {
  setTimeout(function () { cb(decode_base64(s)); }, 0);
}

A @ Toothbrush sugeriu "indexar uma string como uma matriz" e se livrar do split. Essa rotina parece realmente estranha e não tem certeza de quão compatível será, mas atinge outro passarinho, então vamos lá.

function decode_base64(s) {
  var b=l=0, r='',
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  [].forEach.call(s, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
  });
  return r;
}

Ao tentar encontrar mais informações sobre a string JavaScript como array, eu tropecei nesta dica profissional usando um /./gregex para percorrer uma string. Isso reduz ainda mais o tamanho do código, substituindo a string no lugar e eliminando a necessidade de manter uma variável de retorno.

function decode_base64(s) {
  var b=l=0,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  return s.replace(/./g, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    return l<8?'':String.fromCharCode((b>>>(l-=8))&0xff);
  });
}

Se, no entanto, você estava procurando algo um pouco mais tradicional, talvez o seguinte seja mais para o seu gosto.

function decode_base64(s) {
  var b=l=0, r='', s=s.split(''), i,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  for (i in s) {
    b=(b<<6)+m.indexOf(s[i]); l+=6;
    if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
  }
  return r;
}

Como não havia o problema nulo à direita, ele foi removido para permanecer abaixo do padrão, mas deve ser facilmente resolvido com um trim()ou umtrimRight() se você preferir, caso isso represente um problema para você.

ie

return r.trimRight();

Nota:

O resultado é uma sequência de bytes ascii, se você precisar de unicode, o mais fácil é a escapesequência de bytes que pode ser decodificada decodeURIComponentpara produzir a sequência de caracteres unicode.

function decode_base64_usc(s) {      
  return decodeURIComponent(escape(decode_base64(s)));
}

Como escapeestá sendo descontinuado, podemos alterar nossa função para oferecer suporte a unicode diretamente sem a necessidade escapeou String.fromCharCodepodemos produzir uma %string de escape pronta para decodificação de URI.

function decode_base64(s) {
  var b=l=0,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  return decodeURIComponent(s.replace(/./g, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
  }));
}

nJoy!

nickl-
fonte
3
Você não precisa splitda string, pois pode indexar uma string JavaScript como uma matriz. s.split('').forEach(function ...pode ser substituído por [].forEach.call(s, function .... Deve ser muito mais rápido, porque não é necessário dividir a string.
Escova de dentes
O "mais tradicional" foi completamente quebrado para mim - produziu uma bagunça ilegível com traços de texto original espalhados por toda parte. No Chrome.
Steve Bennett
@ Steve Bennett Eu testei todas as variantes no chrome ... funciona. Você pode fornecer um exemplo de string base64 que falha?
nickl-
Três anos depois? Ha. Eu nem me lembro do que eu precisava disso.
9788 Steve
6

Eu tentei as rotinas Javascript em phpjs.org e elas funcionaram bem.

Tentei pela primeira vez as rotinas sugeridas na resposta escolhida por Ranhiru Cooray - http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

Eu descobri que eles não funcionavam em todas as circunstâncias. Eu escrevi um caso de teste em que essas rotinas falham e as postei no GitHub em:

https://github.com/scottcarter/base64_javascript_test_data.git

Também publiquei um comentário no blog no ntt.cc para alertar o autor (aguardando moderação - o artigo é antigo, portanto não tenho certeza se o comentário será publicado).

Scott Carter
fonte
1

Prefiro usar os métodos de codificação / decodificação bas64 do CryptoJS , a biblioteca mais popular para algoritmos criptográficos padrão e seguros implementados em JavaScript usando as melhores práticas e padrões.

Dan Dascalescu
fonte
1

No Node.js, podemos fazê-lo de maneira simples

var base64 = 'SGVsbG8gV29ybGQ='
var base64_decode = new Buffer(base64, 'base64').toString('ascii');

console.log(base64_decode); // "Hello World"
KARTHIKEYAN.A
fonte
0

Para estruturas JavaScripts em que não há atobmétodo e, caso você não queira importar bibliotecas externas, esta é uma função curta.

Ele obteria uma string que contém o valor codificado em Base64 e retornará uma matriz decodificada de bytes (onde a matriz de bytes é representada como matriz de números em que cada número é um número inteiro entre 0 e 255, inclusive).

function fromBase64String(str) {
    var alpha = 
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var value = [];
    var index = 0;
    var destIndex  = 0;
    var padding = false;
    while (true) {

        var first  = getNextChr(str, index, padding, alpha);
        var second = getNextChr(str, first .nextIndex, first .padding, alpha);
        var third  = getNextChr(str, second.nextIndex, second.padding, alpha);
        var fourth = getNextChr(str, third .nextIndex, third .padding, alpha);

        index = fourth.nextIndex;
        padding = fourth.padding;

        // ffffffss sssstttt ttffffff
        var base64_first  = first.code  == null ? 0 : first.code;
        var base64_second = second.code == null ? 0 : second.code;
        var base64_third  = third.code  == null ? 0 : third.code;
        var base64_fourth = fourth.code == null ? 0 : fourth.code;

        var a = (( base64_first << 2) & 0xFC ) | ((base64_second>>4) & 0x03);
        var b = (( base64_second<< 4) & 0xF0 ) | ((base64_third >>2) & 0x0F);
        var c = (( base64_third << 6) & 0xC0 ) | ((base64_fourth>>0) & 0x3F);

        value [destIndex++] = a;
        if (!third.padding) {
            value [destIndex++] = b;
        } else {
            break;
        }
        if (!fourth.padding) {
            value [destIndex++] = c;
        } else {
            break;
        }
        if (index >= str.length) {
            break;
        }
    }
    return value;
}

function getNextChr(str, index, equalSignReceived, alpha) {
    var chr = null;
    var code = 0;
    var padding = equalSignReceived;
    while (index < str.length) {
        chr = str.charAt(index);
        if (chr == " " || chr == "\r" || chr == "\n" || chr == "\t") {
            index++;
            continue;
        }
        if (chr == "=") {
            padding = true;
        } else {
            if (equalSignReceived) {
                throw new Error("Invalid Base64 Endcoding character \"" 
                    + chr + "\" with code " + str.charCodeAt(index) 
                    + " on position " + index 
                    + " received afer an equal sign (=) padding "
                    + "character has already been received. "
                    + "The equal sign padding character is the only "
                    + "possible padding character at the end.");
            }
            code = alpha.indexOf(chr);
            if (code == -1) {
                throw new Error("Invalid Base64 Encoding character \"" 
                    + chr + "\" with code " + str.charCodeAt(index) 
                    + " on position " + index + ".");
            }
        }
        break;
    }
    return { character: chr, code: code, padding: padding, nextIndex: ++index};
}

Recursos utilizados: RFC-4648 Seção 4

Yordan Nedelchev
fonte