Pobierz dane pliku kodujące Base64 z formularza wejściowego


100

Mam podstawowy formularz HTML, z którego mogę pobrać trochę informacji, które badam w Firebug.

Moim jedynym problemem jest to, że próbuję kodować base64 dane pliku, zanim zostaną wysłane na serwer, gdzie wymagane jest, aby były w tej formie, aby zostały zapisane w bazie danych.

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

A w Javascript + jQuery:

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

Mam kilka operacji opartych na dostępnym javascript: .getAsBinary (), .getAsText (), .getAsTextURL

Jednak żaden z tych zwrotów nie zwraca użytecznego tekstu, który można wstawić, ponieważ zawierają bezużyteczne `` znaki '' - nie chcę, aby w przesłanym pliku pojawiało się `` ogłaszanie zwrotne '' i potrzebuję wielu formularzy dotyczących określonych obiektów, więc jest to ważne. pobierz plik i użyj w ten sposób Javascript.

Jak mam pobrać plik w taki sposób, żebym mógł użyć jednego z powszechnie dostępnych koderów Javascript base64 !?

Dzięki

Aktualizacja - Zaczynam bounty tutaj, potrzebna jest obsługa wielu przeglądarek !!!

Tutaj jestem:

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

Kilka problemów z obsługą wielu przeglądarek:

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

Ponadto IE nie obsługuje:

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

Więc muszę zamienić na:

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

Wsparcie dla IE.

Działa to w Firefoksie, Chrome i Safari (ale nie koduje poprawnie pliku lub przynajmniej po jego opublikowaniu plik nie wychodzi poprawnie)

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

Również,

file.readAsArrayBuffer() 

Wydaje się, że jest obsługiwany tylko w HTML5?

Wiele osób zasugerowało: http://www.webtoolkit.info/javascript-base64.html

Ale to zwraca tylko błąd en w metodzie UTF_8 przed kodowaniem base64? (lub pusty ciąg)

var encoded = Base64.encode(file); 

Co przesyłasz? Dane tekstowe czy binarne?
beatgammit

@tjamenson binary data - cokolwiek naprawdę „dokument słowny” „pdf” „obraz” itd. Chciałem przypisać nazwę pliku w innej zmiennej, ale zacząłem się zastanawiać, czy nie mam jakiejś fatalnej usterki w zrozumieniu tego, co jest możliwe z przesyłanie formularzy i html - czy ta metoda jest całkowicie niewykonalna i nie jest możliwe przesłanie danych pliku poprzez przesłanie ich w postaci ciągu? Również bez HTML5, który czytam, ma kilka rozwiązań -
jordan.baucke

Ciekawy. Dlaczego używasz kodowania base-64 między przeglądarką a serwerem i próbujesz to osiągnąć w przeglądarce? Wygląda na to, że jeśli próbujesz zabezpieczyć dane, SSL byłby znacznie łatwiejszy, ponieważ szyfruje wszystkie dane HTTP (w tym pliki) przez sieć, i możesz po stronie serwera base-64, jeśli jest to konieczne dla twojej bazy danych.
William Walseth

@William Nie próbuję zabezpieczyć danych, po prostu sprowadzam je do odpowiedniego formatu. Salesforce.com (platforma Apex) wymaga, aby baza danych była zakodowana w base64 przed utworzeniem rekordu w bazie danych, ich funkcjonalność do kodowania plików base64 za pośrednictwem formularza jest bardzo słabo udokumentowana (po zadaniu tego pytania dowiedziałem się, jak to zrobić). W każdym razie wygląda na to, że dane pliku binarnego z kodowaniem base64 są obsługiwane natywnie tylko w HTML5 lub Mozilla File API
jordan.baucke

1
OK, teraz rozumiem, dlaczego tego potrzebujesz. Brak serwera pośredniego + szalone wymagania dotyczące chmury + brak rozwiązania dla wielu przeglądarek = 1 bałagan. Przepraszam.
William Walseth,

Odpowiedzi:


121

Jest to całkowicie możliwe w javascript po stronie przeglądarki.

Łatwa droga:

Metoda readAsDataURL () może już zakodować ją jako base64. Prawdopodobnie będziesz musiał usunąć początkowe elementy (do pierwszego), ale to nic wielkiego. To jednak pozbawiłoby całą zabawę.

Trudna droga:

Jeśli chcesz spróbować na własnej skórze (lub nie działa), spójrz na readAsArrayBuffer(). To da ci Uint8Array i możesz użyć określonej metody. Jest to prawdopodobnie przydatne tylko wtedy, gdy chcesz zepsuć same dane, na przykład manipulując danymi obrazu lub wykonując inną magię voodoo przed przesłaniem.

Istnieją dwie metody:

  • Konwertuj na ciąg i użyj wbudowanego btoalub podobnego
    • Nie przetestowałem wszystkich przypadków, ale działa dla mnie - po prostu pobierz kody znaków
  • Konwertuj bezpośrednio z Uint8Array na base64

Niedawno zaimplementowałem tar w przeglądarce . W ramach tego procesu wykonałem własną bezpośrednią implementację Uint8Array-> base64. Myślę, że nie będziesz tego potrzebować, ale jest tutaj, jeśli chcesz rzucić okiem; jest całkiem schludny.

Co ja teraz robię:

Kod konwersji na ciąg znaków z Uint8Array jest dość prosty (gdzie buf to 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;
}

Stamtąd po prostu wykonaj:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64 będzie teraz ciągiem zakodowanym w base64 i powinien załadować tylko peachy. Spróbuj tego, jeśli chcesz dwukrotnie sprawdzić przed naciśnięciem:

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

Spowoduje to pobranie go jako pliku.

Pozostałe informacje:

Aby uzyskać dane jako Uint8Array, spójrz na dokumentację MDN:


świetnie - pomyślałem, że readAsArrayBuffer()dane wyjściowe wyglądały na poprawne dane base64 , ale nie zostałyby przetworzone z powodu początkowej części ciągu - teraz zrobię to!
jordan.baucke

1
Wydaje się, że readAsArrayBuffer () nie istnieje w Chrome / Safari i przypuszczam, że będzie to problematyczne w innych przeglądarkach ~ czy istnieje odpowiednik, którego mogę użyć w innych przeglądarkach?
jordan.baucke

createObjectURL () <- wygląda to obiecująco. Spróbuję to zaimplementować, ale jestem pewien, że IE będzie potrzebować trzeciego koła
jordan.baucke

Czy można przypisać nazwę pliku przed uruchomieniem rozwiązania do pobierania?
Ωmega,

@ Ωmega - Nie. Wszystko to polega na pobieraniu strumienia binarnego. Nie ma sposobu (AFAIK), aby określić nazwę pliku. Jednak niektóre przeglądarki odgadują rozszerzenie. Aby uzyskać nazwy plików, musisz przesłać, a następnie pobrać ponownie.
beatgammit,

38

Moje rozwiązanie polegało na użyciu readAsBinaryString()i btoa()na jego wyniku.

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
Zdecydowanie najłatwiej, dlaczego to nie daje większej liczby głosów?
sarink

14

Użyłem FileReader do wyświetlenia obrazu po kliknięciu przycisku przesyłania pliku bez użycia żadnych żądań Ajax. Poniżej znajduje się kod, który mam nadzieję, że może komuś pomóc.

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

Po tym, jak sam się z tym zmagałem, zacząłem implementować FileReader dla przeglądarek, które go obsługują (Chrome, Firefox i jeszcze niewydane Safari 6), a także skrypt PHP, który odbija dane pliku POST jako dane zakodowane w Base64 dla innych przeglądarki.


0

Zacząłem myśleć, że użycie „iframe” do przesyłania w stylu Ajax może być znacznie lepszym wyborem w mojej sytuacji, dopóki HTML5 nie zatoczy pełnego koła i nie będę musiał obsługiwać starszych przeglądarek w mojej aplikacji!


Ciekawe, dlaczego nie weźmiesz po prostu [ webtoolkit.info/javascript-base64.html#] , a potem skomentujesz input = Base64._utf8_encode(input);i output = Base64._utf8_decode(output);? Każdy problem inny niż błąd konwersji utf-8?
SHR

@shr Nie wiem, jak pobrać dane pliku binarnego do wprowadzenia do tych metod w każdej przeglądarce? $('#inputid').files[0]( o ile wiem, nie działa w IE7 ). Gdyby to było takie proste? var output = Base64.encode($('#inputid').files[0])??
jordan.baucke

0

Zainspirowany odpowiedzią @ Josefa:

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)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.