Javascript: загрузка файла ... без файла - PullRequest
50 голосов
/ 04 февраля 2010

Я пытаюсь подделать загрузку файла, фактически не используя входные данные от пользователя.Содержимое файла будет динамически генерироваться из строки.

Возможно ли это?Кто-нибудь когда-нибудь делал это раньше?Существуют ли примеры / теория?

Чтобы уточнить, я знаю, как загрузить файл, используя методы AJAX, используя скрытый iframe и друзей - проблема заключается в загрузке файла, который не имеет форму.1006 * Я использую ExtJS, но jQuery также возможен, так как ExtJS может подключиться к нему (ext-jquery-base).

Ответы [ 7 ]

33 голосов
/ 04 февраля 2010

Почему бы просто не использовать XMLHttpRequest() с POST?

function beginQuoteFileUnquoteUpload(data)
{
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://www.mysite.com/myuploadhandler.php", true);
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
            alert("File uploaded!");
    }
    xhr.send("filedata="+encodeURIComponent(data));
}

Сценарий обработчика на сервере просто записывает данные файла в файл.

EDIT
Загрузка файла - это все еще пост http с другим типом контента. Вы можете использовать этот тип контента и отделить его от границ:

function beginQuoteFileUnquoteUpload(data)
{
    // Define a boundary, I stole this from IE but you can use any string AFAIK
    var boundary = "---------------------------7da24f2e50046";
    var xhr = new XMLHttpRequest();
    var body = '--' + boundary + '\r\n'
             // Parameter name is "file" and local filename is "temp.txt"
             + 'Content-Disposition: form-data; name="file";'
             + 'filename="temp.txt"\r\n'
             // Add the file's mime-type
             + 'Content-type: plain/text\r\n\r\n'
             + data + '\r\n'
             + boundary + '--';

    xhr.open("POST", "http://www.mysite.com/myuploadhandler.php", true);
    xhr.setRequestHeader(
        "Content-type", "multipart/form-data; boundary="+boundary

    );
    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
            alert("File uploaded!");
    }
    xhr.send(body);
}

Если вы хотите отправить дополнительные данные, вы просто разделяете каждый раздел границей и описываете расположение содержимого и заголовки типа содержимого для каждого раздела. Каждый заголовок отделяется новой строкой, а тело отделяется от заголовков дополнительной новой строкой. Естественно, загрузка двоичных данных таким способом будет немного сложнее: -)

Дальнейшее редактирование: забыли упомянуть, убедитесь, что какая-либо строка границы отсутствует в текстовом «файле», который вы отправляете, иначе она будет рассматриваться как граница.

30 голосов
/ 04 апреля 2014

Если вам не нужна поддержка старых браузеров, вы можете использовать объект FormData, который является частью File API:

var formData = new FormData();
var blob = new Blob(['Lorem ipsum'], { type: 'plain/text' });
formData.append('file', blob,'readme.txt');

var request = new XMLHttpRequest();
request.open('POST', 'http://example.org/upload');
request.send(formData);

Файл Api поддерживается всеми текущими браузерами (IE10 +)

13 голосов
/ 07 февраля 2010

Просто поделитесь конечным результатом, который работает - и имеет чистый способ добавления / удаления параметров без какого-либо жесткого программирования.

var boundary = '-----------------------------' +
            Math.floor(Math.random() * Math.pow(10, 8));

    /* Parameters go here */
var params = {
    file: {
        type: 'text/plain',
        filename: Path.utils.basename(currentTab.id),
        content: GET_CONTENT() /* File content goes here */
    },
    action: 'upload',
    overwrite: 'true',
    destination: '/'
};

var content = [];
for(var i in params) {
    content.push('--' + boundary);

    var mimeHeader = 'Content-Disposition: form-data; name="'+i+'"; ';
    if(params[i].filename)
        mimeHeader += 'filename="'+ params[i].filename +'";';
    content.push(mimeHeader);

    if(params[i].type)
        content.push('Content-Type: ' + params[i].type);

    content.push('');
    content.push(params[i].content || params[i]);
};

    /* Use your favorite toolkit here */
    /* it should still work if you can control headers and POST raw data */
Ext.Ajax.request({
    method: 'POST',
    url: 'www.example.com/upload.php',
    jsonData: content.join('\r\n'),
    headers: {
        'Content-Type': 'multipart/form-data; boundary=' + boundary,
        'Content-Length': content.length
    }
});

Это было протестировано для работы во всех современных браузерах, включая, но не ограничиваясь:

  • IE6 +
  • FF 1.5 +
  • Опера 9 +
  • Chrome 1.0 +
  • Safari 3.0 +
6 голосов
/ 04 февраля 2010

Загрузка файла - это всего лишь запрос POST с правильно закодированным содержимым файла и специальным заголовком multipart/formdata.Вам нужно использовать это <input type=file />, потому что безопасность вашего браузера запрещает доступ к пользовательскому диску напрямую.

Поскольку вам не нужно читать пользовательский диск, ДА , вы можете подделать егоJavascript.Это будет просто XMLHttpRequest.Чтобы создать «подлинный» запрос на загрузку, вы можете установить Fiddler и проверить исходящий запрос.

Вам необходимо правильно закодировать этот файл, поэтому эта ссылка может быть очень полезной: RFC 2388: возвращение значений из форм: multipart / form-data

3 голосов
/ 15 ноября 2016

Простой способ имитировать загрузку поддельных файлов с помощью jQuery:

var fd = new FormData();
var file = new Blob(['file contents'], {type: 'plain/text'});

fd.append('formFieldName', file, 'fileName.txt');

$.ajax({
  url: 'http://example.com/yourAddress',
  method: 'post',
  data: fd,
  processData: false,        //this...
  contentType: false         //and this is for formData type
});
3 голосов
/ 04 февраля 2010

Я только что перехватил эту строку POST_DATA с помощью дополнения Firefox TamperData. Я отправил форму с одним полем type="file" с именем «myfile» и кнопкой «btn-submit» со значением «Upload». Содержимое загруженного файла:

Line One
Line Two
Line Three

Итак, вот строка POST_DATA:

-----------------------------192642264827446\r\n
Content-Disposition: form-data;    \n
name="myfile"; filename="local-file-name.txt"\r\n
Content-Type: text/plain\r\n
\r\n
Line \n
One\r\n
Line Two\r\n
Line Three\r\n
\r\n
-----------------------------192642264827446\n
\r\n
Content-Disposition: form-data; name="btn-submit"\r\n
\r\n
Upload\n
\r\n
-----------------------------192642264827446--\r\n

Я не уверен, что означает число (192642264827446), но это не должно быть слишком сложно выяснить.

2 голосов
/ 25 января 2014

https://stackoverflow.com/a/2198524/2914587 работал для меня, после того, как я добавил дополнительные '--' перед окончательным boundary в полезной нагрузке:

var body = '--' + boundary + '\r\n'
         // Parameter name is "file" and local filename is "temp.txt"
         + 'Content-Disposition: form-data; name="file";'
         + 'filename="temp.txt"\r\n'
         // Add the file's mime-type
         + 'Content-type: plain/text\r\n\r\n'
         + data + '\r\n'
         + '--' + boundary + '--';
...