未定义 FormData 时如何在 Web Workers 中上传文件
当我通过 Web Worker 上传时,如何在 PHP 中检索 $_FILES
?当我尝试使用 FormData
时,出现以下错误:
How can I retrieve $_FILES
in PHP when I upload through a Web Worker? When I tried to use FormData
, I got the following error:
错误:FormData 未定义
Error: FormData is not defined
这是我的代码:
function uploadFile(blobFile, fileName, filePart, totalChunks) {
//if I try to put this
//var formData = new FormData(); //it does not work
var xhr = new XMLHttpRequest();
xhr.open("POST", "upload.php"+"?"+"file="+fileName + filePart, true);
xhr.onload = function(e) {};
xhr.send(blobFile);
}
那么在 upload.php 中,我应该如何从 $_FILES
获取 tmp 路径?以防万一,我还将显示引用 Web Worker 的页面:
So in upload.php how am I supposed to get the tmp path from $_FILES
? Just in case, I will also show the page referencing the Web worker:
<form id="fileuploader" enctype="multipart/form-data" method="post" action="upload.php">
<label for="fileToUpload">Select Files to Upload</label><br />
<input type="file" name="fileToUpload[]" multiple="" id="fileToUpload" onchange="fileList();"/><br />
<input type="button" onclick="sendRequest();" value="Upload" />
<!-- a place for File Listing -->
<div id="fileList"></div>
</form>
<script type="text/javascript">
function sendRequest() {
var worker = new Worker("fileupload.js");
worker.onmessage = function(e) {
alert(e.data);
}
var file = document.getElementById('fileToUpload');
for(var i = 0; i < file.files.length; i++) {
worker.postMessage(file.files[i]);
}
}
推荐答案
我写了下面的 polyfill 来模拟 Web Workers 中的 FormData
方法.由于 Web Worker 不支持 DOM,因此也不支持 new FormData(
构造函数调用.File
和 Blob
对象、类型化数组和字符串都被 polyfill 支持.
I have written the following polyfill to emulate the FormData
method in Web Workers. Since Web workers do not support DOM, the new FormData(<HTMLFormElement>);
constructor call is not supported either.
File
and Blob
objects, typed arrays and strings are supported by the polyfill though.
它最初是作为 在 Google Chrome 扩展程序中上传文件的答案的一部分发布的.要查看如何使用它的示例,请查看其他答案.
It was originally posted as a part of the answer to Upload a File in a Google Chrome Extension. To see an example of how it can be used, have a look at the other answer.
/*
* FormData for XMLHttpRequest 2 - Polyfill for Web Worker (c) 2012 Rob W
* License: Creative Commons BY - http://creativecommons.org/licenses/by/3.0/
* - append(name, value[, filename])
* - toString: Returns an ArrayBuffer object
*
* Specification: http://www.w3.org/TR/XMLHttpRequest/#formdata
* http://www.w3.org/TR/XMLHttpRequest/#the-send-method
* The .append() implementation also accepts Uint8Array and ArrayBuffer objects
* Web Workers do not natively support FormData:
* http://dev.w3.org/html5/workers/#apis-available-to-workers
**/
(function() {
// Export variable to the global scope
(this == undefined ? self : this)['FormData'] = FormData;
var ___send$rw = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype['send'] = function(data) {
if (data instanceof FormData) {
if (!data.__endedMultipart) data.__append('--' + data.boundary + '--
');
data.__endedMultipart = true;
this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + data.boundary);
data = new Uint8Array(data.data).buffer;
}
// Invoke original XHR.send
return ___send$rw.call(this, data);
};
function FormData() {
// Force a Constructor
if (!(this instanceof FormData)) return new FormData();
// Generate a random boundary - This must be unique with respect to the form's contents.
this.boundary = '------RWWorkerFormDataBoundary' + Math.random().toString(36);
var internal_data = this.data = [];
/**
* Internal method.
* @param inp String | ArrayBuffer | Uint8Array Input
*/
this.__append = function(inp) {
var i=0, len;
if (typeof inp === 'string') {
for (len=inp.length; i<len; i++)
internal_data.push(inp.charCodeAt(i) & 0xff);
} else if (inp && inp.byteLength) {/*If ArrayBuffer or typed array */
if (!('byteOffset' in inp)) /* If ArrayBuffer, wrap in view */
inp = new Uint8Array(inp);
for (len=inp.byteLength; i<len; i++)
internal_data.push(inp[i] & 0xff);
}
};
}
/**
* @param name String Key name
* @param value String|Blob|File|Uint8Array|ArrayBuffer Value
* @param filename String Optional File name (when value is not a string).
**/
FormData.prototype['append'] = function(name, value, filename) {
if (this.__endedMultipart) {
// Truncate the closing boundary
this.data.length -= this.boundary.length + 6;
this.__endedMultipart = false;
}
var valueType = Object.prototype.toString.call(value),
part = '--' + this.boundary + '
' +
'Content-Disposition: form-data; name="' + name + '"';
if (/^[object (?:Blob|File)(?:Constructor)?]$/.test(valueType)) {
return this.append(name,
new Uint8Array(new FileReaderSync().readAsArrayBuffer(value)),
filename || value.name);
} else if (/^[object (?:Uint8Array|ArrayBuffer)(?:Constructor)?]$/.test(valueType)) {
part += '; filename="'+ (filename || 'blob').replace(/"/g,'%22') +'"
';
part += 'Content-Type: application/octet-stream
';
this.__append(part);
this.__append(value);
part = '
';
} else {
part += '
' + value + '
';
}
this.__append(part);
};
})();
相关文章