Jak javascript może przesłać obiekt blob?

107

Mam dane blob w tej strukturze:

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

W rzeczywistości są to dane dźwiękowe nagrane przy użyciu najnowszego Chrome getUerMedia()i Recorder.js.

Jak mogę przesłać ten obiekt BLOB na serwer przy użyciu metody publikowania w jquery? Próbowałem tego bez szczęścia:

   $.post('http://localhost/upload.php', { fname: "test.wav", data: soundBlob }, 
    function(responseText) {
           console.log(responseText);
    });
Yang
źródło
1
Możesz pomyśleć o użyciu do tego binaryJS. Jeśli przesyłasz strumieniowo dane, może to załatwić sprawę.
toksykat20
Ta odpowiedź jest również bardzo szczegółowa. stackoverflow.com/a/8758614/1331430
Fabrício Matté

Odpowiedzi:

123

Spróbuj tego

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

Musisz użyć interfejsu API FormData i ustawić wartości jQuery.ajax's processDataoraz contentTypeto false.

Fabrício Matté
źródło
1
Czy wiesz, jak to zrobić również bez AJAX?
William Entriken
@FullDecent Co masz na myśli? Aby zachęcić użytkownika do pobrania pliku za pomocą interfejsu API plików? Lub po prostu przechowywać zawartość obiektu BLOB?
Fabrício Matté
4
Zasadniczo$('input[type=file]').value=blob
William Entriken,
14
Wymagania bezpieczeństwa uniemożliwiają programowe ustawianie wartości wejściowych pliku: stackoverflow.com/questions/1696877/ ...
yeeking
9
Należy zauważyć, że obiekt BLOB ma ogólną nazwę pliku po wysłaniu na serwer, w przeciwieństwie do pliku. Ale możesz sprecyzować nazwę pliku Bloba w FormData: stackoverflow.com/questions/6664967/ ...
Sebastien Lorber
20

W rzeczywistości nie musisz używać FormDatado wysyłania a Blobdo serwera z JavaScript (a Filejest również a Blob).

Przykład 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
});

Przykład 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);

To prawda, jeśli zastępujesz tradycyjny formularz wieloczęściowy HTML implementacją „AJAX” (to znaczy, że zaplecze zużywa dane formularza wieloczęściowego), chcesz użyć FormDataobiektu w sposób opisany w innej odpowiedzi.

Źródło: Nowe sztuczki w XMLHttpRequest2 | HTML5 Rocks

Dmitrij Paszkiewicz
źródło
17

Nie mogłem uzyskać powyższego przykładu do pracy z obiektami blob i chciałem wiedzieć, co dokładnie znajduje się w pliku upload.php. A więc proszę:

(testowane tylko w 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);

}

Zawartość 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
źródło
Jestem prawie pewien, że możesz zmienić linię data: fd,w ajaxwywołaniu funkcji na data: blob,.
Kenny Evitt
11

Udało mi się uzyskać przykład @yeeking, aby działał, nie używając FormData, ale używając obiektu javascript do przesyłania obiektu blob. Działa z dźwiękowym blobem utworzonym za pomocą pliku recorder.js. Przetestowano w Chrome w wersji 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);
}

Zawartość 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
źródło
7
Ostrożnie w pliku php - jeśli pozwolisz klientowi HTTP ustawić nazwę pliku, może go użyć do przesłania złośliwej zawartości do wybranego przez siebie pliku i katalogu. (o ile
Apacz
9

Aktualizacja 2019

To aktualizuje odpowiedzi za pomocą najnowszego interfejsu API pobierania i nie wymaga jQuery.

Uwaga: nie działa w IE, Opera Mini i starszych przeglądarkach. Zobacz caniuse .

Podstawowe pobieranie

Może to być tak proste, jak:

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

Pobierz z obsługą błędów

Po dodaniu obsługi błędów mogłoby to wyglądać następująco:

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

Kod PHP

To jest kod po stronie serwera w 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
źródło
2

Wypróbowałem wszystkie powyższe rozwiązania, a ponadto te w powiązanych odpowiedziach. Rozwiązania obejmujące między innymi ręczne przekazanie obiektu blob do właściwości file HTMLInputElement, wywołanie wszystkich metod readAs * w FileReader, użycie wystąpienia File jako drugiego argumentu dla wywołania FormData.append, próba pobrania danych obiektu BLOB jako ciągu przez pobranie wartości w URL.createObjectURL (myBlob), które okazały się nieprzyjemne i spowodowały awarię mojego komputera.

Teraz, jeśli zdarzy ci się spróbować tych lub więcej i nadal okaże się, że nie możesz przesłać swojego obiektu BLOB, może to oznaczać, że problem występuje po stronie serwera. W moim przypadku mój blob przekroczył http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize i post_max_size limit w PHP.INI, więc plik opuszczał front-end formularz, ale został odrzucony przez serwer. Możesz zwiększyć tę wartość bezpośrednio w PHP.INI lub przez .htaccess

Chcę odpowiedzi
źródło