Wie kann Javascript einen Blob hochladen?

107

Ich habe Blob-Daten in dieser Struktur:

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

Es handelt sich tatsächlich um Audiodaten, die mit den neuesten Versionen von Chrome getUerMedia()und Recorder.js aufgezeichnet wurden

Wie kann ich diesen Blob mit der Post-Methode von jquery auf den Server hochladen? Ich habe das ohne Glück versucht:

   $.post('http://localhost/upload.php', { fname: "test.wav", data: soundBlob }, 
    function(responseText) {
           console.log(responseText);
    });
Yang
quelle
1
Vielleicht möchten Sie über die Verwendung von binaryJS nachdenken. Wenn Sie Daten streamen, reicht dies möglicherweise aus.
Toxicate20
Diese Antwort ist ebenfalls sehr detailliert. stackoverflow.com/a/8758614/1331430
Fabrício Matté

Antworten:

123

Versuche dies

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

Sie müssen die verwenden Formdata API und stellen Sie die jQuery.ajax‚s processDataund contentTypezu false.

Fabrício Matté
quelle
1
Wissen Sie, wie man das auch ohne AJAX macht?
William Entriken
@FullDecent Was meinst du? Um den Benutzer aufzufordern, eine Datei über die Datei-API herunterzuladen? Oder um nur den Blob-Inhalt zu speichern?
Fabrício Matté
4
Grundsätzlich zu tun$('input[type=file]').value=blob
William Entriken
14
Sicherheitsanforderungen verhindern programmatische Einstellung der Dateieingabewerte: stackoverflow.com/questions/1696877/...
yeeking
9
Beachten Sie, dass ein Blob im Gegensatz zu einer Datei einen generischen Dateinamen hat, wenn er an den Server gesendet wird. Aber Sie können den Blob-Dateinamen in FormData angeben: stackoverflow.com/questions/6664967/…
Sebastien Lorber
20

Sie müssen eigentlich nicht verwenden FormData, um a Blobvon JavaScript an den Server zu senden (und a Fileist auch a Blob).

jQuery-Beispiel:

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

Vanilla JavaScript Beispiel:

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

Zugegeben, wenn Sie ein herkömmliches mehrteiliges HTML-Formular durch eine "AJAX" -Implementierung ersetzen (dh Ihr Back-End verwendet mehrteilige Formulardaten), möchten Sie das FormDataObjekt wie in einer anderen Antwort beschrieben verwenden.

Quelle: Neue Tricks in XMLHttpRequest2 | HTML5 Rocks

Dmitry Pashkevich
quelle
17

Ich konnte das obige Beispiel nicht dazu bringen, mit Blobs zu arbeiten, und ich wollte wissen, was genau in upload.php enthalten ist. Also los geht's:

(nur in Chrome 28.0.1500.95 getestet)

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

}

Der Inhalt von 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);
?>
yeeking
quelle
Ich bin mir ziemlich sicher, dass Sie die Zeile data: fd,im ajaxFunktionsaufruf in ändern können data: blob,.
Kenny Evitt
11

Ich konnte das Beispiel @yeeking zum Laufen bringen, indem ich nicht FormData, sondern ein Javascript-Objekt zum Übertragen des Blobs verwendete. Funktioniert mit einem Sound-Blob, der mit recorder.js erstellt wurde. Getestet in Chrome Version 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);
}

Inhalt von 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
quelle
7
Vorsicht in der PHP-Datei - Wenn Sie dem HTTP-Client erlauben, den Dateinamen festzulegen, kann er damit schädliche Inhalte in eine Datei und ein Verzeichnis seiner Wahl hochladen. (solange Apache dort schreiben kann)
am
9

Update 2019

Dadurch werden die Antworten mit der neuesten Fetch-API aktualisiert und jQuery wird nicht benötigt.

Haftungsausschluss: Funktioniert nicht mit IE, Opera Mini und älteren Browsern. Siehe caniuse .

Grundlegender Abruf

Es könnte so einfach sein wie:

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

Abrufen mit Fehlerbehandlung

Nach dem Hinzufügen der Fehlerbehandlung könnte dies folgendermaßen aussehen:

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

PHP-Code

Dies ist der serverseitige Code 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);
?>
Chatnoir
quelle
2

Ich habe alle oben genannten Lösungen ausprobiert und zusätzlich auch die in verwandten Antworten. Lösungen, einschließlich, aber nicht beschränkt auf das manuelle Übergeben des Blobs an die Dateieigenschaft eines HTMLInputElement, das Aufrufen aller readAs * -Methoden in FileReader, das Verwenden einer File-Instanz als zweites Argument für einen FormData.append-Aufruf und das Abrufen der Blob-Daten als Zeichenfolge durch Abrufen die Werte bei URL.createObjectURL (myBlob), die sich als böse herausstellten und meinen Computer zum Absturz brachten.

Wenn Sie diese oder mehrere versuchen und dennoch feststellen, dass Sie Ihren Blob nicht hochladen können, kann dies bedeuten, dass das Problem serverseitig ist. In meinem Fall hat mein Blob das Limit http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize und post_max_size in PHP.INI überschritten, sodass die Datei das Frontend verlassen hat Formular, wird aber vom Server abgelehnt. Sie können diesen Wert entweder direkt in PHP.INI oder über .htaccess erhöhen

Ich möchte Antworten
quelle