Bagaimana cara javascript mengunggah gumpalan?

107

Saya memiliki data blob dalam struktur ini:

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

Ini sebenarnya data suara yang direkam menggunakan Chrome getUerMedia()dan Recorder.js terbaru

Bagaimana cara mengunggah blob ini ke server menggunakan metode posting jquery? Saya sudah mencoba ini tanpa hasil:

   $.post('http://localhost/upload.php', { fname: "test.wav", data: soundBlob }, 
    function(responseText) {
           console.log(responseText);
    });
Yang
sumber
1
Anda mungkin ingin berpikir tentang menggunakan binaryJS untuk ini. Jika Anda mengalirkan data, itu mungkin berhasil.
racun20
Jawaban ini juga sangat rinci. stackoverflow.com/a/8758614/1331430
Fabrício Matté

Jawaban:

123

Coba ini

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

Anda perlu menggunakan API FormData dan mengatur jQuery.ajax's processDatadan contentTypeuntuk false.

Fabrício Matté
sumber
1
Apakah Anda juga tahu bagaimana melakukan ini tanpa AJAX?
William Entriken
@FullDecent Apa maksud Anda? Untuk meminta pengguna mendownload file menggunakan File API? Atau hanya menyimpan konten blob?
Fabrício Matté
4
Pada dasarnya$('input[type=file]').value=blob
William Entriken
14
Persyaratan keamanan mencegah pengaturan programatik nilai input file: stackoverflow.com/questions/1696877/…
yeeking
9
Perhatikan bahwa Blob memiliki nama file umum saat dikirim ke server, tidak seperti File. Tetapi Anda dapat menambahkan nama file Blob di FormData: stackoverflow.com/questions/6664967/…
Sebastien Lorber
20

Anda sebenarnya tidak harus menggunakan FormDatauntuk mengirim Blobke server dari JavaScript (dan Filejuga a Blob).

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

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

Memang, jika Anda mengganti formulir multibagian HTML tradisional dengan implementasi "AJAX" (yaitu, back-end Anda menggunakan data formulir multibagian), Anda ingin menggunakan FormDataobjek seperti yang dijelaskan dalam jawaban lain.

Sumber: Trik Baru di XMLHttpRequest2 | HTML5 Rocks

Dmitry Pashkevich
sumber
17

Saya tidak bisa mendapatkan contoh di atas untuk bekerja dengan blob dan saya ingin tahu apa sebenarnya di upload.php. Jadi ini dia:

(hanya diuji di 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);

}

Isi dari 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
sumber
Saya cukup yakin Anda dapat mengubah baris data: fd,dalam ajaxpemanggilan fungsi menjadi data: blob,.
Kenny Evitt
11

Saya bisa mendapatkan contoh @yeeking untuk bekerja dengan tidak menggunakan FormData tetapi menggunakan objek javascript untuk mentransfer gumpalan. Bekerja dengan blob suara yang dibuat menggunakan recorder.js. Diuji di Chrome versi 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);
}

Isi dari 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
sumber
7
Hati-hati dalam file php - jika Anda mengizinkan klien HTTP untuk menyetel nama file, mereka dapat menggunakannya untuk mengunggah konten berbahaya ke dalam file dan direktori yang mereka pilih. (selama Apache dapat menulis di sana)
yeeking
9

Pembaruan 2019

Ini memperbarui jawaban dengan Fetch API terbaru dan tidak membutuhkan jQuery.

Penafian: tidak berfungsi di IE, Opera Mini, dan browser lama. Lihat caniuse .

Pengambilan Dasar

Ini bisa sesederhana:

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

Ambil dengan Penanganan Kesalahan

Setelah menambahkan penanganan kesalahan, ini akan terlihat seperti:

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

Kode PHP

Ini adalah kode sisi server di 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
sumber
2

Saya mencoba semua solusi di atas dan sebagai tambahan, yang ada di jawaban terkait juga. Solusi termasuk namun tidak terbatas pada meneruskan blob secara manual ke properti file HTMLInputElement, memanggil semua metode readAs * pada FileReader, menggunakan instance File sebagai argumen kedua untuk panggilan FormData.append, mencoba mendapatkan data blob sebagai string dengan mendapatkan nilai-nilai di URL.createObjectURL (myBlob) yang ternyata buruk dan merusak mesin saya.

Sekarang, jika Anda mencobanya atau lebih dan masih tidak dapat mengunggah blob Anda, itu bisa berarti masalahnya ada pada sisi server. Dalam kasus saya, blob saya melebihi http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize dan batas post_max_size di PHP.INI sehingga file tersebut meninggalkan front end formulir tetapi ditolak oleh server. Anda dapat meningkatkan nilai ini secara langsung di PHP.INI atau melalui .htaccess

Saya Ingin Jawaban
sumber