Ottieni dati di file con codifica Base64 dal modulo di input


100

Ho un modulo HTML di base da cui posso prendere un po 'di informazioni che sto esaminando in Firebug.

Il mio unico problema è che sto cercando di codificare in base64 i dati del file prima che vengano inviati al server in cui è necessario che siano in quella forma per essere salvati nel database.

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

E in Javascript + jQuery:

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

Ho alcune operazioni basate su javascript disponibile: .getAsBinary (), .getAsText (), .getAsTextURL

Tuttavia, nessuno di questi restituisce testo utilizzabile che può essere inserito in quanto contengono "caratteri" inutilizzabili : non voglio che si verifichi un "postback" nel mio file caricato e ho bisogno di avere più moduli mirati a oggetti specifici, quindi è importante che io ottenere il file e utilizzare Javascript in questo modo.

Come dovrei ottenere il file in modo tale da poter utilizzare uno degli encoder Javascript base64 che sono ampiamente disponibili !?

Grazie

Aggiornamento - A partire da Bounty qui, è necessario il supporto cross browser !!!

Ecco dove mi trovo:

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

Un paio di problemi con il supporto cross browser:

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

Inoltre, IE non supporta:

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

Quindi devo sostituire con:

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

Per supporto IE.

Funziona in Firefox, Chrome e Safari (ma non codifica correttamente il file, o almeno dopo che è stato pubblicato il file non esce correttamente)

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

Anche,

file.readAsArrayBuffer() 

Sembra essere supportato solo in HTML5?

Molte persone hanno suggerito: http://www.webtoolkit.info/javascript-base64.html

Ma questo restituisce solo un errore sul metodo UTF_8 prima che codifichi base64? (o una stringa vuota)

var encoded = Base64.encode(file); 

Cosa stai caricando? Dati di testo o binari?
beatgammit

@tjamenson binary data - qualsiasi cosa realmente 'documento word' 'pdf' 'immagine' ecc. Stavo per assegnare il nome del file in un'altra variabile ma ho iniziato a chiedermi se avessi qualche difetto fatale nella mia comprensione di cosa è possibile fare con caricare moduli e html: questo metodo è totalmente impossibile e non è possibile trasmettere i dati dei file pubblicandoli come stringa? Anche senza HTML5 che sto leggendo ha alcune soluzioni -
jordan.baucke

Interessante. Perché stai codificando in base 64 tra browser e server e stai tentando di farlo nel browser? Sembra che se stai cercando di proteggere i dati, SSL sarebbe molto più semplice in quanto crittografa tutti i dati HTTP (inclusi i file) in rete., E potresti lato server base 64, se necessario per il tuo database.
William Walseth

@ William non sto cercando di proteggere i dati, basta portarli nel formato corretto. Salesforce.com (piattaforma Apex) richiede che il database sia codificato in base64 prima che il record venga creato nel database, la loro funzionalità per codificare i dati del file in base64 tramite un modulo è molto scarsamente documentata (ho capito come farlo dopo aver posto questa domanda). Ad ogni modo, sembra che i dati dei file binari con codifica base64 siano supportati nativamente solo in HTML5 o Mozilla File API
jordan.baucke

1
OK, ora capisco perché ne hai bisogno. Nessun server intermedio + requisiti cloud folli + nessuna soluzione cross browser = 1 pasticcio. Scusate.
William Walseth

Risposte:


121

È del tutto possibile in javascript lato browser.

Il modo più semplice:

Il metodo readAsDataURL () potrebbe già codificarlo come base64 per te. Probabilmente dovrai eliminare le cose iniziali (fino alla prima), ma non è un problema. Questo però eliminerebbe tutto il divertimento.

Il modo più duro:

Se vuoi provarlo nel modo più duro (o non funziona), guarda readAsArrayBuffer(). Questo ti darà un Uint8Array e potrai usare il metodo specificato. Questo è probabilmente utile solo se vuoi fare confusione con i dati stessi, come manipolare i dati dell'immagine o fare altre magie voodoo prima del caricamento.

Esistono due metodi:

  • Converti in stringa e usa il built-in btoao simili
    • Non ho testato tutti i casi, ma funziona per me: ottieni solo i codici di caratteri
  • Converti direttamente da un Uint8Array a base64

Recentemente ho implementato tar nel browser . Come parte di quel processo, ho creato la mia implementazione diretta di Uint8Array-> base64. Non credo che ne avrai bisogno, ma è qui se vuoi dare un'occhiata; è abbastanza pulito.

Cosa faccio ora:

Il codice per la conversione in stringa da un Uint8Array è piuttosto semplice (dove buf è un 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;
}

Da lì, basta fare:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64 ora sarà una stringa con codifica base64 e dovrebbe caricare solo peachy. Prova questo se vuoi ricontrollare prima di premere:

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

Questo lo scaricherà come file.

Altre informazioni:

Per ottenere i dati come Uint8Array, guarda i documenti MDN:


fantastico - ho pensato di readAsArrayBuffer()produrre quelli che sembravano dati base64 corretti , ma non è stato elaborato a causa della parte di elemosina della stringa - ci proverò ora!
jordan.baucke

1
readAsArrayBuffer () non sembra esistere in Chrome / Safari e presumo che sarà problematico in altri browser ~ esiste un equivalente che posso usare in questi altri browser?
jordan.baucke

createObjectURL () <- questo sembra promettente cercherò di implementarlo, ma sono sicuro che IE avrà bisogno di una terza ruota
jordan.baucke

È possibile assegnare un nome file prima di eseguire la soluzione di download?
Ωmega

@ Ωmega - No. Tutto ciò che fa è scaricare un flusso binario. Non c'è modo (AFAIK) per specificare un nome di file. Alcuni browser però ipotizzano un'estensione. Per ottenere i nomi dei file, dovrai caricarli e poi scaricarli di nuovo.
beatgammit

38

La mia soluzione era l'uso readAsBinaryString()e btoa()il suo risultato.

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

3
Di gran lunga il modo più semplice, perché questo non ha più voti?
sarink

14

Ho usato FileReader per visualizzare l'immagine al clic del pulsante di caricamento del file senza utilizzare alcuna richiesta Ajax. Di seguito è riportato il codice che spero possa aiutare qualcuno.

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

1

Dopo aver lottato da solo con questo, sono arrivato a implementare FileReader per i browser che lo supportano (Chrome, Firefox e Safari 6 non ancora rilasciato) e uno script PHP che riecheggia i dati dei file POST come dati codificati Base64 per l'altro browser.


0

Ho iniziato a pensare che l'utilizzo di "iframe" per il caricamento in stile Ajax potrebbe essere una scelta molto migliore per la mia situazione fino a quando HTML5 non tornerà al punto di partenza e non dovrò supportare i browser legacy nella mia app!


Sono solo curioso, perché non prendi [ webtoolkit.info/javascript-base64.html#] , quindi commenta input = Base64._utf8_encode(input);e output = Base64._utf8_decode(output);? Qualche problema diverso dall'errore di conversione utf-8?
shr

@shr non so come prendere i dati del file binario per l'input in questi metodi in ogni browser? $('#inputid').files[0](non funziona in IE7, per quanto ne so ). Se fosse così facile? var output = Base64.encode($('#inputid').files[0])??
jordan.baucke

0

Ispirato dalla risposta di @ 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.