Як можна кодувати рядок до Base64 в JavaScript?


809

У мене є сценарій PHP, який може кодувати зображення PNG до рядка Base64.

Я б хотів зробити те саме, використовуючи JavaScript. Я знаю, як відкрити файли, але я не впевнений, як зробити кодування. Я не звик працювати з бінарними даними.


2
Тут найкращий спосіб base64_encode та base64_decode за допомогою JavaScript. Дивіться посилання нижче. phpjs.org/functions/base64_encode:358 phpjs.org/functions/base64_decode:357
gautamlakum

ось ще один плагін jquery для кодування / декодування base64
zahid9i

Перевірте microjs: microjs.com/#base64
Srivastav

Відповіді:


865

Ви можете використовувати btoa()та atob()конвертувати в кодування base64 та з нього.

У коментарях з'являється деяка плутанина щодо того, що ці функції приймають / повертають, тож ...

  • btoa()приймає "рядок", де кожен символ являє собою 8-бітний байт - якщо ви передасте рядок, що містить символи, які не можуть бути представлені у 8 бітах, він, ймовірно, зламається . Це не проблема, якщо ви насправді трактуєте рядок як байтовий масив, але якщо ви намагаєтесь зробити щось інше, вам доведеться спочатку кодувати його.

  • atob()повертає "рядок", де кожен символ представляє 8-бітовий байт - тобто його значення буде між 0і 0xff. Це не означає, що це ASCII - імовірно, якщо ви взагалі використовуєте цю функцію, ви розраховуєте працювати з бінарними даними, а не з текстом.

Дивись також:


47
Зауважте, що це також працює для веб-браузерів, таких як Safari.
Даніель Фон Фанге

5
але це не працює на iPhone3G з iOS 4.1. Він працює на тренажері iPhone-симулятора, якщо встановлено на iPhone4 або iPhone.
Грант М

29
Зверніть увагу на особливу увагу для рядків Unicode: developer.mozilla.org/En/DOM/Window.btoa#Unicode_Strings btoa та atob працюють належним чином лише для рядків на основі ASCII. Як американець, ви, мабуть, не помітите різниці ... але коли ви вперше використаєте наголошений символ, ваш код зламається.
Дан Еспарза

70
ви повинні використовувати, btoa(unescape(encodeURIComponent(str))))якщо str UFT8
SET

4
Дивіться мою редакцію, @Triynko. Вони не призначені для обробки тексту , періоду.
Shog9

289

Звідси :

/**
*
*  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;
}

}

Також пошук по "кодуванню JavaScript base64" повертає безліч інших варіантів, перший був першим.


3
Це також корисно, коли кодування base64 є нестандартним; у моєму випадку символ "/" не використовувався, а "?" Замість цього використовується символ, тобто навіть в Chrome atob () не збирався декодувати базові 64 рядки, що надходять.
Кріс Москіні

21
Будьте обережні з цим кодом - він намагається інтерпретувати ваш рядок як кодований рядок UTF-8. У нас був випадок, коли у нас був двійковий рядок (тобто кожен символ у рядку слід інтерпретувати як байт), і цей код пошкодив дані. Прочитайте джерело, Лука.
Даніель Янковський

11
Все, що потрібно, щоб зробити його безпечним для більшості двійкових кодування / декодування, щоб видалити сумнівну string = string.replace(/\r\n/g,"\n");заяву в методі кодування utf8.
Маріус

7
@Marius: Мені цікаво, чому вони взагалі включали б їх string = string.replace(/\r\n/g,"\n");, лол Це як "о, давайте кодувати цей рядок, але по-перше, чому б ми просто безладно не нормалізували всі розриви рядків без поважних причин". Це абсолютно слід вилучати з класу за будь-яких обставин.
Трайнко

2
Я не гуру JavaScript, але, схоже, цей код містить помилку: якщо chr2 - NaN, його значення все ще використовується у виписці enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);. У моєму браузері це працює нормально, NaN>>4дорівнює 0, але я не знаю, чи роблять це всі браузери (також NaN/16дорівнює 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!"

Крос-браузер

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


з Node.js

Ось як ви кодуєте звичайний текст до base64 в 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');

І ось як ви декодуєте рядки, закодовані base64:

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

з Dojo.js

Для кодування масиву байтів за допомогою dojox.encoding.base64:

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

Для розшифровки рядка, кодованого base64:

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

установка котла кутова-основа64

<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=');
}]);

3
Ця відповідь заснована на оригінальному коді і НЕ включає оновлення цього коду, розміщені в інших відповідях тут.
Євген Рябцев

Пропоноване рішення NodeJS застаріло.
Володимир Нул

94

Код Солні чудовий за винятком того, що він порушується в IE7 через посилання на "це". Виправлено шляхом заміни таких посилань на "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;
}
}

4
ой моє погано, я брав дані з URL-адреси браузера; де | перетворюється на% 7C; отже, кодування також неправильне.
Канагавелу Сугумар

Я знаю, що це насправді старе, але я бачив, що ця функція використовується більше ніж в одному місці, ключовий рядок насправді на 65 символів, а не в 64. Рядок не є стандартною специфікацією, я не впевнений, що це має значення, але просто цікаво якщо так?
Джонатан Вагнер

"використовувати суворо"; це те, що ламає "це" та інші елементи типу, як "з", і з того, що я прочитав, "eval" отримує удар. Всі неправильні ідеї щодо зловживань. Особисто я не бачу, чому JavaScript повинен спускатись по маршруту, який він проходить, це ніколи не мало бути програмою, яка була тісно пов'язана і була складнішою, ніж це вже є. Якщо ви хочете бути пов'язаними, тоді зробіть компілятор для javascript.
Марк Гіблін

Я намагаюся використовувати цю функцію, і я отримую помилку: Викликано: org.mozilla.javascript.EcmaError: TypeError: Неможливо знайти функцію заміни в об'єкті teste teste teste Я намагаюся кодувати .txt "teste teste teste". Хтось знає, чому ця помилка?
PRVS

@JonathanWagner - для нормального кодування використовується 64 символи. 65-й ​​символ використовується як доповнення їх. Вхідний рядок не має кількості символів, розділених на 3.
Kickstart

90

Ви можете використовувати btoa(до бази-64) іatob (від бази-64).

Для IE 9 і нижче спробуйте плагін jquery-base64 :

$.base64.encode("this is a test");
$.base64.decode("dGhpcyBpcyBhIHRlc3Q=");

133
Чому все має бути плагіном jQuery: c це лише основна функціональність JavaScript, це не має нічого спільного з DOM або jQuery
EaterOfCode

38
Це не основна функціональність, або не було б стільки різних відповідей на високий рівень голосування (в тому числі виконайте сам tl; dr код). Отже, imho це насправді хороший випадок використання jQuery (один вкладиш, який, як очікується, працюватиме навіть в WebView Android) - ще більше, якщо це вже залежність.
Risadinha

1
Мені подобається встановлювати подібні фрагменти коду в jQuery головним чином тому, що вони існуватимуть у контрольованому просторі імен. Якщо ви не використовуєте AMD, CommonJS або подібну схему дизайну, у вашому глобальному просторі імен дуже просто заплутатися з купою випадкових функцій.
sffc

9
@Risadinha - за винятком того, що його функціональність взагалі не залежить і не розширює jQuery ... буквально єдиними посиланнями на jQuery в його коді є приєднання його до об'єкта jQuery ... тож який сенс приєднувати його до jQuery і тому вимагає jQuery використовувати? Просто зробіть це власним 1 вкладишем base64.encode(...)і base64.decode(...)... приєднувати його до jQuery, коли він має нульовий функціонал jQuery, абсолютно не має сенсу ...
Jimbo Jonny

1
jQuery не запитували. Неправильна відповідь на просте старе питання JS.
metaColin

34

З коментарів (SET і Стефана Штайгера) нижче прийнятої відповіді, ось короткий підсумок того, як кодувати / декодувати рядок до / з base64 без необхідності бібліотеки.

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

Демо

(використовує бібліотеку jQuery, але не для кодування / декодування)


Для підтвердження, це підтримує символи UTF-8?
Crashalot

1
@Crashalot Я розумію, що це на два роки пізно, але так, це так. Я також просто розумію, коли я набираю це, що ви надали редагування, яке, можливо, зробило роботу UTF8.
tycrek

Для всіх, хто шукає хорошого рішення для використання з Node.js, я можу підтвердити це. Для розшифровки в Node я використав:Buffer.from(b64data, 'base64').toString();
tycrek

26

В обох реалізаціях системи є кілька помилок _utf8_decode. c1і c2присвоюються як глобальні змінні через порушення роботи varоператора таc3 взагалі не ініціалізуються або декларуються.

Це працює, але ці змінні замінять усі існуючі з тим самим іменем поза цією функцією.

Ось версія, яка цього не зробить:

// 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;
}

9
@Daan У мене не вистачало представників, щоб редагувати відповіді, коли я писав цю відповідь ... в 2011 році
грабує

2
IE7? я думаю, ми повинні перестати витрачати час на написання коду для цього, люди не перестануть використовувати цю стару технологію, якщо ми не змусили їх розробників!
Рамі Дабайн

@RonanDejhero це не працює в IE7? Я не пам’ятаю, чи тестував я в цьому конкретному браузері.
грабує

1
Що я мав на увазі, що якщо він не працює в IE7, ніхто не повинен хвилюватись !. я не
тестував

16

Я відповів +1 +1 Соні, але хотів внести кілька змін, які я вніс для власного проекту, якщо хтось вважатиме це корисним. В основному я трохи очистив оригінальний код, щоб JSLint не скаржився так сильно, і я зробив методи, відмічені як приватні, в коментарях насправді приватними. Я також додав два потрібні мені методи у власному проекті, а саме decodeToHexі encodeFromHex.

Код:

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
    };
}());

Спочатку я вважав, що ваше розкручування вихідного конкатенації в окремі оператори буде більш оптимальним, але після того, як я подумав про це на секунду, це повинно бути більш неефективним, оскільки рядки Javascript незмінні, і це призведе до 4 копій потенційно величезних крапок даних під час роботи з великими файлами бінарних даних. Безпечніше зробити спочатку об'єднати 4 символи, а потім створити нову струну. Я б хотів, щоб я знав напевно про кращий метод побудови струн, який би впевнений, що він буде ефективним на всіх платформах. (навіть IE6)
Маріус

Я не вважав ефективністю під час очищення оригіналу розміщеного коду. Я просто зробив це більш читабельним і зробив методи, позначені як приватні в коментарях в оригіналі, насправді приватними, використовуючи модель викриття. Я впевнений, що його можна оптимізувати і щодо продуктивності. Не зовсім впевнений, коли тут збирається сміття, і хеширование великих файлів через Javascript не дуже поширене (або, ймовірно, не є оптимальним рішенням у будь-якому випадку).
Joe Dyndale

Смішно, як тут живе цей тип коду. На цій сторінці вже є 3 різні версії.
gregn3

15

Щоб новіші браузери кодували Uint8Array до рядка, а декодували рядок - Uint8Array.

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

Для Node.js ви можете використовувати наступне для кодування рядка, Buffer або Uint8Array до рядка, а декодувати з рядка, Buffer або Uint8Array до Buffer.

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

13

Щоб зробити String URL з кодованою Base64 зручною, у JavaScript ви можете зробити щось подібне:

// 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, '/');

Дивіться також цю скрипку: http://jsfiddle.net/magikMaker/7bjaT/


9
Я покірливо припускаю, що використання програми encodeURIComponentможе призвести до найкращого результату з меншими витратами зусиль з боку розробника.
Пабло Фернандес

11
encodeURIComponent змінить довжину кодованих рядків base64, а заміна '-' та '_' на '+' та '/' є стандартною практикою при використанні base64 в URL-адресах (наприклад, docs.python.org/library/base64.html#base64 .urlsafe_b64encode ). Не потрібно засмучуватися.
natevw

12

Зверніть увагу, що це не підходить для сирих рядків Unicode! Дивіться розділ Unicode тут .

Синтаксис кодування

var encodedData = window.btoa(stringToEncode);

Синтаксис для декодування

var decodedData = window.atob(encodedData);


1
Пряме посилання на розділ unicode: developer.mozilla.org/en-US/docs/Web/API/…
TomTasche

12

Я переписав вручну ці методи кодування та декодування, за винятком шістнадцяткового, у модульний формат для сумісності між платформами та веб-переглядачами, а також з реальним приватним масштабуванням, а також використовує btoaіatob якщо вони існують завдяки швидкості, а не використовувати власне кодування:

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

Використання:

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

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

12

Це питання та його відповіді вказували мене в правильному напрямку.
Особливо з unicode atob і btoa не можна використовувати "ваніль", і в наші дні ВСЕ ВСЕ є unicode ..

Безпосередньо від Mozilla дві приємні функції для цієї мети (тестовані з тегами unicode та html всередині)

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"

Ці функції будуть виконувати блискавично порівняно з необробленим базовим декодуванням 64, використовуючи користувацьку функцію javascript, оскільки btoa та atob виконуються поза інтерпретатором.

Якщо ви можете ігнорувати старі IE та старі мобільні телефони (наприклад, iphone 3?), Це має бути хорошим рішенням.


10

якщо вам потрібно кодувати об’єкт зображення HTML, ви можете написати просту функцію, наприклад:

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
}  

Щоб отримати base64 зображення за допомогою id:

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

більше тут


Так, і var img = новий Зображення (); img.src = "../images/myPic.png";
pdschuller

7

Створюємо мінімізований поліфайл для window.atob+, window.btoaякий я зараз використовую.

(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})})();

6

Я вважаю за краще використовувати методи кодування / декодування bas64 від CryptoJS , найпопулярнішої бібліотеки для стандартних та захищених криптографічних алгоритмів, реалізованих у JavaScript, використовуючи кращі практики та шаблони.


6

Ось версія AngularJS Factory @ користувача 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;
});

6

Мені потрібно кодування рядка UTF-8 як base64 для мого проекту. Більшість відповідей тут, здається, не належним чином обробляють сурогатні пари UTF-16 при переході на UTF-8, тому для завершення я опублікую своє рішення:

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('');
}

Зауважте, що код не ретельно перевірений. Я перевірив деякі вхідні дані, включаючи такі речі, як, наприклад, strToUTF8Base64('衠衢蠩蠨')порівняння з результатами онлайн-інструменту кодування ( https://www.base64encode.org/ ).


5

Для мого проекту мені ще потрібно підтримати IE7 та працювати з великим входом для кодування.

На підставі коду, запропонованого Джо Діндалом та згідно з коментарем Маріуса, можна покращити продуктивність з IE7, побудувавши результат із масивом замість рядка.

Ось приклад для кодування:

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("");
};

5

Якщо ви хочете трохи більше працювати, якщо ви хочете високоякісне нативне рішення, ви можете використовувати деякі функції HTML5.

Якщо ви можете отримати свої дані в a Blob, ви можете скористатися функцією FileReader.readAsDataURL (), щоб отриматиdata:// URL-адресу та порубати її передню частину, щоб отримати дані base64.

Однак вам, можливо, доведеться додатково обробити для urldeкодування даних, оскільки я не впевнений, що +символи не знайшли data://URL-адресу чи ні , але це має бути досить тривіально.


5

Ну, якщо ви використовуєте dojo, це дає нам прямий спосіб кодування або декодування в base64.

Спробуйте це:-

Для кодування масиву байтів за допомогою dojox.encoding.base64:

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

Для розшифровки рядка, кодованого base64:

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

3

Ви можете використовувати window.btoaта window.atob...

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

Можливо, використовуючи спосіб, яким є MDN , можна зробити свою роботу найкраще ... Також приймаючи unicode ..., використовуючи ці дві прості функції:

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

3

Ось ЖИВИЙ DEMO з atob()і btoa()JS вбудованих функцій:

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

2

Використовуйте бібліотеку js-base64 як

btoa () не працює з емоджи

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/js-base64@2.5.2/base64.min.js"></script>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.