Holen Sie sich Base64-Codierungsdateidaten aus dem Eingabeformular

100

Ich habe ein einfaches HTML-Formular, aus dem ich einige Informationen abrufen kann, die ich in Firebug untersuche.

Mein einziges Problem ist, dass ich versuche, die Dateidaten mit base64 zu codieren, bevor sie an den Server gesendet werden, auf dem sie in dieser Form vorliegen müssen, um in der Datenbank gespeichert zu werden.

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

Und in Javascript + jQuery:

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

Ich habe einige Operationen, die auf verfügbarem Javascript basieren: .getAsBinary (), .getAsText (), .getAsTextURL

Keiner dieser Texte gibt jedoch verwendbaren Text zurück, der eingefügt werden kann, da er unbrauchbare "Zeichen" enthält. Ich möchte nicht, dass in meiner Datei ein "Postback" auftritt, und ich muss mehrere Formulare für bestimmte Objekte haben, daher ist es wichtig, dass ich Holen Sie sich die Datei und verwenden Sie Javascript auf diese Weise.

Wie soll ich die Datei so erhalten, dass ich einen der weit verbreiteten Javascript base64-Encoder verwenden kann?

Vielen Dank

Update - Start Bounty hier, brauche Cross-Browser-Unterstützung !!!

Hier bin ich:

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

Einige Probleme mit der Cross-Browser-Unterstützung:

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

Außerdem unterstützt IE nicht:

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

Also muss ich ersetzen durch:

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

Für IE-Unterstützung.

Dies funktioniert in Firefox, Chrome und Safari (aber die Datei wird nicht richtig codiert, oder zumindest nach dem Posten wird die Datei nicht richtig ausgegeben).

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

Ebenfalls,

file.readAsArrayBuffer() 

Scheint nur in HTML5 unterstützt zu werden?

Viele Leute schlugen vor: http://www.webtoolkit.info/javascript-base64.html

Dies gibt jedoch nur einen Fehler bei der UTF_8-Methode zurück, bevor sie von base64 codiert wird. (oder eine leere Zeichenfolge)

var encoded = Base64.encode(file); 
jordan.baucke
quelle
Was lädst du hoch? Textdaten oder Binärdaten?
Beatgammit
@tjamenson Binärdaten - alles, was wirklich "Word-Dokument", "PDF", "Bild" usw. ist. Ich wollte den Dateinamen in einer anderen Variablen zuweisen, aber ich begann mich zu fragen, ob ich einen schwerwiegenden Fehler in meinem Verständnis hatte, was mit möglich ist Formulare und HTML hochladen - ist diese Methode überhaupt nicht möglich und es ist nicht möglich, Dateidaten zu übertragen, indem sie als Zeichenfolge veröffentlicht werden? Auch ohne HTML5, das ich lese, gibt es einige Lösungen -
jordan.baucke
Interessant. Warum codieren Sie Base-64 zwischen Browser und Server und versuchen dies im Browser zu erreichen? Wenn Sie versuchen, die Daten zu sichern, scheint SSL viel einfacher zu sein, da alle HTTP-Daten (einschließlich Dateien) über das Kabel verschlüsselt werden. Bei Bedarf können Sie die Basis-64-Serverseite für Ihre Datenbank verwenden.
William Walseth
@William Ich versuche nicht, die Daten zu sichern, sondern bringe sie einfach in das richtige Format. Salesforce.com (Apex-Plattform) erfordert, dass die Datenbank base64-codiert ist, bevor der Datensatz in der Datenbank erstellt wird. Ihre Funktionalität zum Base64-Codieren von Dateidaten über ein Formular ist sehr schlecht dokumentiert (ich habe herausgefunden, wie dies zu tun ist, nachdem ich diese Frage gestellt habe). Wie auch immer, es sieht so aus, als würden Base64-codierende Binärdateidaten nur nativ in HTML5 oder der Mozilla File API unterstützt
jordan.baucke
1
OK, jetzt verstehe ich, warum du das brauchst. Kein Zwischenserver + verrückte Cloud-Anforderungen + keine browserübergreifende Lösung = 1 Durcheinander. Es tut uns leid.
William Walseth

Antworten:

121

In browser-seitigem Javascript ist dies durchaus möglich.

Der einfache Weg:

Die Methode readAsDataURL () codiert sie möglicherweise bereits als base64 für Sie. Sie müssen wahrscheinlich das Anfangsmaterial (bis zum ersten) entfernen, aber das ist kein Problem. Dies würde jedoch den ganzen Spaß nehmen.

Der harte Weg:

Wenn Sie es auf die harte Tour versuchen möchten (oder es funktioniert nicht), schauen Sie sich an readAsArrayBuffer(). Dadurch erhalten Sie ein Uint8Array und können die angegebene Methode verwenden. Dies ist wahrscheinlich nur dann nützlich, wenn Sie mit den Daten selbst herumspielen möchten, z. B. Bilddaten bearbeiten oder andere Voodoo-Magie ausführen möchten, bevor Sie sie hochladen.

Es gibt zwei Methoden:

  • In Zeichenfolge konvertieren und die integrierte btoaoder ähnliche verwenden
    • Ich habe nicht alle Fälle getestet, aber es funktioniert für mich - holen Sie sich einfach die Zeichencodes
  • Konvertieren Sie direkt von einem Uint8Array in base64

Ich habe kürzlich tar im Browser implementiert . Als Teil dieses Prozesses habe ich meine eigene direkte Uint8Array-> base64-Implementierung erstellt. Ich glaube nicht, dass du das brauchst, aber es ist hier, wenn du einen Blick darauf werfen willst. es ist ziemlich ordentlich.

Was mache ich nun:

Der Code zum Konvertieren von einem Uint8Array in einen String ist ziemlich einfach (wobei buf ein Uint8Array ist):

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

Von dort aus machen Sie einfach:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64 ist jetzt eine Base64-codierte Zeichenfolge und sollte nur pfirsichfarben hochgeladen werden. Versuchen Sie dies, wenn Sie dies vor dem Drücken überprüfen möchten:

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

Dadurch wird es als Datei heruntergeladen.

Andere Information:

Informationen zum Abrufen der Daten als Uint8Array finden Sie in den MDN-Dokumenten:

Beatgammit
quelle
großartig - ich dachte, ich würde etwas readAsArrayBuffer()ausgeben, das wie korrekte base64- Daten aussieht , aber es würde wegen des bettelnden Teils der Zeichenfolge nicht verarbeitet werden - ich werde es jetzt versuchen!
Jordan.baucke
1
readAsArrayBuffer () scheint in Chrome / Safari nicht zu existieren und ich gehe davon aus, dass dies in anderen Browsern problematisch sein wird. Gibt es ein Äquivalent, das ich in diesen anderen Browsern verwenden kann?
Jordan.baucke
createObjectURL () <- das sieht vielversprechend aus Ich werde versuchen, es zu implementieren, aber ich bin sicher, IE wird ein
drittes
Ist es möglich, einen Dateinamen zuzuweisen, bevor Sie Ihre Download-Lösung ausführen?
Ωmega
@ Ωmega - Nein. Sie müssen lediglich einen Binär-Stream herunterladen. Es gibt keine Möglichkeit (AFAIK), einen Dateinamen anzugeben. Einige Browser vermuten jedoch eine Erweiterung. Um Dateinamen zu erhalten, müssen Sie diese hochladen und erneut herunterladen.
Beatgammit
37

Meine Lösung war die Verwendung readAsBinaryString()und btoa()das Ergebnis.

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
quelle
3
Bei weitem der einfachste Weg, warum hat dies nicht mehr Stimmen?
Sarink
14

Ich habe FileReader verwendet, um Bilder beim Klicken auf die Schaltfläche zum Hochladen von Dateien anzuzeigen, ohne Ajax-Anforderungen zu verwenden. Es folgt der Code, der hoffentlich jemandem helfen kann.

$(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
quelle
1

Nachdem ich selbst damit zu kämpfen hatte, implementierte ich FileReader für Browser, die dies unterstützen (Chrome, Firefox und das bisher unveröffentlichte Safari 6), und ein PHP-Skript, das POST-Dateidaten als Base64-codierte Daten für die anderen wiedergibt Browser.

Chris Nolet
quelle
0

Ich habe angefangen zu denken, dass die Verwendung des 'iframe' für das Hochladen im Ajax-Stil eine viel bessere Wahl für meine Situation sein könnte, bis sich der Kreis von HTML5 schließt und ich keine älteren Browser in meiner App unterstützen muss!

jordan.baucke
quelle
Nur neugierig, warum nimmst du nicht einfach [ webtoolkit.info/javascript-base64.html#] und kommentierst dann input = Base64._utf8_encode(input);und aus output = Base64._utf8_decode(output);? Gibt es ein anderes Problem als den Konvertierungsfehler von utf-8?
Shr
@shr Ich weiß nicht, wie ich die Binärdateidaten für die Eingabe in diese Methoden in jedem Browser abrufen soll. $('#inputid').files[0](funktioniert in IE7 nicht, soweit ich das beurteilen kann ). Wenn es so einfach wäre? var output = Base64.encode($('#inputid').files[0])??
Jordan.baucke
0

Inspiriert von @ Josefs Antwort:

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
quelle