Comment javascript peut-il télécharger un objet blob?

107

J'ai des données blob dans cette structure:

Blob {type: "audio/wav", size: 655404, slice: function}
size: 655404
type: "audio/wav"
__proto__: Blob

Ce sont en fait des données sonores enregistrées à l'aide des récents Chrome getUerMedia()et Recorder.js

Comment puis-je télécharger cet objet blob sur le serveur à l'aide de la méthode de publication de jquery? J'ai essayé ceci sans aucune chance:

   $.post('http://localhost/upload.php', { fname: "test.wav", data: soundBlob }, 
    function(responseText) {
           console.log(responseText);
    });
Yang
la source
1
Vous voudrez peut-être penser à utiliser binaryJS pour cela. Si vous diffusez des données en continu, cela pourrait faire l'affaire.
toxicate20
Cette réponse est également très détaillée. stackoverflow.com/a/8758614/1331430
Fabrício Matté

Réponses:

123

Essaye ça

var fd = new FormData();
fd.append('fname', 'test.wav');
fd.append('data', soundBlob);
$.ajax({
    type: 'POST',
    url: '/upload.php',
    data: fd,
    processData: false,
    contentType: false
}).done(function(data) {
       console.log(data);
});

Vous devez utiliser l' API FormData et définir le jQuery.ajax's processDataet contentTypesur false.

Fabrício Matté
la source
1
Savez-vous comment faire cela sans AJAX aussi?
William Entriken
@FullDecent Que voulez-vous dire? Pour inviter l'utilisateur à télécharger un fichier à l'aide de l'API de fichier? Ou pour simplement stocker le contenu blob?
Fabrício Matté
4
À faire en gros$('input[type=file]').value=blob
William Entriken
14
Les exigences de sécurité empêchent la définition par programmation des valeurs d'entrée de fichier: stackoverflow.com/questions/1696877/…
yeeking
9
Notez qu'un objet blob a un nom de fichier générique lorsqu'il est envoyé au serveur, contrairement à un fichier. Mais vous pouvez spécifier le nom du fichier Blob dans FormData: stackoverflow.com/questions/6664967/...
Sebastien Lorber
20

En fait, vous n'avez pas à utiliser FormDatapour envoyer un Blobau serveur à partir de JavaScript (et a Fileest également un Blob).

Exemple jQuery:

var file = $('#fileInput').get(0).files.item(0); // instance of File
$.ajax({
  type: 'POST',
  url: 'upload.php',
  data: file,
  contentType: 'application/my-binary-type', // set accordingly
  processData: false
});

Exemple JavaScript vanille:

var file = $('#fileInput').get(0).files.item(0); // instance of File
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload.php', true);
xhr.onload = function(e) { ... };
xhr.send(file);

Certes, si vous remplacez un formulaire en plusieurs parties HTML traditionnel par une implémentation «AJAX» (c'est-à-dire que votre back-end consomme des données de formulaire en plusieurs parties), vous souhaitez utiliser l' FormDataobjet comme décrit dans une autre réponse.

Source: Nouvelles astuces dans XMLHttpRequest2 | Roches HTML5

Dmitry Pashkevich
la source
17

Je n'ai pas pu faire fonctionner l'exemple ci-dessus avec des blobs et je voulais savoir ce qu'il y avait exactement dans upload.php. Alors voilà:

(testé uniquement dans Chrome 28.0.1500.95)

// javascript function that uploads a blob to upload.php
function uploadBlob(){
    // create a blob here for testing
    var blob = new Blob(["i am a blob"]);
    //var blob = yourAudioBlobCapturedFromWebAudioAPI;// for example   
    var reader = new FileReader();
    // this function is triggered once a call to readAsDataURL returns
    reader.onload = function(event){
        var fd = new FormData();
        fd.append('fname', 'test.txt');
        fd.append('data', event.target.result);
        $.ajax({
            type: 'POST',
            url: 'upload.php',
            data: fd,
            processData: false,
            contentType: false
        }).done(function(data) {
            // print the output from the upload.php script
            console.log(data);
        });
    };      
    // trigger the read from the reader...
    reader.readAsDataURL(blob);

}

Le contenu de upload.php:

<?
// pull the raw binary data from the POST array
$data = substr($_POST['data'], strpos($_POST['data'], ",") + 1);
// decode it
$decodedData = base64_decode($data);
// print out the raw data, 
echo ($decodedData);
$filename = "test.txt";
// write the data out to the file
$fp = fopen($filename, 'wb');
fwrite($fp, $decodedData);
fclose($fp);
?>
bâillements
la source
Je suis presque sûr que vous pouvez changer la ligne data: fd,dans l' ajaxappel de fonction à data: blob,.
Kenny Evitt
11

J'ai pu faire fonctionner l'exemple @yeeking en n'utilisant pas FormData mais en utilisant un objet javascript pour transférer le blob. Fonctionne avec un blob sonore créé à l'aide de recorder.js. Testé dans la version 32.0.1700.107 de Chrome

function uploadAudio( blob ) {
  var reader = new FileReader();
  reader.onload = function(event){
    var fd = {};
    fd["fname"] = "test.wav";
    fd["data"] = event.target.result;
    $.ajax({
      type: 'POST',
      url: 'upload.php',
      data: fd,
      dataType: 'text'
    }).done(function(data) {
        console.log(data);
    });
  };
  reader.readAsDataURL(blob);
}

Contenu de upload.php

<?
// pull the raw binary data from the POST array
$data = substr($_POST['data'], strpos($_POST['data'], ",") + 1);
// decode it
$decodedData = base64_decode($data);
// print out the raw data,
$filename = $_POST['fname'];
echo $filename;
// write the data out to the file
$fp = fopen($filename, 'wb');
fwrite($fp, $decodedData);
fclose($fp);
?>
Soumen Basak
la source
7
Attention dans le fichier php - si vous autorisez le client HTTP à définir le nom de fichier, il pourrait l'utiliser pour télécharger du contenu malveillant dans un fichier et un répertoire de son choix. (tant qu'Apache peut y écrire)
yeeking
9

Mise à jour 2019

Cela met à jour les réponses avec la dernière API Fetch et n'a pas besoin de jQuery.

Avertissement: ne fonctionne pas sur IE, Opera Mini et les anciens navigateurs. Voir caniuse .

Récupération de base

Cela pourrait être aussi simple que:

  fetch(`https://example.com/upload.php`, {method:"POST", body:blobData})
                .then(response => console.log(response.text()))

Récupérer avec gestion des erreurs

Après avoir ajouté la gestion des erreurs, cela pourrait ressembler à:

fetch(`https://example.com/upload.php`, {method:"POST", body:blobData})
            .then(response => {
                if (response.ok) return response;
                else throw Error(`Server returned ${response.status}: ${response.statusText}`)
            })
            .then(response => console.log(response.text()))
            .catch(err => {
                alert(err);
            });

Code PHP

Il s'agit du code côté serveur dans upload.php.

<?php    
    // gets entire POST body
    $data = file_get_contents('php://input');
    // write the data out to the file
    $fp = fopen("path/to/file", "wb");

    fwrite($fp, $data);
    fclose($fp);
?>
chat noir
la source
2

J'ai essayé toutes les solutions ci-dessus et en plus, celles des réponses connexes. Solutions incluant, mais sans s'y limiter, le passage manuel de l'objet blob à la propriété file d'un HTMLInputElement, l'appel de toutes les méthodes readAs * sur FileReader, l'utilisation d'une instance File comme deuxième argument pour un appel FormData.append, en essayant d'obtenir les données blob sous forme de chaîne en obtenant les valeurs de URL.createObjectURL (myBlob) qui se sont avérées désagréables et ont planté ma machine.

Maintenant, si vous essayez de les essayer ou plus et que vous ne parvenez toujours pas à télécharger votre blob, cela peut signifier que le problème est côté serveur. Dans mon cas, mon blob a dépassé la limite http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize et post_max_size dans PHP.INI, le fichier quittait donc le front-end forme mais rejetée par le serveur. Vous pouvez augmenter cette valeur directement dans PHP.INI ou via .htaccess

Je veux des réponses
la source