Как JavaScript может загрузить большой двоичный объект?


107

У меня есть данные blob в этой структуре:

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
Фабрисио Матте

Ответы:


123

Попробуй это

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

Вы должны использовать API FormData и установить jQuery.ajax«s processDataи contentTypeк false.


1
Вы знаете, как это сделать и без AJAX?
Уильям Энтрикен, 07

@FullDecent Что ты имеешь в виду? Чтобы предложить пользователю загрузить файл с помощью File API? Или просто хранить содержимое blob?
Fabrício Matté

4
Что делать в основном$('input[type=file]').value=blob
Уильям Энтрикен

14
Требования безопасности предотвращают программную настройку входных значений файла: stackoverflow.com/questions/1696877/…
yeeking

9
Обратите внимание, что Blob имеет общее имя файла при отправке на сервер, в отличие от File. Но вы можете указать имя файла Blob в FormData: stackoverflow.com/questions/6664967/…
Себастьен Лорбер,

20

На самом деле вам не нужно использовать FormDataдля отправки Blobна сервер из JavaScript (а 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
});

Пример ванильного 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 Rocks


17

Мне не удалось заставить приведенный выше пример работать с большими двоичными объектами, и я хотел знать, что именно находится в 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,.
Кенни Эвитт

11

Мне удалось заставить пример @yeeking работать, не используя FormData, но используя объект javascript для передачи blob. Работает со звуковой каплей, созданной с помощью рекордера.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

9

Обновление 2019

Это обновляет ответы с помощью последней версии Fetch API и не требует jQuery.

Отказ от ответственности: не работает в IE, Opera Mini и более старых браузерах. См. 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

Я пробовал все решения выше, а также те, что в связанных ответах. Решения, включая, помимо прочего, передачу большого двоичного объекта в свойство файла HTMLInputElement, вызов всех методов readAs * в FileReader с использованием экземпляра File в качестве второго аргумента для вызова FormData.append, попытка получить данные большого двоичного объекта в виде строки путем получения значения в URL.createObjectURL (myBlob), которые оказались неприятными и разбили мою машину.

Теперь, если вы попытаетесь выполнить те или другие действия и по-прежнему обнаружите, что не можете загрузить свой большой двоичный объект, это может означать, что проблема на стороне сервера. В моем случае мой BLOB- объект превысил http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize и ограничение post_max_size в PHP.INI, поэтому файл покидал внешний интерфейс форма, но отклоняется сервером. Вы можете либо увеличить это значение непосредственно в PHP.INI, либо через .htaccess.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.