Javascript: загрузка файла... без файла
Я пытаюсь подделать загрузку файла без фактического использования ввода файла пользователем. Содержимое файла будет динамически генерироваться из строки.
Возможно ли это? Кто-нибудь когда-либо делал это раньше? Существуют ли примеры/теория?
Чтобы уточнить, я знаю, как загрузить файл с использованием методов AJAX с помощью скрытого iframe и друзей - проблема заключается в загрузке файла, который не находится в форме.
Я использую ExtJS, но jQuery возможен, так как ExtJS может подключаться к нему (ext-jquery-base).
Ответы
Ответ 1
Почему бы просто не использовать 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));
}
Обработчик script на сервере просто записывает данные файла в файл.
ИЗМЕНИТЬ
Загрузка файла по-прежнему является 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 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);
}
Если вы хотите отправить дополнительные данные, вы просто разделяете каждый раздел с помощью границы и описываете заголовки контента и контента для каждого раздела. Каждый заголовок разделяется новой строкой, и тело отделено от заголовков дополнительной новой строкой. Естественно, загрузка двоичных данных таким образом будет несколько сложнее: -)
Дальнейшее редактирование: забыли упомянуть, убедитесь, что какая-либо граничная строка не находится в текстовом "файле", который вы отправляете, иначе он будет рассматриваться как граница.
Ответ 2
Если вам не нужна поддержка старых браузеров, вы можете использовать объект 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 +)
Ответ 3
Просто поделитесь конечным результатом, который работает - и имеет чистый способ добавления/удаления параметров без какого-либо hardcoding.
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 +
- Opera 9 +
- Chrome 1.0 +
- Safari 3.0 +
Ответ 4
Файл загружает только запрос POST
с соответствующим кодированием содержимого файла и со специальным заголовком multipart/formdata
. Вы должны использовать этот <input type=file />
, потому что ваша защита браузера запрещает вам напрямую обращаться к пользовательскому диску.
Поскольку вам не нужно читать пользовательский диск, ДА, вы можете подделать его с помощью Javascript. Это будет всего лишь XMLHttpRequest
. Чтобы создать "аутентичный" запрос на загрузку, вы можете установить Fiddler
и проверить свой исходящий запрос.
Вам нужно будет правильно закодировать этот файл, поэтому эта ссылка может быть очень полезной: RFC 2388: Возвращаемые значения из форм: multipart/form-data
Ответ 5
Я просто поймал эту строку POST_DATA с помощью дополнения Firefox TamperData. Я отправил форму с одним полем type="file"
с именем "myfile" и кнопкой отправки "btn-submit" со значением "Загрузить". Содержимое загруженного файла
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), но этого не должно быть слишком сложно узнать.
Ответ 6
fooobar.com/questions/100075/... работал у меня, после добавления дополнительного '--'
до окончательного 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 mime-type
+ 'Content-type: plain/text\r\n\r\n'
+ data + '\r\n'
+ '--' + boundary + '--';
Ответ 7
Простой способ подражать "поддельной" загрузке файла с помощью 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
});