Làm thế nào để javascript có thể tải lên một blob?


107

Tôi có một dữ liệu blob trong cấu trúc này:

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

Đó thực sự là dữ liệu âm thanh được ghi lại bằng Chrome getUerMedia()Recorder.js gần đây

Làm cách nào tôi có thể tải blog này lên máy chủ bằng phương pháp đăng bài của jquery? Tôi đã thử điều này mà không gặp may:

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

1
Bạn có thể muốn nghĩ về việc sử dụng binaryJS cho việc này. Nếu bạn đang phát trực tuyến dữ liệu, điều đó có thể thực hiện thủ thuật.
toxate 20

Câu trả lời này cũng rất chi tiết. stackoverflow.com/a/8758614/1331430
Fabrício Matte

Câu trả lời:


123

Thử cái này

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

Bạn cần sử dụng API FormData và đặt jQuery.ajax's processDatacontentTypethành false.


1
Bạn có biết cách làm điều này mà không có AJAX không?
William Entriken

@FullDecent Ý bạn là gì? Để nhắc người dùng tải xuống tệp bằng File API? Hay chỉ lưu trữ nội dung blob?
Fabrício Matté

4
Về cơ bản$('input[type=file]').value=blob
William Entriken

14
Yêu cầu bảo mật ngăn chặn thiết lập chương trình của các giá trị đầu vào tập tin: stackoverflow.com/questions/1696877/...
yeeking

9
Lưu ý rằng Blob có tên tệp chung khi được gửi đến máy chủ, không giống như Tệp. Nhưng bạn có thể nói rõ tên tệp Blob trong FormData: stackoverflow.com/questions/6664967/…
Sebastien Lorber

20

Bạn thực sự không phải sử dụng FormDatađể gửi một Blobđến máy chủ từ JavaScript (và a Filecũng là một Blob).

Ví dụ 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
});

Ví dụ về 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);

Được chấp nhận, nếu bạn đang thay thế một biểu mẫu đa phần HTML truyền thống bằng một triển khai "AJAX" (nghĩa là, phần sau của bạn sử dụng dữ liệu biểu mẫu nhiều phần), bạn muốn sử dụng FormDatađối tượng như được mô tả trong một câu trả lời khác.

Nguồn: Thủ thuật mới trong XMLHttpRequest2 | HTML5 Rocks


17

Tôi không thể lấy ví dụ trên để làm việc với các đốm màu và tôi muốn biết chính xác những gì trong upload.php. Vì vậy, bạn bắt đầu:

(chỉ được thử nghiệm trong 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);

}

Nội dung của 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);
?>

Tôi khá chắc rằng bạn có thể thay đổi dòng data: fd,trong lệnh ajaxgọi hàm thành data: blob,.
Kenny Evitt

11

Tôi có thể lấy ví dụ @yeeking hoạt động bằng cách không sử dụng FormData mà sử dụng đối tượng javascript để chuyển blob. Hoạt động với một đốm âm thanh được tạo bằng recorder.js. Đã thử nghiệm trong phiên bản 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);
}

Nội dung của 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
Cẩn thận trong tệp php - nếu bạn cho phép máy khách HTTP đặt tên tệp, họ có thể sử dụng nó để tải nội dung độc hại lên tệp và thư mục mà họ chọn. (miễn là Apache có thể viết ở đó)
yeeking

9

Cập nhật 2019

Điều này cập nhật câu trả lời bằng API Tìm nạp mới nhất và không cần jQuery.

Tuyên bố từ chối trách nhiệm: không hoạt động trên IE, Opera Mini và các trình duyệt cũ hơn. Xem caniuse .

Tìm nạp cơ bản

Nó có thể đơn giản như:

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

Tìm nạp với Xử lý lỗi

Sau khi thêm xử lý lỗi, nó có thể giống như sau:

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

Mã PHP

Đây là mã phía máy chủ trong 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

Tôi đã thử tất cả các giải pháp ở trên và ngoài ra, cả những giải pháp trong các câu trả lời liên quan. Các giải pháp bao gồm nhưng không giới hạn việc chuyển blob theo cách thủ công tới thuộc tính tệp của HTMLInputElement, gọi tất cả các phương thức readAs * trên FileReader, sử dụng cá thể File làm đối số thứ hai cho lệnh gọi FormData.append, cố gắng lấy dữ liệu blob dưới dạng chuỗi bằng cách lấy các giá trị tại URL.createObjectURL (myBlob) trở nên khó chịu và làm hỏng máy của tôi.

Bây giờ, nếu bạn tình cờ thử những thứ đó trở lên và vẫn thấy bạn không thể tải lên blob của mình, điều đó có thể có nghĩa là vấn đề là phía máy chủ. Trong trường hợp của tôi, blob của tôi đã vượt quá giới hạn http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize và post_max_size trong PHP.INI nên tệp đã rời khỏi giao diện người dùng nhưng bị máy chủ từ chối. Bạn có thể tăng giá trị này trực tiếp trong PHP.INI hoặc qua .htaccess

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.