JavaScript สามารถอัปโหลด Blob ได้อย่างไร?


107

ฉันมีข้อมูลหยดในโครงสร้างนี้:

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

เป็นข้อมูลเสียงที่บันทึกโดยใช้ Chrome getUerMedia()และRecorder.jsล่าสุด

ฉันจะอัปโหลดหยดนี้ไปยังเซิร์ฟเวอร์โดยใช้วิธีการโพสต์ของ jquery ได้อย่างไร ฉันได้ลองโดยไม่มีโชค:

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

1
คุณอาจต้องการคิดเกี่ยวกับการใช้ binaryJS สำหรับสิ่งนี้ หากคุณกำลังสตรีมข้อมูลนั่นอาจเป็นเคล็ดลับ
toxicate20

คำตอบนี้มีรายละเอียดมากเช่นกัน stackoverflow.com/a/8758614/1331430
FabrícioMatté

คำตอบ:


125

ลองทำตามนี้

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

คุณจำเป็นต้องใช้FormData APIและการตั้งค่าjQuery.ajaxของprocessDataและเพื่อcontentTypefalse


1
คุณรู้วิธีทำโดยไม่ใช้ AJAX ด้วยหรือไม่?
William Entriken

@FullDecent คุณหมายถึงอะไร? เพื่อแจ้งให้ผู้ใช้ดาวน์โหลดไฟล์โดยใช้ File API? หรือเพื่อเก็บเนื้อหาหยด?
FabrícioMatté

4
โดยพื้นฐานแล้ว$('input[type=file]').value=blob
William Entriken

14
ข้อกำหนดด้านความปลอดภัยป้องกันการตั้งค่าทางโปรแกรมของค่าอินพุตไฟล์: stackoverflow.com/questions/1696877/…
yeeking

9
โปรดทราบว่า Blob มีชื่อไฟล์ทั่วไปเมื่อส่งไปยังเซิร์ฟเวอร์ซึ่งแตกต่างจากไฟล์ แต่คุณสามารถใช้ชื่อไฟล์ Blob ใน FormData: stackoverflow.com/questions/6664967/…
Sebastien Lorber

20

คุณไม่จำเป็นต้องใช้FormDataเพื่อส่งBlobไปยังเซิร์ฟเวอร์จาก JavaScript (และ a Fileยังเป็น a Blob)

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

ตัวอย่าง 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);

จริงอยู่หากคุณกำลังแทนที่รูปแบบหลายส่วนของ HTML แบบดั้งเดิมด้วยการใช้งาน "AJAX" (นั่นคือส่วนหลังของคุณใช้ข้อมูลในรูปแบบหลายส่วน) คุณต้องการใช้FormDataวัตถุตามที่อธิบายไว้ในคำตอบอื่น

ที่มา: เทคนิคใหม่ใน XMLHttpRequest2 | HTML5 หิน


17

ฉันไม่สามารถรับตัวอย่างข้างต้นเพื่อทำงานกับ blobs ได้และฉันต้องการทราบว่าใน upload.php คืออะไร ไปเลย:

(ทดสอบเฉพาะใน 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);

}

เนื้อหาของ 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);
?>

ฉันค่อนข้างมั่นใจว่าคุณสามารถเปลี่ยนบรรทัดdata: fd,ในการajaxเรียกใช้ฟังก์ชันdata: blob,ได้
Kenny Evitt

11

ฉันสามารถรับ @yeeking ตัวอย่างเพื่อใช้งานได้โดยไม่ใช้ FormData แต่ใช้วัตถุจาวาสคริปต์เพื่อถ่ายโอนหยด ทำงานร่วมกับหยดเสียงที่สร้างโดยใช้ recorder.js ทดสอบใน Chrome เวอร์ชัน 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);
}

เนื้อหาของ 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
ระวังในไฟล์ php - หากคุณอนุญาตให้ไคลเอนต์ HTTP ตั้งชื่อไฟล์พวกเขาสามารถใช้เพื่ออัปโหลดเนื้อหาที่เป็นอันตรายไปยังไฟล์และไดเร็กทอรีที่พวกเขาเลือกได้ (ตราบเท่าที่ Apache สามารถเขียนได้ที่นั่น)
yeeking

10

อัปเดต 2019

สิ่งนี้จะอัปเดตคำตอบด้วยFetch APIล่าสุดและไม่จำเป็นต้องใช้ jQuery

ข้อจำกัดความรับผิดชอบ: ใช้ไม่ได้กับ IE, Opera Mini และเบราว์เซอร์รุ่นเก่า ดูcaniuse caniuse

การดึงข้อมูลพื้นฐาน

มันอาจจะง่ายเหมือน:

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

ดึงข้อมูลด้วยการจัดการข้อผิดพลาด

หลังจากเพิ่มการจัดการข้อผิดพลาดอาจมีลักษณะดังนี้:

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

นี่คือรหัสฝั่งเซิร์ฟเวอร์ใน 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

ฉันลองใช้วิธีแก้ปัญหาทั้งหมดข้างต้นและนอกจากนี้คำตอบที่เกี่ยวข้องด้วย โซลูชันรวมถึง แต่ไม่ จำกัด เพียงการส่ง blob ด้วยตนเองไปยังคุณสมบัติไฟล์ของ HTMLInputElement โดยเรียกใช้เมธอด readAs * ทั้งหมดบน FileReader โดยใช้อินสแตนซ์ไฟล์เป็นอาร์กิวเมนต์ที่สองสำหรับการเรียก FormData ต่อท้ายพยายามรับข้อมูล blob เป็นสตริงโดยรับ ค่าที่ URL.createObjectURL (myBlob) ซึ่งกลายเป็นสิ่งที่น่ารังเกียจและทำให้เครื่องของฉันพัง

ตอนนี้หากคุณพยายามที่จะลองสิ่งเหล่านั้นหรือมากกว่านั้นและยังพบว่าคุณไม่สามารถอัปโหลดหยดของคุณได้อาจหมายความว่าปัญหาเกิดจากฝั่งเซิร์ฟเวอร์ ในกรณีของฉันหยดของฉันเกินhttp://www.php.net/manual/en/ini.core.php#ini.upload-max-filesizeและขีด จำกัด post_max_size ใน PHP.INI ดังนั้นไฟล์จึงออกจากส่วนหน้า ฟอร์ม แต่ถูกเซิร์ฟเวอร์ปฏิเสธ คุณสามารถเพิ่มค่านี้ได้โดยตรงใน PHP.INI หรือผ่าน. htaccess

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.