How can I compress JSON and uncompress on PHP? - javascript

BTW, this is not a duplicate, I'm not trying to compress in PHP, I'm trying to compress Client Side and uncompress in PHP.
I'm trying to compress a JSON array containing 5 base64 images and some text to my PHP api.
I have tried lz-string and pako and it appears to be sending the compressed payload as expected but I'm having issues decompressing on the PHP backend.
Typescript Gzip.
var payload = pako.gzip(JSON.stringify(data), { to: 'string' });
let headers = new Headers({ "Content-Encoding" : "gzip"});
headers.append('Content-Type', 'application/json; charset=x-user-defined-binary');
let requestOptions = new RequestOptions({ headers: headers });
var url = this.baseUrl + "/app/notice/issue/compressed";
return this.http.post(url, data, requestOptions).pipe(timeout(100000), map(res => { return res.json() }), catchError(err => { return throwError(err.message); }));
PHP
$input = file_get_contents("php://input");
$test = gzdecode($input);
echo $test;
Output
"
<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
<h4>A PHP Error was encountered</h4>
<p>Severity: Warning</p>
<p>Message: gzdecode(): data error</p>
</div>"
If anyone can help in reducing the size of my JSON, that would be really helpful.
Thanks.

You PHP exapmle looks fine and should work.
I'm not sure about the Typescript part: binary string can be additionaly encoded (as UTF-8 maybe?) before being sent by browser or http.post() method.
Check sent Content-Length of the request and actual length of the binary string after compression. They obviously must be the same.
I suggest removing {to: 'string'} option in pako.gzip() method to get Uint8Array instead of string and use XMLHttpRequest instead of http.post()
See also:
Angular Post Binary Data
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data

Related

Does there exist a 'good-practice' way to send files without relying on FormData?

I'm currently working on an app with a React Native front-end and Node.js/Express backend. I am perfectly able to upload files using FormData with Content-Type multipart/form-data. The problem I have is that when using FormData, any other data that you wish to send in the body of the request is necessarily converted to a string. This isn't the case when one simply sends a JS object as the body of the request (as long you parse it on the backend of course). I wish to know if there is a good-practice way to send a file/files alongside JSON in a request, without losing the typings of said JSON?
Thanks
Add your data as JSON in a field of the FormData:
const data = {
foo: ["bar", 1]
};
const file = new File(["some content"], "myfile.txt");
const formdata = new FormData();
formdata.append("file", file);
// Send as JSON
formdata.append("data", JSON.stringify(data));
const req = new Request("./", { method: "POST", body: formdata });
// simulate server side getting the response
req.formData().then( (fd) => {
const received_file = fd.get("file");
// parse JSON
const received_data = JSON.parse(fd.get("data"));
console.log({ received_file, received_data });
});
When you insist on sending the image along with other data inside the JSON, then AFAIK your only option is to convert the image to some data type which can be transmitted via JSON.
The most obvious choice would be a string, and what is usually used here is the base64 encoding. It is, however, not very efficient and can cause lag.
What is sometimes done to stay within the JSON domain but still being able to upload images is to create two endpoints. One for the JSON data. One for the image upload in a binary format.

JavaScript Fetch: characters with encoding issues

I'm trying to use Fetch to bring some data into the screen, however some of the characters ares showing a weird � sign which I believe has something to do with converting special chars.
When debugging on the server side or if I call the servlet on my browser, the problem doesn't happen, so I believe the issue is with my JavaScript. See the code below:
var myHeaders = new Headers();
myHeaders.append('Content-Type','text/plain; charset=UTF-8');
fetch('getrastreiojadlog?cod=10082551688295', myHeaders)
.then(function (response) {
return response.text();
})
.then(function (resp) {
console.log(resp);
});
I think it is probably some detail, but I haven't managed to find out what is happening. So any tips are welcome
Thx
The response's text() function always decodes the payload as utf-8.
If you want the text in other charset you may use TextDecoder to convert the response buffer (NOT the text) into a decoded text with chosen charset.
Using your example it should be:
var myHeaders = new Headers();
myHeaders.append('Content-Type','text/plain; charset=UTF-8');
fetch('getrastreiojadlog?cod=10082551688295', myHeaders)
.then(function (response) {
return response.arrayBuffer();
})
.then(function (buffer) {
const decoder = new TextDecoder('iso-8859-1');
const text = decoder.decode(buffer);
console.log(text);
});
Notice that I'm using iso-8859-1 as decoder.
Credits: Schneide Blog
Maybe your server isn't returning an utf-8 encoded response, try to find which charset is used and then modify it in call headers.
Maybe ISO-8859-1 :
myHeaders.append('Content-Type','text/plain; charset=ISO-8859-1');
As it turns out, the problem was in how ther servlet was serving the data without explicitly informing the enconding type on the response.
By adding the following line in the Java servlet:
response.setContentType("text/html;charset=UTF-8");
it was possible got get the characters in the right format.

How to send file details to back end using angularjs?

Hi I am developing web application in angularjs. I am developing file upload module. I have below array with file details.
//below code to get array of files
$scope.showPicker=function()
{
var client = filestack.init('AGeDIRvVZTRWgtmFbfGuZz');
client.pick({
}).then(function (result) {
arrMakes.push(result.filesUploaded);
});
}
In the above image i shown my array. I have three files.
Below is my angular code to send details to api.
var files = new FormData();
angular.forEach(arrMakes, function (value, index) {
console.log(value,index);
files.append(index, value);
files.append('data', angular.toJson(index).replace(/['"]+/g, ''));
});
return $http.post(this.uploadUrl, files, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined,
}
})
The problem is i am not receiving file in server side. Below line gives me 0 files in server.
System.Web.HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;
May i know am i sending correct data to server? Can someone help me to fix this? Any help would be greatly appreciated. Thank you.
You are not uploading any files to the server, only strings.
You can't append objects to a FormData. appart from Blob & File objects See what will happen:
fd = new FormData
fd.append(2, {foo: 'bar'})
fd.append('data', 5)
new Response(fd).text().then(console.log)
// you get [object Object]
Why do you stringify the index in "data"? It will be casted to string automatically. And what is there that you have to replace?
If i where you i would just simple send the hole arrMakes to the server and download all the files from the url on the backend, otherwise the client has to download and then upload them to the server and wasting bandwidth and time.
beside, you don't need angulars forEach loop, arrays has that method built in
arrMakes.forEach(function (value, index) {
...
})
You won't even have to use any loop if you just pass the arrMarks to the server

How to save zip file represented as a string in Node js

I have a response from an ebay-api
--MIMEBoundaryurn_uuid_C91296EA5FF69EE9571479882375576565344 Content-Type: application/xop+xml; charset=utf-8; type="text/xml"
Content-Transfer-Encoding: binary Content-ID:
<0.urn:uuid:C91296EA5FF69EE9571479882375576565345>
Success1.1.02016-11-23T06:26:15.576Z514
--MIMEBoundaryurn_uuid_C91296EA5FF69EE9571479882375574545344 Content-Type: application/zip Content-Transfer-Encoding: binary
Content-ID:
PKY'uIi[��#�50014028337_report.xmlUT y�2Xy�2Xux
00�R�j�#��+��[��PlX#�(�x,=l�q]Lfewc��w Ĥ��O��١�HT���t��GGT�
��6�;���'������.$����=d����m;c}Wߦ�RW�A
f�����g�I��4U��x��3��f���ғ{f��xj�,+���ۖI%5��B's��G,#��t,L{�c�����MD笓��)!�9��
�M�o;8_��<�i�y����sz���u���=��Ջ^2�S��%+2�2�`QV�$�����~?�w�ǥ�_Q�퉦�'PKY'uIi[��#���50014028337_report.xmlUTy�2Xux
00PK\�
--MIMEBoundaryurn_uuid_C91296EA5FF69EE9571479882375576565344--
This is of type string. and i extracted the attached zip file data i.e.
PKY'uIi[��#�50014028337_report.xmlUT y�2Xy�2Xux
00�R�j�#��+��[��PlX#�(�x,=l�q]Lfewc��w Ĥ��O��١�HT���t��GGT�
��6�;���'������.$����=d����m;c}Wߦ�RW�A
f�����g�I��4U��x��3��f���ғ{f��xj�,+���ۖI%5��B's��G,#��t,L{�c�����MD笓��)!�9��
�M�o;8_��<�i�y����sz���u���=��Ջ^2�S��%+2�2�`QV�$�����~?�w�ǥ�_Q�퉦�'PKY'uIi[��#���50014028338_report.xmlUTy�2Xux
00PK\�
This shows that it has a report.xml in it. So when i write this data in a zip file, it creates a zip file and upon extract gives error.
fs.writeFile("./static/DownloadFile.zip", fileData, 'binary', function(err){
if (err) throw err;
console.log("success");
});
How can i write this data in a zip file properly. Pls advice. If required any more information.
EDIT:
I tried writing the zip file in PHP and is succssfully writing it with this code:
$zipFilename="DownloadFile.zip";
$data = $fileData;
$handler = fopen($zipFilename, 'wb')
or die("Failed. Cannot Open $zipFilename to Write!</b></p>");
fwrite($handler, $data);
fclose($handler);
Please advice how can i achieve the same thing in nodejs.
Depending on what HTTP Client you are using the implementation might change a little.
With axios I'm doing something like so:
I'm requesting a zip file so I specify the Accept header as application/zip
In order to get a buffer and not Binary, specify the responseType as arrayBuffer
const res = await axios.get('/routToThat/file', {
headers: {
Accept: 'application/zip',
},
responseType: 'arraybuffer',
});
By doing the latter, instead of receiving a Binary from the response:
A#B�ArE⏾�7�ϫ���f�걺N�����Yg���o_M^�D�T�U X_���e?� hi\...
I receive a Buffer:
Buffer(22781691) [80, 75, 3, …]
Once the request is resolved and I have that Buffer, I use that same writeFile function from fs
NOTE: I'm not specifying the Encoding in writeFile
fs.writeFile(name, res.data, (err) => {
if (err) throw err;
console.log("success");
});
As I see in your code example your binary data is already mangled by request module. Just use in request setting
encoding:null
and the zip file is a valid binary in body (now buffer instead of utf-8 string!) you can decompress. As long as you see the questions marks you still have the encoding issue.

Why is my Angular POST request to a PHP page not setting up the POST array?

I have a angular post that sends to my php file, but in the PHP file, I cannot access anything from the post variable. It returns my SUCCESS string, but nothing after that, so my return on the post is "SUCCESS - - - - - " where the data should be between the dashes.
JSON/JS object:
DESCRIPTION: "123321"
LOCATION: "ab_calgary_eighth_ave_pl"
NAME: "123321"
QUANTITY: 123321
TYPE: "cycle"
Angular POST Code:
$scope.insertNewInventoryItem = function()
{
if(typeof ($scope.newItem.LOCATION) == 'undefined')
alert("LocationCannot Be Empty. Please Select An Option From The Drop Down.");
else if(typeof ($scope.newItem.TYPE) == 'undefined')
alert("Type Cannot Be Empty. Please Select An Option From The Drop Down.");
else
{
$http.post("dataaccess/addnewinventory.php", $scope.newItem).then(onAddNewComplete, onAddNewError);
}
}
PHP Page attempting to find the posted values:
<?php
$con = mysqli_connect("localhost", "dbadminuser", "password", "database_demo_inventory");
// Check connection
if (mysqli_connect_errno())
{
echo "FAIL - Failed to connect to MySQL: " . mysqli_connect_error();
}
else
{
echo "SUCCESS - " . $HTTP_POST_VARS['newItem.NAME'] . " - " . $HTTP_POST_VARS['TYPE'] . " - " . $HTTP_POST_VARS["QUANTITY"] . " - " . $HTTP_POST_VARS . " - " . $_POST[0];
}
mysqli_close($con);
?>
Picture of the Request from GOOGLE developer tools:
Picture of return data from the request (see PHP code for where SUCCESS is coming from):
Why can I not access the post variables? Am I missing something here?
By default, Angular transmits data using the Content-Type: "application/json" and PHP can't parse the JSON data into the $_POST natively. You could follow these two steps to resolve this issue:
Step 1: Change the default value of header Content-Type:
angular.module("myApp",[], function($httpProvider){
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
})
Step 2: Convert the JSON data into key=value pair serialized data. (I'm using jQuery $.param function to convert the data)
$http({
method:"POST",
url: "post.php",
data: $.param($scope.newItem)
}).success(function(data, status, headers, config){
console.log(data);
}).error(function(data, status, headers, config){
console.log(status);
});
Note: $HTTP_POST_VARS is not a super global variable and it has been completely deprecated in PHP 5. I think you could use $_POST.
while chickenrice's answer is true and solves the issue, I'd prefer to use the JSON data as the payload at least for few reasons.
suits if your objects are complicated, contains nested structures.
It allows you to send any kind of object e.g. [[1,2],[3,4]] -
Array(array,array..) This is just impossible to send in uri-encoded
string.
It's not comfortable if you send simple "name=egor&type=lulzsec"
since it will look "verbose".
You CAN omit CSRF tokens with this!
To get this in PHP make use of file_get_contents("php://input"); to get the request body directly.
You would need to have a small wrapper around this. Moreover you might need to whitelist the content type headers to mitigate the CSRF.
EDIT
if (0 === strpos($_SERVER['CONTENT_TYPE'], 'application/json')) {
$input_json = file_get_contents('php://input');
$input= json_decode( $input_json, TRUE ); //convert JSON into array
}
My backend is Apache22/PHP5.4. I've been banging my head against the wall on this issue for days. Just now, I finally cracked it.
Setting content-type to application/x-www-form-urlencoded didn't get the data into input:// or $_POST. Then I came across this thread: https://groups.google.com/forum/#!topic/angular/MBf8qvBpuVE
Not setting Content-Type will make the underlying XHR browser implementation add a correct header
The keys is to set content-type: false. This is my working code, and I don't even have to get the data from input:// it goes directly to $_POST.
var serialized = $httpParamSerializer($scope.formData);
return $http({
method : 'POST',
url : 'your-url-here',
data : serialized,
headers : { 'Content-Type': false }
}).then(
function(response) {
return response;
},
//Network or server error
function(data, status, headers,config,statusText) {
console.log('AJAX failure: status='+status+', statusText='+statusText);
}
);
I am very new to AngularJS, and so I have no idea why setting the header didn't work for me.
For decoding the PHP, I used the following code, which gave me direct access into the POST data, which in my case was JSON. Apparently JSON is a unsupported data structure, so PHP failed to parse it automatically into the POST array:
$jsonText = file_get_contents('php://input');
$decodedText = html_entity_decode($jsonText);
$myArray = json_decode('[' . $decodedText . ']', true);
Explanation:
Line 1 gets the raw data that was sent over from the request (in this case it was from the Angular Controller posted in the OP.
Line 2 decodes the JSON array grabbed in step one, correctly forming it to parse later. Note that in this case, steps one and two both return the exact same looking object.
Line 3 takes the formatted JSON data and decodes it into a PHP array. Now you can use the following to access parts of the array:
$myvar = $myArray[0]["SOME_VARIABLE"];
Thanks for the answers guys!

Categories

Resources