I am having a problem with a POSTed binary stream "growing" in transit/upon reception between an AngularJS app and a PHP backend.
The POST is pretty common to what I've done elsewhere...however, this mixes text and binary data... I'm not sure if this is sufficient...
var req = {
method: 'POST',
url: 'putInitialPicture.php',
data : {
"xuserid" : $scope.user.id,
"xauthtoken" : $scope.user.authtoken,
"data" : picdata
}
};
console.log("posting....");
$http(req)
.success(function (data, status, headers, config) {
console.log("returned from post");
console.log(data);
$scope.sync($scope.user.id);
})
.error(function(data, status, headers, config) {
console.log("error result");
console.log(data);
});
In the PHP code on the receiving function, I do the normal
$postdata = file_get_contents("php://input");
$_POST = json_decode($postdata, true);
to obtain the posted data
Later in the script, after validations are performed, and the destination filename is determined the data is written out with a simple
file_put_contents("$basename/$fname",$_POST['data']);
This is where things get... interesting.
The written file (an image file - a JPG) is not the same as I read on the Angular side. The file (as reported by Angular code that reads the data) is 5727 bytes.
The size on disk, after the data is POSTed, decoded, and written to disk by PHP, is 9992 bytes.
Somewhere between the server, the client and the server, it has not quite doubled. I can discount the initial GET operation, as the content being retrieved is being reported as the correct size.
It would seem that somewhere in the POST there's something happening to the binary stream to make it able to be sent that is more than a simple JSON decode is able to handle.... but I cant figure out what.
Is there a Header I need to set on the POST to have the webserver decode the data properly? or is there an additional decoding of the $_POST['data'] object needed prior to use?
I'm not sure what to try next here.. the questions/answers I google are all simple text... not a combination text/binary post.
EDIT - Solution - sort of
Sending the binary data is just a bad idea. Instead I opted for reuse of an Upload service I already had working. This required creation of a File object (more generically a blob) that I could toss the bytes downloaded from the remote server into, resulting in:
$scope.CreateBlob = function(Data, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = Data;
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0 ; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: contentType });
}
and replacing the $http.post(...) with
var blob = $scope.CreateBlob( picdata ,"image/jpg");
$scope.files = [];
$scope.files.push(blob);
Already having a $watch set on $scope.files the upload "just happens".
The weird thing now though... the $http.get(...) returns a picdata string that is shorter than the server says it is. According to the headers, the length the image should be 5886 bytes...
Accept-Ranges:bytes
Cache-Control:max-age=84600, public, no-transform
Content-Length:5886
Content-Type:image/jpeg
Date:Sun, 27 Sep 2015 04:06:10 GMT
ETag:"c01bf-16fe-520b2957e00e9"
Expires:Mon, 28 Sep 2015 03:36:10 GMT
Last-Modified:Sun, 27 Sep 2015 03:57:47 GMT
Server:Apache/2.2.22 (Debian)
However, when I log the picdata.length I'm getting 5727 bytes
Different problem.. different day..