Hi everyone and happy new year :)
I want to upload a file using XHR and web workers, sending chunks of the file and merging at the end. The problem is that the end file is empty, I think that the issue is in the content type of XHR request that will should send a correct "multipart/form-data" (when uploading a chunk), since that PHP print_r($_FILES) returns an empty Array() but in the web worker it's not possible to use FormData(). Help me to resolve this trouble, please :'(
index.html
<form onsubmit="return false" enctype="multipart/form-data">
<input id="file" type="file">
<div id="filedrop">or drop files here</div>
</form>
<script>
window.addEventListener("load", function() {
var fileselect = document.getElementById("file");
fileselect.addEventListener("change", FileSelectHandler, false);
var filedrag = document.getElementById("filedrop");
filedrag.addEventListener("dragover", FileDragHover, false);
filedrag.addEventListener("dragleave", FileDragHover, false);
filedrag.addEventListener("drop", FileSelectHandler, false);
}, false);
function FileDragHover(e) {
e.stopPropagation();
e.preventDefault();
}
function FileSelectHandler(e) {
FileDragHover(e);
var blob = e.target.files[0] || e.dataTransfer.files[0];
worker = new Worker("upload.webworker.js");
worker.postMessage(blob);
worker.onmessage = function(e) {
console.log(e);
};
}
</script>
uploadFile.php
<?
if ($_GET['a'] == "chunk") {
$target = "upload/" . $_GET['name'] . '-' . $_GET['index'];
move_uploaded_file($_FILES['file']['tmp_name'], $target);
sleep(1);
} else {
$target = "upload/" . $_GET['name'];
$dst = fopen($target, 'wb');
$slices = (int)$_GET['slices'];
for ($i = 0; $i < $slices; $i++) {
$slice = $target . '-' . $i;
$src = fopen($slice, 'rb');
stream_copy_to_stream($src, $dst);
fclose($src);
unlink($slice);
}
fclose($dst);
}
?>
upload.webworker.js
function uploadChunk(blob, index, start, end, slices, slices2) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
slices--;
if (slices == 0) {
var xhrMerge = new XMLHttpRequest();
xhrMerge.open("POST", "uploadFile.php?a=merge&name=" + blob.name + "&slices=" + slices2);
xhrMerge.onload = function() {
self.close();
};
xhrMerge.send();
}
};
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) self.postMessage(Math.round(100 / e.total * e.loaded)); //this doesn't work o.O
};
var chunk = blob.slice(start, end);
xhr.open("POST", "uploadFile.php?a=chunk&name=" + blob.name + "&index=" + index);
xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=--------------------");
xhr.send(chunk);
}
self.onmessage = function(e) {
const BYTES_PER_CHUNK = 1024 * 1024 * 32;
var blob = e.data,
start = 0,
index = 0,
slices = Math.ceil(blob.size / BYTES_PER_CHUNK),
slices2 = slices;
while (start < blob.size) {
end = start + BYTES_PER_CHUNK;
if (end > blob.size) end = blob.size;
uploadChunk(blob, index, start, end, slices, slices2);
start = end;
index++;
}
};
PS: if you want, tell me please how to optimize the upload in general =)
PPS: I'll should take advantages using synchronous ajax requests (only in the web worker) ?
PPPS: and if I to use php://input for reading chunk, it's better ?
I resolved reading file from php://input with this code:
$putdata = fopen("php://input", "r");
$fp = fopen($target, "w");
while ($data = fread($putdata, 16384)) {
fwrite($fp, $data);
}
fclose($fp);
fclose($putdata);
In this way, I don't need to write the HTTP headers of the multipart/form-data
Related
I'm trying to make an online file manager for another project with friends, and when uploading files bigger than 1GB, the process either crashes (firefox), or succeeds but the received file weighs 0 bytes (chromium).
JS:
function uploadFile(fileInputId, fileIndex) {
//send file name
try {
var fileName = document.getElementById('fileUploader').files[0].name;
}
catch {
document.getElementById('uploadStatus').innerHTML = `<font color="red">Mettre un fichier serait une bonne idée.</font>`;
return false;
}
document.cookie = 'fname=' + fileName;
//take file from input
const file = document.getElementById(fileInputId).files[fileIndex];
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onloadend = function(event) {
ajax = new XMLHttpRequest();
//send data
ajax.open("POST", 'uploader.php', true);
//all browser supported sendAsBinary
XMLHttpRequest.prototype.mySendAsBinary = function(text) {
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0)
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
if (typeof window.Blob == "function") {
var blob = new Blob([data]);
}else {
var bb = new (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder)();
bb.append(data);
var blob = bb.getBlob();
}
this.send(blob);
}
//track progress
var eventSource = ajax.upload || ajax;
eventSource.addEventListener('progress', function(e) {
//percentage
var position = e.position || e.loaded;
var total = e.totalSize || e.total;
var percentage = Math.round((position/total)*100);
document.getElementById('uploadStatus').innerHTML = `${percentage}%`;
});
ajax.onreadystatechange = function() {
if(ajax.readyState == 4 && ajax.status == 200) {
document.getElementById('uploadStatus').innerHTML = this.responseText;
}
}
ajax.mySendAsBinary(event.target.result);
}
}
PHP:
//mysql login
$conn = new PDO([Redacted]);
//file info
$fileName = $_COOKIE['fname'];
$targetDir = "uploads/";
$targetFile = $targetDir.$fileName;
$fileNameRaw = explode('.', $fileName)[0]; //file name with no extension
$tempFilePath = $targetDir.$fileNameRaw.'.tmp';
if (file_exists($targetFile)) {
echo '<font color="red">Un fichier du même nom existe déjà.</font>';
exit();
}
//read from stream
$inputHandler = fopen('php://input', 'r');
//create temp file to store data from stream
$fileHandler = fopen($tempFilePath, 'w+');
//store data from stream
while (true) {
$buffer = fgets($inputHandler, 4096);
if (strlen($buffer) == 0) {
fclose($inputHandler);
fclose($fileHandler);
break;
}
fwrite($fileHandler, $buffer);
}
//when finished
rename($tempFilePath, $targetFile);
chmod($targetFile, 0777);
echo 'Fichier envoyé avec succès !';
$bddInsert = $conn->prepare('INSERT INTO files(nom, chemin) VALUES(?,?)');
$bddInsert->execute(array($fileName, $targetFile));
in my php.ini,
max_execution_time is set to 0
max_input_time to -1
and my post max and upload max sizes are at 4G
I'm using apache2
You should not be reading the file with the fileReader if you don't need it.
Just send the file (blob) directly to your ajax request and avoid the FileReader
function uploadFile (fileInputId, fileIndex) {
// Send file name
try {
var fileName = document.getElementById('fileUploader').files[0].name;
}
catch {
document.getElementById('uploadStatus').innerHTML = `<font color="red">Mettre un fichier serait une bonne idée.</font>`;
return false;
}
document.cookie = 'fname=' + fileName;
// Take file from input
const file = document.getElementById(fileInputId).files[fileIndex];
const ajax = new XMLHttpRequest();
// send data
ajax.open("POST", 'uploader.php', true);
// track progress
ajax.upload.addEventListener('progress', function(e) {
// percentage
var position = e.position || e.loaded;
var total = e.totalSize || e.total;
var percentage = Math.round((position/total)*100);
document.getElementById('uploadStatus').innerHTML = `${percentage}%`;
});
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
document.getElementById('uploadStatus').innerHTML = this.responseText;
}
}
ajax.send(file)
}
I am working with a file chunking solution ( cant remember where I found it ) but I have modified the solution to my needs.
The issue is that although most of the time the file will upload successfully sometimes I get an error
Uncaught SyntaxError: Unexpected token < in JSON at position 0
I also get another error at the same time
( unlink(test/H2jig-6.png): Resource temporarily unavailable in ... )
I was hoping that you guys will be able to spot the issue in my code that is causing this problem. I think that it manages to unlink the files too early before the uploads are done and then is unable to find them.
Upload file HTML/JS
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>test upload by chunk</title>
</head>
<body>
<input type="file" id="f" />
<script>
function makeid() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
(function() {
var f = document.getElementById('f');
if (f.files.length)
processFile();
f.addEventListener('change', processFile, false);
function processFile(e) {
var scount = 0;
var file = f.files[0];
console.log(file);
var ext = file.name.split('.').pop();
ext = '.'+ext;
var size = file.size;
var sliceSize = 250000;
var num_of_slices = Math.ceil(size / sliceSize);
var fileid = makeid();
var start = 0;
setTimeout(loop, 1);
function loop() {
var end = start + sliceSize;
if (size - end < 0) {
end = size;
}
var s = slice(file, start, end);
scount ++;
send(s, start, end,scount,size,num_of_slices,ext,fileid);
if (end < size) {
start += sliceSize;
setTimeout(loop, 1);
}
}
}
function send(piece, start, end,scount,size,num_of_slices,ext,fileid) {
var formdata = new FormData();
var xhr = new XMLHttpRequest();
xhr.open('POST', 'uploadchunk2.php', true);
formdata.append('start', start);
formdata.append('end', end);
formdata.append('file', piece);
formdata.append('scount', scount);
formdata.append('fsize', size);
formdata.append('num_of_slices', num_of_slices);
formdata.append('ext', ext);
formdata.append('fileid', fileid);
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
// myFunction(myArr);
}
};
xhr.send(formdata);
}
/**
* Formalize file.slice
*/
function slice(file, start, end) {
var slice = file.mozSlice ? file.mozSlice :
file.webkitSlice ? file.webkitSlice :
file.slice ? file.slice : noop;
return slice.bind(file)(start, end);
}
function noop() {
}
})();
</script>
</body>
</html>
PHP upload
<?php
$target_path = '/test/';
$tmp_name = $_FILES['file']['tmp_name'];
$filename = $_FILES['file']['name'];
$target_file = $target_path.$filename;
$num_chunks_uploaded = $_POST['scount'];
$num_chunks_created = $_POST['num_of_slices'];
$extension = $_POST['ext'];
$file_id = $_POST['fileid'];
$file_location = 'test/';
$file_path = $file_location.$file_id.$extension;
$chunked_file_path = $file_location.$file_id.'-'.$num_chunks_uploaded.$extension;
move_uploaded_file(
$_FILES['file']['tmp_name'],
$chunked_file_path
);
// count amount of uploaded chunks
$chunksUploaded = 0;
for ($i=1; $i <= $num_chunks_created ; $i++) {
if ( file_exists($file_location.$file_id.'-'.$i.$extension) ) {
++$chunksUploaded;
}
}
// when this triggers - that means the chunks are uploaded
if ($chunksUploaded == $num_chunks_created) {
/* here you can reassemble chunks together */
for ($i = 1; $i <= $num_chunks_created; $i++) {
$file = fopen($file_location.$file_id.'-'.$i.$extension, 'rb');
$buff = fread($file, 2097152);
fclose($file);
$final = fopen($file_path, 'ab');
$write = fwrite($final, $buff);
fclose($final);
unlink($file_location.$file_id.'-'.$i.$extension);
}
}
$data = $chunksUploaded;
header('Content-Type: application/json');
echo json_encode($_POST);
?>
This isn't the answer to your problem, but it solves one problem you do have in your JavaScript.
PHP requires that a MAX_FILE_SIZE field be sent with uploaded files. This field must appear before the file field in the POST variables. So you need to add:
formdata.append('MAX_FILE_SIZE', 1000000) // or whatever you want the max size to be
before the field containing the file to be sent.
Currently my entire code is working almost flawlessly, how ever upon upload the ajax data is not being displayed on my webpage after a successful upload.
Below is the code I am using (completely) because I am rather new and have been reviewing various stack over flow posts to guide me in building this.
Sorry for lack of structure below.. I don't know how to adapt to stack overflows structure requirements..
The actual form input / submit
<form action="upload2.php" class="upload" enctype="multipart/form-data" id="upload" method="post" name="upload">
<fieldset>
<legend>Uplaod Files</legend> <input id="file" multiple name="file[]" required="" type="file"> <input id="submit" name="submit" type="submit" value="upload">
</fieldset>
<div class="bar">
<span class="bar-fill" id="pb"><span class="bar-fill-text" id="pt"></span></span>
</div>
<div class="uploads" id="uploads"></div>
</form>
Here's the PHP code I am using to upload the file.
<?
header('Content-Type: application/json');
$upload = [];
$allowed = ['mp3', 'm4a'];
$succeeded = [];
$failed = [];
if (!empty($_FILES['file'])) {
foreach ($_FILES['file']['name'] as $key => $name) {
if ($_FILES['file']['error'][$key] === 0) {
$temp = $_FILES['file']['tmp_name'][$key];
$file_name = $_FILES['file']['name'][$key];
$file_size = $_FILES['file']['size'][$key];
$ext = explode('.', $name);
$ext = strtolower(end($ext));
$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 4)), 0, 4);
$file = $s . '.' . $ext;
$data = $file_name . PHP_EOL . $file_size;
file_put_contents('d/' . $s . '.txt', $data);
if (in_array($ext, $allowed) === true && move_uploaded_file($temp, "v/{$file}") === true) {
$succeeded[] = array(
'name' => $name,
'file' => $file,
);
} else {
$failed[] = array(
'name' => $name
);
}
}
}
if (isset($_POST['ajax'])) {
echo json_encode(array(
'succeeded' => $succeeded,
'failed' => $failed
));
}
}
Below is javascript event listener + the returned data from ajax
document.getElementById('submit').addEventListener('click', function (e) {
e.preventDefault();
var f = document.getElementById('file'),
pb = document.getElementById('pb'),
pt = document.getElementById('pt');
app.uploader({
files: f,
progressBar: pb,
progressText: pt,
processor: 'upload2.php',
finished: function (data) {
var uploads = document.getElementById('uploads'),
succeeded = document.createElement('div'),
failed = document.createElement('div'),
anchor,
span,
x;
if (data.failed.length) {
failed.innerHTML = '<p>file didnt upload<\/p>';
}
uploads.innerText = '';
for (x = 0; x < data.succeeded.length; x = x + 1) {
anchor = document.createElement('a');
anchor.href = 'uploads/' + data.succeeded[x].file;
anchor.innerText = data.succeeded[x].name;
archor.target = '_blank';
console.log(anchor);
succeeded.appendChild(anchor);
}
uploads.appendChild(succeeded);
},
});
});
Below is the javascript we're using for ajax (I think the issue is here but I keep reviewing it and I'm not able to find the problem.)
var app = app || {};
(function (o) {
"use strict";
var ajax, getFormData, setProgress;
ajax = function (data) {
var xmlhttp = new XMLHttpRequest(),
uploaded;
xmlhttp.addEventListener('readystatechange', function () {
if (this.readystate === 4) {
if (this.status === 200) {
uploaded = JSON.parse(this.response);
if (typeof o.options.finished === 'function') {
o.options.finished(uploaded);
}
} else {
if (typeof o.options.error === 'function') {
o.options.error();
}
}
}
});
xmlhttp.upload.addEventListener('progress', function (event) {
var percent;
if (event.lengthComputable === true) {
percent = Math.round((event.loaded / event.total) * 100);
setProgress(percent);
}
});
xmlhttp.open('post', o.options.processor);
xmlhttp.send(data);
};
getFormData = function (source) {
var data = new FormData(),
i;
for (i = 0; i < source.length; i = i + 1) {
data.append('file[]', source[i]);
}
data.append('ajax', true);
return data;
};
setProgress = function (value) {
if (o.options.progressBar !== undefined) {
o.options.progressBar.style.width = value ? value + '%' : 0;
}
if (o.options.progressText !== undefined) {
o.options.progressText.innerText = value ? value + '%' : '';
}
};
o.uploader = function (options) {
o.options = options;
if (o.options.files !== undefined) {
ajax({});
ajax(getFormData(o.options.files.files));
}
}
}(app));
My file is uploading, the progress bar is working and without returning e.preventDefault(); when it redirect to upload2.php I'm able to see the contents of the json i really don't know what my problem could be..
First of all, you have a typo in anchor here:
archor.target = '_blank';
Maybe this throws error and stops other code execution
Also you could check if your uploads div is visible via element inspector in browser.
If console.log shows nothing - do you mean by this it is not even called or it shows undefined? If it doesn't show at all, then look into the for that uses data.succeeded.length param as a limit - maybe it equals 0 and thus console.log is never called
I am running into issues when uploading an image sent to PHP via JS. I can upload the image fine, but I would to resize the image before moving it to it's new destination. I can also rename the image without any issues. It's really just the resizing that is the issue here.
After a lot of searching I have seen a lot of questions regarding this on SO, which is how I got to where I am now, but not one that answers this 100%. If you know of a question/answer already on SO please link me to the correct article.
Any help is much appreciated, thanks.
Here is the JS
var test = document.querySelector('#afile');
test.addEventListener('change', function() {
var file = this.files[0];
var fd = new FormData();
fd.append('afile', file);
// These extra params aren't necessary but show that you can include other data.
fd.append('id', burgerId);
var xhr = new XMLHttpRequest();
// why wont this work in the actions directory?
xhr.open('POST', 'actions/upload.php', true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
var uploadProcess = document.getElementById('uploadProcess');
uploadProcess.setAttribute('style', 'width: ' + percentComplete + '%;');
// uploadProcess.innerHTML = parseInt(percentComplete) + '% uploaded';
}
};
xhr.onload = function() {
if (this.status == 200) {
var resp = JSON.parse(this.response);
image = 'img/' + resp.newFileName;
sessionStorage.setItem('burgerLoc', image);
var image = document.createElement('img');
image.src = resp.dataUrl;
document.body.appendChild(image);
};
};
xhr.send(fd);
// upImage(id)
}, false);
Here is the markup
<input type="file" name="afile" id="afile" accept="image/*"/>
Here is the PHP
$image = $_FILES['afile']['name'];
$image_tmp = $_FILES['afile']['tmp_name'];
$image_type = $_FILES['afile']['type'];
function getName($str) {
$parts = explode('.',$str);
$imgName = str_replace(' ', '_',$parts[0]);
return $imgName;
}
function getExtension($str) {
$parts = explode('.',$str);
$ext = $parts[1];
return $ext;
}
$image_name = stripslashes($image);
$name = getName($image_name);
$image_ext = getExtension($image_name);
$ext = strtolower($image_ext);
if($ext == 'jpg' || $ext == 'jpeg' ) {
$ext = 'jpg';
$src = imagecreatefromjpeg($image_tmp);
} else if($ext == 'png') {
$src = imagecreatefrompng($image_tmp);
} else {
$src = imagecreatefromgif($image_tmp);
}
$file_content = file_get_contents($image_tmp);
$data_url = 'data:' . $image_type . ';base64,' . base64_encode($file_content);
list($width,$height) = getimagesize($image_tmp);
// width of the main image
$new_width = 748;
$new_height = ($height / $width) * $new_width;
$img_dest = imagecreatetruecolor($new_width,$new_height);
imagecopyresampled($img_dest,$src,0,0,0,0,$new_width,$new_height,$width,$height);
// rename the file
$new_file_name = strtolower($_REQUEST['id'] . '.' . $ext);
$new_file_location = '../img/' . $new_file_name;
imagejpeg($img_dest,$new_file_name,100);
move_uploaded_file($image_tmp, $new_file_location);
imagedestroy($src);
imagedestroy($img_dest);
$json = json_encode(array(
'dataUrl' => $data_url,
'extension' => $ext,
'id' => $_REQUEST['id'],
'name' => $image,
'newFileName' => $new_file_name,
'type' => $image_type
));
echo $json;
I would maybe try installing ImageMagick in your linux distribution and try to use this function to resize the image
http://php.net/manual/en/imagick.resizeimage.php
I have reproduced your script on my webserver... I have made modifications and came up with this.
The most significant modification is that I am using exact paths in the file locations, and that I am moving the tmp file to a real file, load that real file, resize that real file instead of trying it to do with the tmp uploaded file.
PHP:
<?php
$image = $_FILES['afile']['name'];
$image_tmp = $_FILES['afile']['tmp_name'];
$image_type = $_FILES['afile']['type'];
function getName($str) {
$parts = explode('.',$str);
$imgName = str_replace(' ', '_',$parts[0]);
return $imgName;
}
function getExtension($str) {
$parts = explode('.',$str);
$ext = $parts[1];
return $ext;
}
$image_name = stripslashes($image);
$name = getName($image_name);
$image_ext = getExtension($image_name);
$ext = strtolower($image_ext);
$outputfolder = "/var/www/html/wp-content/";
$new_file_name = strtolower($_REQUEST['id'] . '.' . $ext);
$new_file_location = $outputfolder.$new_file_name;
move_uploaded_file($image_tmp, $new_file_location);
if($ext == 'jpg' || $ext == 'jpeg' ) {
$ext = 'jpg';
$src = imagecreatefromjpeg($new_file_location);
} else if($ext == 'png') {
$src = imagecreatefrompng($new_file_location);
} else {
$src = imagecreatefromgif($new_file_location);
}
list($width,$height) = getimagesize($new_file_location);
// width of the main image
$new_width = 748;
$new_height = ($height / $width) * $new_width;
$img_dest = imagecreatetruecolor($new_width,$new_height);
imagecopyresampled($img_dest,$src,0,0,0,0,$new_width,$new_height,$width,$height);
$resizedLocation = $outputfolder."resized_".$new_file_name;
imagejpeg($img_dest,$resizedLocation,100);
imagedestroy($src);
imagedestroy($img_dest);
$file_content = file_get_contents($resizedLocation);
$data_url = 'data:image/jpeg;base64,' . base64_encode($file_content);
$json = json_encode(array(
'dataUrl' => $data_url,
'extension' => $ext,
'id' => $_REQUEST['id'],
'name' => $image,
'newFileName' => $new_file_name,
'type' => $image_type
));
echo $json;
?>
Your HTML/JS stays untouched.
Now this works for me flawlessly, the only thing you have to make sure
the $outputfolder is writeable by the linux user under which the webeserver executing the php script is runnging (typically web-data...)
My web server:
CentOS Linux release 7.0.1406 (Core)
php.x86_64 5.4.16-23.el7_0.3
apache x86_64 2.4.6
Anyone can help me with my code? I wanna build an upload function using HTML5 API. if I upload less than 1mb the file is alright. However, if file more than 1mb the file will be corrupted.
the HTML file :
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<form method="POST" action="upload.php" enctype='multipart/form-data'>
<input type="file" name="fileToUpload" id="file"><br />
<input type="submit" id="submit">
</form>
</body>
<script>
$(document).ready(function(){
$('#submit').on('click', function(e){
e.preventDefault();
sendRequest();
});
//window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
var bytes_per_chunk = 1048576; // 1mb chunk sizes.
var global_upload_counter = 0;
function sendRequest(){
var blob = document.getElementById('file').files[0];
var total_size = blob.size;
var start = 0;
var end = bytes_per_chunk;
// var counter = 1;
while(start < total_size)
{
// console.log('start : ' + start + ', end :' + end + ' and counter : ', counter);
var chunk = blob.slice(start, end);
uploadFile(chunk, blob.name);
start = end;
end = start + bytes_per_chunk;
//counter++;
}
}
function uploadFile(chunk, filename){
var fd = new FormData();
fd.append('fileToUpload', chunk);
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', uploadComplete, false);
xhr.addEventListener('error', uploadFailed, false);
xhr.addEventListener('abort', uploadCanceled, false);
xhr.open('POST', 'upload.php?filename=' + filename);
xhr.send(fd);
}
function uploadComplete(evt) {
// This event is raised when the server send back a response
if (evt.target.responseText != ""){
alert(evt.target.responseText);
}
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
xhr.abort();
xhr = null;
}
});
</script>
</html>
PHP code (upload.php):
<?php
$target_path = "upload/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];
$filename = $_GET['filename'];
//$target_file = $target_path.$name;
$complete = $target_path. $filename;
// append; open or create binary file for writing at end-of-file
$com = fopen($complete, "ab");
error_log($target_path);
// read as binary
$in = fopen($tmp_name, "rb");
if($in){
while ($buff = fread($in, $size)){
fwrite($com, $buff);
}
}
fclose($in);
First of all, why do you want to separate the file into chunks? You can upload the whole file in a go via AJAX. The error that you are encountering might be due to the chunk logic.
Try removing the chunk logic and it will work just fine. So your upload function would look something like this:
$(document).ready(function(){
$('#submit').on('click', function(e){
e.preventDefault();
sendRequest();
});
//window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
var bytes_per_chunk = 1048576; // 1mb chunk sizes.
var global_upload_counter = 0;
function sendRequest(){
var blob = document.getElementById('file').files[0];
var total_size = blob.size;
uploadFile(blob,filename);
}
function uploadFile(chunk, filename){
var fd = new FormData();
fd.append('fileToUpload', chunk);
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', uploadComplete, false);
xhr.addEventListener('error', uploadFailed, false);
xhr.addEventListener('abort', uploadCanceled, false);
xhr.open('POST', 'upload.php?filename=' + filename);
xhr.send(fd);
}
function uploadComplete(evt) {
// This event is raised when the server send back a response
if (evt.target.responseText != ""){
alert(evt.target.responseText);
}
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
xhr.abort();
xhr = null;
}
});
Instead of chunks, send the full file and it should work.
If you are worried about the upload progress, here are a few solutions:
jQuery Upload Progress and AJAX file upload ,
File upload progress bar with jQuery
Looking at the answer provided by user470714 on uploading a file in chunks using html5 I found the issues.
Which the ajax didn't actually uploading the chunks in order. So I updated my HTML code as follow and now it works fine :
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<form method="POST" action="upload.php" enctype='multipart/form-data'>
<input type="file" name="fileToUpload" id="file"><br />
<input type="submit" id="submit">
</form>
</body>
<script>
$(document).ready(function(){
$('#submit').on('click', function(e){
e.preventDefault();
sendRequest();
});
//window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
var bytes_per_chunk = 1048576; // 1mb chunk sizes.
var global_upload_counter = 0;
function sendRequest(){
var blob = document.getElementById('file').files[0];
var total_size = blob.size;
window.upload_counter = 0;
window.upload_filearray = [];
var start = 0;
var end = bytes_per_chunk;
while(start < total_size)
{
var chunk = blob.slice(start, end);
window.upload_filearray[window.upload_counter] = chunk;
window.upload_counter++;
start = end;
end = start + bytes_per_chunk;
}
// initiate upload the first time
window.upload_counter = 0;
window.filename = blob.name;
uploadFile(window.upload_filearray[window.upload_counter]);
}
function uploadFile(chunk){
var fd = new FormData();
fd.append('fileToUpload', chunk);
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', uploadComplete, false);
xhr.addEventListener('error', uploadFailed, false);
xhr.addEventListener('abort', uploadCanceled, false);
xhr.open('POST', 'upload.php?filename=' + window.filename);
window.upload_counter++;
xhr.send(fd);
}
function uploadComplete(evt) {
// This event is raised when the server send back a response
if (evt.target.responseText != ""){
console.log(evt.target.responseText);
}
if(window.upload_filearray.length > window.upload_counter){
uploadFile(window.upload_filearray[window.upload_counter]);
}
}
function uploadFailed(evt) {
alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
xhr.abort();
xhr = null;
}
});
</script>
</html>