Dapatkan Base64 menyandikan file-data dari Formulir Input

100

Saya memiliki formulir HTML dasar yang darinya saya dapat mengambil sedikit informasi yang saya periksa di Firebug.

Satu-satunya masalah saya adalah saya mencoba untuk menyandikan base64 data file sebelum dikirim ke server di mana itu harus dalam bentuk itu untuk disimpan ke database.

<input type="file" id="fileupload" />

Dan di Javascript + jQuery:

var file = $('#fileupload').attr("files")[0];

Saya memiliki beberapa operasi berdasarkan javascript yang tersedia: .getAsBinary (), .getAsText (), .getAsTextURL

Namun tidak satu pun dari teks yang dapat digunakan kembali ini yang dapat dimasukkan karena mengandung 'karakter' yang tidak dapat digunakan - Saya tidak ingin terjadi 'postback' di file saya yang diunggah, dan saya perlu memiliki beberapa formulir yang menargetkan objek tertentu jadi penting bagi saya dapatkan file dan gunakan Javascript dengan cara ini.

Bagaimana cara mendapatkan file sedemikian rupa sehingga saya dapat menggunakan salah satu pembuat enkode Javascript base64 yang tersedia secara luas !?

Terima kasih

Perbarui - Mulai bounty di sini, perlu dukungan lintas browser !!!

Di sinilah saya berada:

<input type="file" id="fileuploadform" />

<script type="text/javascript">
var uploadformid = 'fileuploadform';
var uploadform = document.getElementById(uploadformid);


/* method to fetch and encode specific file here based on different browsers */

</script>

Beberapa masalah dengan dukungan lintas browser:

var file = $j(fileUpload.toString()).attr('files')[0];
fileBody = file.getAsDataURL(); // only would works in Firefox

Selain itu, IE tidak mendukung:

var file = $j(fileUpload.toString()).attr('files')[0];

Jadi saya harus mengganti dengan:

var element = 'id';
var element = document.getElementById(id);

Untuk Dukungan IE.

Ini berfungsi di Firefox, Chrome dan, Safari (tetapi tidak menyandikan file dengan benar, atau setidaknya setelah diposting, file tidak keluar dengan benar)

var file = $j(fileUpload.toString()).attr('files')[0];
var encoded = Btoa(file);

Juga,

file.readAsArrayBuffer() 

Sepertinya hanya didukung di HTML5?

Banyak orang menyarankan: http://www.webtoolkit.info/javascript-base64.html

Tapi ini hanya mengembalikan kesalahan en pada metode UTF_8 sebelum base64 mengkodekan? (atau string kosong)

var encoded = Base64.encode(file); 
jordan.baucke
sumber
Apa yang kamu upload Data teks atau biner?
beatgammit
@tjamenson binary data - apa pun yang benar-benar 'dokumen kata' 'pdf' 'gambar' dll. Saya akan menetapkan nama file di variabel lain tetapi saya mulai bertanya-tanya apakah saya memiliki beberapa kesalahan fatal dalam pemahaman saya tentang apa yang mungkin dilakukan dengan unggah formulir dan html - apakah metode ini benar-benar tidak dapat dilakukan dan tidak mungkin mengirimkan data file melalui mempostingnya sebagai string? Juga tanpa HTML5 yang saya baca memiliki beberapa solusi -
jordan.baucke
Menarik. Mengapa Anda melakukan pengkodean base-64 antara browser dan server, dan mencoba melakukannya di browser? Sepertinya jika Anda mencoba untuk mengamankan data, SSL akan jauh lebih mudah karena mengenkripsi semua data HTTP (termasuk file) melalui kabel., Dan Anda dapat melakukan sisi server base-64, jika perlu untuk database Anda.
William Walseth
@William Saya tidak mencoba mengamankan data, cukup kirimkan ke format yang benar. Salesforce.com (platform Apex) memerlukan database base64-encoded sebelum rekaman dibuat dalam database, fungsinya untuk menyandikan data file base64 melalui formulir didokumentasikan dengan sangat buruk (saya menemukan cara melakukan ini setelah menanyakan pertanyaan ini). Bagaimanapun, sepertinya data file biner pengkodean base64 hanya didukung secara native di HTML5 atau Mozilla File API
jordan.baucke
1
Oke, sekarang saya mengerti mengapa Anda membutuhkan ini. Tidak ada server perantara + persyaratan cloud yang gila + tidak ada solusi lintas browser = 1 kekacauan. Maaf.
William Walseth

Jawaban:

121

Ini sepenuhnya mungkin dalam javascript sisi browser.

Cara mudahnya:

Metode readAsDataURL () mungkin sudah mengenkodekannya sebagai base64 untuk Anda. Anda mungkin perlu menghapus hal-hal awal (hingga yang pertama,), tetapi itu bukan masalah besar. Ini akan menghilangkan semua kesenangan.

Cara yang sulit:

Jika Anda ingin mencobanya dengan cara yang sulit (atau tidak berhasil), lihat readAsArrayBuffer(). Ini akan memberi Anda Uint8Array dan Anda dapat menggunakan metode yang ditentukan. Ini mungkin hanya berguna jika Anda ingin mengacaukan datanya sendiri, seperti memanipulasi data gambar atau melakukan sihir voodoo lainnya sebelum Anda mengunggah.

Ada dua metode:

  • Ubah menjadi string dan gunakan built-in btoaatau serupa
    • Saya belum menguji semua kasus, tetapi bekerja untuk saya - dapatkan saja kode karakternya
  • Konversi langsung dari Uint8Array ke base64

Saya baru-baru ini menerapkan tar di browser . Sebagai bagian dari proses itu, saya membuat implementasi Uint8Array-> langsung saya sendiri. Saya tidak berpikir Anda akan membutuhkannya, tetapi ada di sini jika Anda ingin melihatnya; itu cukup rapi.

Apa yang saya lakukan sekarang:

Kode untuk mengonversi menjadi string dari Uint8Array cukup sederhana (di mana buf adalah Uint8Array):

function uint8ToString(buf) {
    var i, length, out = '';
    for (i = 0, length = buf.length; i < length; i += 1) {
        out += String.fromCharCode(buf[i]);
    }
    return out;
}

Dari sana, lakukan saja:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64 sekarang akan menjadi string berenkode base64, dan seharusnya diupload sangat bagus. Coba ini jika Anda ingin memeriksa ulang sebelum mendorong:

window.open("data:application/octet-stream;base64," + base64);

Ini akan mengunduhnya sebagai file.

Info lain:

Untuk mendapatkan data sebagai Uint8Array, lihat dokumen MDN:

beatgammit
sumber
hebat - Saya pikir readAsArrayBuffer()keluarannya tampak seperti data base64 yang benar , tetapi tidak akan memproses karena bagian yang memohon dari string - Saya akan mencobanya sekarang!
jordan.baucke
1
readAsArrayBuffer () tampaknya tidak ada di Chrome / Safari dan saya berasumsi akan bermasalah di browser lain ~ apakah ada yang setara yang dapat saya gunakan di browser lain ini?
jordan.baucke
createObjectURL () <- ini terlihat menjanjikan. Saya akan mencoba menerapkannya, tetapi saya yakin IE akan membutuhkan roda ke-3
jordan.baucke
Apakah mungkin untuk menetapkan nama file sebelum menjalankan solusi unduhan Anda?
Ωmega
@ Ωmega - Tidak. Yang dilakukannya hanyalah mengunduh aliran biner. Tidak ada cara (AFAIK) untuk menentukan nama file. Beberapa browser menebak ekstensi. Untuk mendapatkan nama file, Anda harus mengupload lalu mendownload lagi.
beatgammit
38

Solusi saya adalah menggunakan readAsBinaryString()dan btoa()hasilnya.

uploadFileToServer(event) {
    var file = event.srcElement.files[0];
    console.log(file);
    var reader = new FileReader();
    reader.readAsBinaryString(file);

    reader.onload = function() {
        console.log(btoa(reader.result));
    };
    reader.onerror = function() {
        console.log('there are some problems');
    };
}
Josef
sumber
3
Sejauh ini cara termudah, mengapa ini tidak memiliki lebih banyak suara?
sarink
14

Saya menggunakan FileReader untuk menampilkan gambar dengan mengklik tombol unggah file tidak menggunakan permintaan Ajax. Berikut ini adalah kode berharap itu dapat membantu seseorang.

$(document).ready(function($) {
    $.extend( true, jQuery.fn, {        
        imagePreview: function( options ){          
            var defaults = {};
            if( options ){
                $.extend( true, defaults, options );
            }
            $.each( this, function(){
                var $this = $( this );              
                $this.bind( 'change', function( evt ){

                    var files = evt.target.files; // FileList object
                    // Loop through the FileList and render image files as thumbnails.
                    for (var i = 0, f; f = files[i]; i++) {
                        // Only process image files.
                        if (!f.type.match('image.*')) {
                        continue;
                        }
                        var reader = new FileReader();
                        // Closure to capture the file information.
                        reader.onload = (function(theFile) {
                            return function(e) {
                                // Render thumbnail.
                                    $('#imageURL').attr('src',e.target.result);                         
                            };
                        })(f);
                        // Read in the image file as a data URL.
                        reader.readAsDataURL(f);
                    }

                });
            });
        }   
    });
    $( '#fileinput' ).imagePreview();
});
rozar
sumber
1

Setelah berjuang dengan ini sendiri, saya datang untuk mengimplementasikan FileReader untuk browser yang mendukungnya (Chrome, Firefox dan Safari 6 yang belum dirilis), dan skrip PHP yang menggemakan kembali data file POSTed sebagai data yang dikodekan Base64 untuk yang lain. browser.

Chris Nolet
sumber
0

Saya mulai berpikir bahwa menggunakan 'iframe' untuk pengunggahan gaya Ajax mungkin merupakan pilihan yang jauh lebih baik untuk situasi saya sampai HTML5 menjadi lingkaran penuh dan saya tidak harus mendukung browser lama di aplikasi saya!

jordan.baucke
sumber
Hanya ingin tahu, mengapa Anda tidak mengambil [ webtoolkit.info/javascript-base64.html#] , lalu memberi komentar input = Base64._utf8_encode(input);dan output = Base64._utf8_decode(output);? Ada masalah selain kesalahan konversi utf-8?
Shr
@shr Saya tidak tahu cara mengambil data file biner untuk dimasukkan ke metode ini di setiap browser? $('#inputid').files[0](tidak berfungsi di IE7, sejauh yang saya tahu ). Jika semudah itu? var output = Base64.encode($('#inputid').files[0])??
jordan.baucke
0

Terinspirasi oleh jawaban @ Josef:

const fileToBase64 = async (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => resolve(reader.result)
    reader.onerror = (e) => reject(e)
  })

const file = event.srcElement.files[0];
const imageStr = await fileToBase64(file)
mb21
sumber