Search code examples
javascriptphpajaxfile-uploadfileapi

Javascript chunked file upload to PHP Server


So I have this function in javascript to send parts of file to server:

function ajaxPartUpload(url, packageNo, file, attachmentId)
        {
            var packageMaxSize = 10240; //1048576; //10485760; //reduced for tests
            var packageCount =  Math.ceil(file.size / packageMaxSize);
            var start = packageNo * packageMaxSize;
            var stop = (packageNo+1) * packageMaxSize - 1; 
            if ((packageNo+1) === packageCount || packageCount === 0) {
                stop = file.size - 1;
            }
            var blob = file.slice(start, stop);
            var reader = new FileReader();

        reader.onloadend = function (evt) {
            if (evt.target.readyState === FileReader.DONE) {
                var data = {
                    blob: reader.result,
                    partNo: packageNo,
                    lastPartNo: packageCount,
                    fileName: file.name,
                    fileType: file.type,
                    fileSize: file.size,
                    attachmentId: attachmentId,
                    multipart: true
                };

                $.ajax({
                    url: url,
                    type: 'post',
                    dataType: 'json',
                    data: data,
                    success: function(response) {
                        if (response.continue === false) {

                            return true;
                        } else {
                            ajaxPartUpload(url, packageNo+1, file, response.attachmentId);
                        }

                    }
                });
            }
        };

        reader.readAsBinaryString(blob);
    }

And It's working as expected, I get in post the binary data of files I'm sending. Under specified url I have script that basicly do this:

$attachment = V()->Attachment->find($_POST['attachmentId']);
        $destination_path = $attachment->getPath();
    $filePointer = fopen($destination_path, 'a');
            $written = fwrite($filePointer, $_POST['blob']);
            if ($written == false )
            {
                throw new Exception('File data not written');
            }
            fclose($filePointer);

And as long as I have text files it's ok, but when I try to send binary file, the files I'm reciving are about 50% bigger in size, and corrupted, it doesn't matter if I make chunk size big enough to hold all file in one http request or not. What I'm doing wrong?

I have dumped length of 'blob' in javascript right before send and length of recived blob in php: I've got 2 compleatly diffrent results for one chunk max 1 MB file has '28KB' (got from ls -lash):

javascript: 25755

php: 36495

What happend? When I've tired text file all was ok.

@EDIT: Solution in JS change:

blob: reader.result,

to

blob: window.btoa(reader.result),

AND in PHP

$written = fwrite($filePointer, $_POST['blob']);

to

$written = fwrite($filePointer, base64_decode($_POST['blob']));

that solves the problem.


Solution

  • I've added atob in javascript on my result from reader, and then decoded data before reading with base64_decode. It solves the problem.

    The problem is that PHP interprets this binary data in some other way, as string perhaps, I don't really know. Anyway sending a 'bit' bigger encoded data saves a lot of nerves.