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.