I have been working on a browser based file uploader that sends files to our S3 buckets for the past couple of months. I've made great progress in the last couple of weeks. However, my biggest road block came in the form of iDevices. Pretty much anything that runs on iOS 8 has been giving me major headaches relating to my uploader. I am able to run my program on Chrome, Firefox, and Safari on desktops/laptops on both PC and MAC. However, when it comes to mobile devices, only Android devices work the intended way. On iOS, Chrome only uploads small files and anything large will return a file that has a size of 0. Safari out right fails. I know that there have been issues with iOS 8 relating to this issue, but from my research, this issue should have been taken care of already. Anyways, I was wondering if there was a work around this problem so that I can upload my files like I am doing for the other devices and browsers.
Error uploading a small image file:
Syntax: JSON Parse error: Unexpected EOF
Failed to load resource: request body stream exhausted
Error uploading a big video file:
Failed to load resource: request body stream exhausted
SyntaxError: JSON Parse error: Unrecognized token '<'
If you would like to see any examples of my code, feel free to ask as I will edit my post for this request.
upload.js
var files; // Array of inputed files
var ownerName; // Inputed name of file owner
var totalSize = 0; // Total file size of all files
var loaded = 0; // Loaded data amount
var MB = 1024 * 1024; // 1 MB
var partSize = MB; // Data amount of part of chunk of file
var chunkSize = 5 * MB; // Data amount of chunk of file
function request(command, xhr, formdata){
xhr.open("POST", "FileUploader.php", true);
if(command === 'UploadPart' || command === 'PutObject')
xhr.upload.addEventListener("progress", progressHandler, false);
xhr.addEventListener("load", completeHandler, false);
xhr.addEventListener("error", errorHandler, false);
xhr.addEventListener("abort", abortHandler, false);
xhr.send(formdata);
return xhr;
}
function uploadFile(){
reset();
if (window.File && window.FileReader && window.FileList && window.Blob){
files = _("file").files;
totalSize = calcTotalSize(files);
for (var i = 0; i < files.length; i++){
var key = createKey(_("name").value, files[i]);
if (files[i].size >= chunkSize)
createMultipartUpload(i, key);
else
putObject(i, key);
}
}
else
alert("Your browser does not support our File Uploader.");
}
function createMultipartUpload(i, key){
var formdata = new FormData();
formdata.append("command", 'CreateMultipartUpload');
formdata.append("fileindex", i);
formdata.append("key", key);
var xhr = request('CreateMultipartUpload', new XMLHttpRequest(), formdata);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4)
uploadPart(JSON.parse(xhr.responseText), 1);
};
}
function uploadPart(sendBackData, partNum){
console.log("Uploading part " + partNum);
var fileIndex = sendBackData['fileindex'];
var file = files[fileIndex];
if (partNum > Math.ceil(file.size / chunkSize)) {
completeMultipartUpload(sendBackData);
return;
}
var blobs = [];
var start = (partNum - 1) * chunkSize;
var end = start + partSize;
var index = 0;
while (start < chunkSize*partNum){
blobs.push(file.slice(start, end));
start = end;
end = start + partSize;
index++;
}
var formdata = new FormData();
for(var i = 0; i < index; i++)
formdata.append("file[]", blobs[i]);
formdata.append("command", 'UploadPart');
formdata.append("uploadId", sendBackData['uploadId']);
formdata.append("key", sendBackData['key']);
formdata.append("partNumber", partNum);
var xhr = request('UploadPart', new XMLHttpRequest(), formdata);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4)
uploadPart(sendBackData, partNum + 1);
};
}
function completeMultipartUpload(sendBackData) {
var formdata = new FormData();
formdata.append("command", 'CompleteMultipartUpload');
formdata.append("uploadId", sendBackData['uploadId']);
formdata.append("key", sendBackData['key']);
var xhr = request('CompleteMultipartUpload', new XMLHttpRequest(), formdata);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var sendBackData = JSON.parse(xhr.responseText);
if(sendBackData['success'])
displayURL(sendBackData['url']);
}
};
}
FileUploader.php
<?php
function sendJson($arr)
{
header('Content-Type: application/json');
die(json_encode($arr));
}
$s3 = S3Client::factory(array(
'key' => AWS_KEY,
'secret' => AWS_SECRET_KEY
));
$command = $_POST['command'];
s3Command($command);
function s3Command($command){
$key = $_POST['key'];
switch ($command) {
case 'CreateMultipartUpload':
$fileindex = $_POST['fileindex'];
$response = $GLOBALS["s3"]->createMultipartUpload(array(
'Bucket' => TMP_IMG,
'Key' => $key,
'ACL' => 'public-read',
));
$uploadId = $response['UploadId'];
sendJson(array(
'uploadId' => $uploadId,
'key' => $key,
'fileindex' => $fileindex
));
break;
case 'UploadPart':
$tmp_files = $_FILES['file'];
$files = array();
for ($i = 0; $i < count($tmp_files['name']); $i++){
$files[] = array(
'name' => $tmp_files['name'][$i],
'tmp_name' => $tmp_files['tmp_name'][$i],
'type' => $tmp_files['type'][$i],
'size' => $tmp_files['size'][$i],
'error' => $tmp_files['error'][$i]
);
}
$body = mergeFiles($files);
$result = $GLOBALS["s3"]->uploadPart(array(
'Bucket' => TMP_IMG,
'Key' => $key,
'UploadId' => $_POST['uploadId'],
'PartNumber'=> $_POST['partNumber'],
'Body' => $body
));
break;
case 'CompleteMultipartUpload':
$partsModel = $GLOBALS["s3"]->listParts(array(
'Bucket' => TMP_IMG,
'Key' => $key,
'UploadId' => $_POST['uploadId']
));
$model = $GLOBALS["s3"]->completeMultipartUpload(array(
'Bucket' => TMP_IMG,
'Key' => $key,
'UploadId' => $_POST['uploadId'],
'Parts' => $partsModel['Parts'],
));
$url = $GLOBALS["s3"]->getObjectUrl(TMP_IMG, $key);
$type = explode('/', $key);
if($type[0] == 'image'){
$result = $GLOBALS["s3"]->getObject(array(
'Bucket' => TMP_IMG,
'Key' => $key
));
$body = $result['Body'];
$url = resizeImage($url);
}
sendJson(array(
'success' => true,
'url' => $url
));
break;
case 'AbortMultipartUpload':
$s3->abortMultipartUpload(array(
'Bucket' => TMP_IMG,
'Key' => $key,
'UploadId' => $_POST['uploadId']
));
break;
}
}
?>