Come può javascript caricare un BLOB?


107

Ho un blob di dati in questa struttura:

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

In realtà sono dati audio registrati utilizzando il recente Chrome getUerMedia()e Recorder.js

Come posso caricare questo blob sul server utilizzando il metodo post di jquery? L'ho provato senza fortuna:

   $.post('http://localhost/upload.php', { fname: "test.wav", data: soundBlob }, 
    function(responseText) {
           console.log(responseText);
    });

1
Potresti pensare di usare binaryJS per questo. Se stai trasmettendo dati, questo potrebbe fare il trucco.
toxicate20

Anche questa risposta è molto dettagliata. stackoverflow.com/a/8758614/1331430
Fabrício Matté

Risposte:


123

Prova questo

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);
});

È necessario utilizzare l' API formdata e impostare il jQuery.ajaxs' processDatae contentTypeal false.


1
Sai come farlo anche senza AJAX?
William Entriken

@FullDecent Cosa intendi? Per richiedere all'utente di scaricare un file utilizzando File API? O per archiviare solo il contenuto del blob?
Fabrício Matté

4
Fondamentalmente$('input[type=file]').value=blob
William Entriken

14
I requisiti di sicurezza impediscono l'impostazione programmatica dei valori di input del file: stackoverflow.com/questions/1696877/...
yeeking

9
Notare che un BLOB ha un nome file generico quando viene inviato al server, a differenza di un file. Ma puoi specificare il nome del file Blob in FormData: stackoverflow.com/questions/6664967/...
Sebastien Lorber

20

In realtà non è necessario utilizzare FormDataper inviare Bloba al server da JavaScript (e a Fileè anche a Blob).

Esempio 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
});

Esempio di vanilla JavaScript:

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

Certo, se stai sostituendo un tradizionale modulo HTML multiparte con un'implementazione "AJAX" (ovvero, il tuo back-end consuma dati del modulo multiparte), vuoi utilizzare l' FormDataoggetto come descritto in un'altra risposta.

Fonte: nuovi trucchi in XMLHttpRequest2 | HTML5 Rocks


17

Non sono riuscito a far funzionare l'esempio sopra con i blob e volevo sapere cosa c'è esattamente in upload.php. Quindi eccoti qui:

(testato solo in 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);

}

I contenuti di 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);
?>

Sono abbastanza sicuro che puoi cambiare la linea data: fd,nella ajaxchiamata di funzione in data: blob,.
Kenny Evitt

11

Sono stato in grado di far funzionare l'esempio @yeeking non utilizzando FormData ma utilizzando l'oggetto javascript per trasferire il blob. Funziona con un blob di suoni creato utilizzando recorder.js. Testato in Chrome versione 32.0.1700.107

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);
}

Contenuto di 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);
?>

7
Fai attenzione al file php: se consenti al client HTTP di impostare il nome del file, potrebbero usarlo per caricare contenuti dannosi in un file e in una directory di loro scelta. (purché Apache possa scrivere lì)
yeeking

9

Aggiornamento 2019

Questo aggiorna le risposte con l'ultima Fetch API e non necessita di jQuery.

Dichiarazione di non responsabilità: non funziona su IE, Opera Mini e browser precedenti. Vedi caniuse .

Recupero di base

Potrebbe essere semplice come:

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

Recupera con gestione degli errori

Dopo aver aggiunto la gestione degli errori, potrebbe essere:

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);
            });

Codice PHP

Questo è il codice lato server in 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);
?>

2

Ho provato tutte le soluzioni di cui sopra e in aggiunta anche quelle nelle risposte correlate. Soluzioni che includono ma non sono limitate al passaggio manuale del BLOB alla proprietà file di HTMLInputElement, chiamando tutti i metodi readAs * su FileReader, utilizzando un'istanza di File come secondo argomento per una chiamata FormData.append, cercando di ottenere i dati del BLOB come stringa ottenendo i valori in URL.createObjectURL (myBlob) che si sono rivelati sgradevoli e hanno bloccato la mia macchina.

Ora, se ti capita di tentare quelli o più e ancora non riesci a caricare il tuo BLOB, potrebbe significare che il problema è lato server. Nel mio caso, il mio blob ha superato il limite di http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize e post_max_size in PHP.INI, quindi il file stava lasciando il front-end modulo ma viene rifiutato dal server. Puoi aumentare questo valore direttamente in PHP.INI o tramite .htaccess

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.