Obtenir des données de fichier encodées en Base64 à partir du formulaire d'entrée

100

J'ai un formulaire HTML de base à partir duquel je peux récupérer un peu d'informations que j'examine dans Firebug.

Mon seul problème est que j'essaie d' encoder en base64 les données du fichier avant qu'elles ne soient envoyées au serveur où il est nécessaire d'être sous cette forme pour être enregistrées dans la base de données.

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

Et en Javascript + jQuery:

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

J'ai quelques opérations basées sur javascript disponible: .getAsBinary (), .getAsText (), .getAsTextURL

Cependant, aucun de ceux-ci ne renvoie de texte utilisable qui peut être inséré car ils contiennent des `` caractères '' inutilisables - je ne veux pas qu'un `` postback '' se produise dans mon fichier téléchargé, et j'ai besoin de plusieurs formulaires ciblant des objets spécifiques, il est donc important que je récupérez le fichier et utilisez Javascript de cette façon.

Comment dois-je obtenir le fichier de telle manière que je puisse utiliser l'un des encodeurs Javascript base64 qui sont largement disponibles !?

Merci

Mise à jour - Commencer la prime ici, besoin de la prise en charge de plusieurs navigateurs !!!

Voici où j'en suis:

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

Quelques problèmes avec la prise en charge de plusieurs navigateurs:

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

De plus, IE ne prend pas en charge:

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

Je dois donc remplacer par:

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

Pour le support IE.

Cela fonctionne dans Firefox, Chrome et Safari (mais n'encode pas correctement le fichier, ou du moins après sa publication, le fichier ne sort pas correctement)

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

Aussi,

file.readAsArrayBuffer() 

Semble être pris en charge uniquement en HTML5?

Beaucoup de gens ont suggéré: http://www.webtoolkit.info/javascript-base64.html

Mais cela ne renvoie qu'une erreur sur la méthode UTF_8 avant l'encodage en base64? (ou une chaîne vide)

var encoded = Base64.encode(file); 
jordan.baucke
la source
Qu'est-ce que vous téléchargez? Données textuelles ou binaires?
beatgammit
@tjamenson données binaires - tout ce qui est vraiment 'document Word' 'pdf' 'image' etc. J'allais attribuer le nom de fichier dans une autre variable mais j'ai commencé à me demander si j'avais un défaut fatal dans ma compréhension de ce qui est possible avec télécharger des formulaires et du HTML - cette méthode est-elle totalement impossible et il n'est pas possible de transmettre les données du fichier en les publiant sous forme de chaîne? Aussi sans HTML5 que je lis a quelques solutions -
jordan.baucke
Intéressant. Pourquoi encodez-vous en base 64 entre le navigateur et le serveur et essayez-vous d'accomplir cela dans le navigateur? On dirait que si vous essayez de sécuriser les données, SSL serait beaucoup plus facile car il crypte toutes les données HTTP (y compris les fichiers) sur le fil., Et vous pouvez le côté serveur de base 64, si nécessaire pour votre base de données.
William Walseth
@William Je n'essaye pas de sécuriser les données, il suffit de les mettre au bon format. Salesforce.com (plate-forme Apex) nécessite que la base de données soit encodée en base64 avant que l'enregistrement ne soit créé dans la base de données, leur fonctionnalité pour encoder les données de fichier en base64 via un formulaire est très mal documentée (j'ai compris comment faire cela après avoir posé cette question). Quoi qu'il en soit, il semble que les données de fichier binaire
encodées en
1
OK, maintenant je vois pourquoi vous en avez besoin. Pas de serveur intermédiaire + exigences de cloud folles + pas de solution de navigateur croisé = 1 désordre. Désolé.
William Walseth

Réponses:

121

C'est tout à fait possible en javascript côté navigateur.

Le moyen le plus simple:

La méthode readAsDataURL () peut déjà l'encoder en base64 pour vous. Vous aurez probablement besoin de supprimer le début (jusqu'au premier), mais ce n'est pas grave. Cela enlèverait tout le plaisir.

À la dure:

Si vous voulez l'essayer à la dure (ou cela ne fonctionne pas), regardez readAsArrayBuffer(). Cela vous donnera un Uint8Array et vous pourrez utiliser la méthode spécifiée. Cela n'est probablement utile que si vous voulez manipuler les données elles-mêmes, comme manipuler des données d'image ou faire d'autres magies vaudou avant de les télécharger.

Il existe deux méthodes:

  • Convertir en chaîne et utiliser le intégré btoaou similaire
    • Je n'ai pas testé tous les cas, mais ça marche pour moi - il suffit d'obtenir les char-codes
  • Convertir directement d'un Uint8Array en base64

J'ai récemment implémenté tar dans le navigateur . Dans le cadre de ce processus, j'ai créé ma propre implémentation directe Uint8Array-> base64. Je ne pense pas que vous en aurez besoin, mais c'est ici si vous voulez jeter un coup d'œil; c'est assez soigné.

Ce que je fais maintenant:

Le code de conversion en chaîne à partir d'un Uint8Array est assez simple (où buf est 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;
}

À partir de là, faites simplement:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64 sera désormais une chaîne encodée en base64, et elle ne devrait télécharger que peachy. Essayez ceci si vous voulez revérifier avant d'appuyer:

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

Cela le téléchargera sous forme de fichier.

Autre info:

Pour obtenir les données sous la forme d'un Uint8Array, consultez la documentation MDN:

beatgammit
la source
super - je pensais readAsArrayBuffer()produire ce qui ressemblait à des données base64 correctes , mais cela ne serait pas traité à cause de la partie suppliante de la chaîne - je vais essayer maintenant!
jordan.baucke
1
readAsArrayBuffer () ne semble pas exister dans Chrome / Safari et je suppose que cela posera problème dans d'autres navigateurs ~ y a-t-il un équivalent que je peux utiliser dans ces autres navigateurs?
jordan.baucke
createObjectURL () <- cela semble prometteur, je vais essayer de l'implémenter, mais je suis sûr que IE va avoir besoin d'une 3ème roue
jordan.baucke
Est-il possible d'attribuer un nom de fichier avant d'exécuter votre solution de téléchargement?
Ωmega
@ Ωmega - Non. Tout cela ne fait que télécharger un flux binaire. Il n'y a aucun moyen (AFAIK) de spécifier un nom de fichier. Certains navigateurs devinent cependant une extension. Pour obtenir les noms de fichiers, vous devrez télécharger puis télécharger à nouveau.
beatgammit
38

Ma solution était l'utilisation readAsBinaryString()et btoa()son résultat.

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
la source
3
De loin le moyen le plus simple, pourquoi cela n'a-t-il pas plus de votes?
sarink
14

J'ai utilisé FileReader pour afficher l'image en cliquant sur le bouton de téléchargement de fichier sans utiliser de requêtes Ajax. Voici le code en espérant qu'il pourrait aider quelqu'un.

$(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
la source
1

Après avoir lutté avec cela moi-même, je suis venu implémenter FileReader pour les navigateurs qui le prennent en charge (Chrome, Firefox et Safari 6, encore inédit), et un script PHP qui renvoie les données de fichier POSTed en tant que données encodées en Base64 pour l'autre navigateurs.

Chris Nolet
la source
0

J'ai commencé à penser que l'utilisation de l'iframe pour le téléchargement de style Ajax pourrait être un bien meilleur choix pour ma situation jusqu'à ce que HTML5 arrive à son tour complet et que je n'ai pas à prendre en charge les anciens navigateurs dans mon application!

jordan.baucke
la source
Juste curieux, pourquoi ne pas prendre simplement [ webtoolkit.info/javascript-base64.html#] , puis commenter input = Base64._utf8_encode(input);et output = Base64._utf8_decode(output);? Un problème autre qu'une erreur de conversion utf-8?
shr
@shr Je ne sais pas comment récupérer les données du fichier binaire pour les saisir dans ces méthodes dans chaque navigateur? $('#inputid').files[0](ne fonctionne pas dans IE7, pour autant que je sache ). Si c'était aussi simple que ça? var output = Base64.encode($('#inputid').files[0])??
jordan.baucke
0

Inspiré par la réponse de @ 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
la source