How can you read POST data from a javascript XMLHttpRequest in Golang? - javascript

Here's the javascript function called:
function cwk_submit_form() {
var form = document.getElementById("FORM_ID")
var XHR = new XMLHttpRequest();
const FD = new FormData( form );
for (const element of FD.entries()) {
console.log(element)
}
XHR.open( "POST", "http://localhost:8080/post_data" );
XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
XHR.send( FD );
}
I left the console.log in there to mention that this does print out the correct data, meaning that the issue is seems to be in how the data is transferred.
The Golang code that receives the response is:
func post_data(w http.ResponseWriter, r *http.Request) {
log.Println("post was called")
r.ParseForm()
for key, value := range r.Form {
log.Printf("%s = %s\n", key, value)
}
}
Nothing is printed by this for loop.
If I use an HTML Form to submit like so:
<form action="//localhost:8080/post_data" method="POST">
<input type="text" name="field1" value="" maxLength="20"/>
<input type="text" name="field2" value="" maxLength="20"/>
<input type="submit" value="Sign in"/>
</form>
then the Golang code above works fine, which leads me to believe that the XMLHttpRequest format is the issue.

Your guess is right there is a problem in your js code.
For all requests, ParseForm parses the raw query from the URL and updates r.Form.
And hence, it will work when the Content-Type you send and the actual content type matches to application/x-www-form-urlencoded which happens in your HTML form case.
On the other hand, when you use FormData, it will be sent as multipart/form-data.
You need to replace your XHR.send(FD) with XHR.send(new URLSearchParams(FD)) in order to send the data in application/x-www-form-urlencoded.

Related

$_FILES not receiving input after AJAX with vanilla Javascript

I have a form that passes various types of input to an ajax call, which opens a php script. The script will do various things including processing the file, before echoing an array of variables.
All inputs go through $_POST regularly, and the file data is passed, too, but the file itself is not accessible from $_FILES.
I am not using jQuery, so most posts are hard to translate to my case.
I have seen a similar issue here,https://stackoverflow.com/questions/56878395/files-empty-after-ajax-upload but that solution doesn't seem to apply.
Here are the key excerpts from the code, thank you in advance for any tips!
var ajaxResponse = "";
var qForm = document.getElementById('myForm');
qForm.addEventListener("submit", function(e) {
e.preventDefault();
var formData = new FormData(qForm);
checkForm(formData);
console.log(ajaxResponse); //this shows the $_FILES var_dump
});
function checkForm(formData) {
var vars = "startDate=" + formData.get('startDate') +
"&qInvited=" + formData.get('qInvited');
ajaxRequestReturn("checkForm.php", vars);
}
function ajaxRequestReturn(phpRequest, vars) {
var req = new XMLHttpRequest();
req.open("POST", phpRequest, false); //not asynchronous, because I pass results to a global variable
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); //removing the setRequestHeader doesn't seem to make any difference.
req.onload = function() {
ajaxResponse = this.responseText;
}
req.onerror = function() {
throw new Error("Bad request.");
}
req.send(vars);
// form.submit();
}
<form class="loginForm" id="myForm" method="post" enctype="multipart/form-data" action="thisPage.php">
<div>
<input type="date" id="startDateInput" name="startDate">
</div>
<div>
<input type="file" name="qInvited" required>
</div>
<input type="submit" id="submitBtn">
</form>
and the checkForm.php file is currently simply:
<?php
echo var_dump($_FILES);
?>
the var_dump($_FILES) should show the qInvited file in it, but it prints
array(0) {
}
instead.
To upload a file via ajax you have to pass a FormData object in your call to XMLHttpRequest.send.
Get rid of the checkForm function and call ajaxRequestReturn with formData as the second parameter.
Also, application/x-www-form-urlencoded is not the correct content type(its multipart/form-data), remove that line. The correct content type will be set automatically when you use the FormData object.

Passing multiple parameters by POST using XMLHttpRequest and HTML

I'm trying to pass multiple parameters via HTML form into a XMLHttpRequest. The request takes a network SSID and PSK and passes it to the /connect endpoint.
It works when I hardcode the SSID and PSK using:
var data = '{"ssid":"homenetwork", "psk":"mypassword"}';
xhr.send(data);
When I try to pull the data from the HTML form I get net::ERR_EMPTY_RESPONSE in Chrome.
<!DOCTYPE html>
<html>
<br>
<label for="network">Network Name (SSID):</label>
<input type="text" id="network" name="network" required size="15">
<label for="presharedkey">Network Password (PSK): </label>
<input type="text" id="presharedkey" name="presharedkey" required size="15">
<button onclick="connectWifi()">Save</button> <br>
<script>
function connectWifi() {
var network = document.getElementById("network") .value;
var presharedkey = document.getElementById("presharedkey") .value;
var url = "http://192.168.0.236:8080/connect";
var xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.status);
console.log(xhr.responseText);
}};
// var data = '{"ssid":"homenetwork", "psk":"mypassword"}';
var data = 'ssid='+network+'&psk='+presharedkey;
xhr.send(data);
}
</script>
</html>
The var data = line I pulled from this StackOverflow question.
Thanks in advance.
The data variable you are using needs to be a JSON object. In your example here it is a string, so the individual values are not passed, just one single string.
Try:
var data = `{"ssid": "${network}", "psk": "${presharedkey}"}`;
[EDIT]
I misunderstood the original question it seems. OP is trying to send the data as a JSON object but doesn't know how to format it (they claim manually passing the string of variables works).

How to receive Ajax urlencode in PHP

I need help with this problem, please help me.
I'm trying to do Ajax urlencode to PHP, but PHP doesn't show me the POST content like does when HTML send directly to PHP.
I'm using this code in Ajax to send FormData to PHP.
With this simple PHP code to see if works on php file name: "thefile.php"
With this JS, HTML and PHP code:
function sendme() {
var form = new FormData(document.forms['form']);
if (window.XMLHttpRequest)
var ajax = new XMLHttpRequest();
else
var ajax = new ActiveXObject("Microsoft.XMLHTTP");
ajax.open("post", "thefile.php", true);
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200)
console.log(ajax.responseText); //to see the return on in console
};
ajax.send(form);
};
<form name="form" onsubmit="return false;">
<input type="text" name="user" required autofocus/>
<input type="password" name="pass" required/>
<input type="submit" name="send" onclick="sendme();" />
</form>
<?php
print_r($_POST); //to see $_POST Array Content
echo ' '.$_POST['user'].' '.$_POST['pass'];
?>
The input content:
user: username
pass: password
The results:
Array
(
[------WebKitFormBoundary50040KVnXutLwSAd
Content-Disposition:_form-data;_name]=>"user"
username
[------WebKitFormBoundary50040KVnXutLwSAd
Content-Disposition:_form-data; name]=>"pass"
password
------WebKitFormBoundary50040KVnXutLwSAd--
)
Notice: Undefined index: user in thefile.php on line 3
Notice: Undefined index: pass in thefile.php on line 3
From the specification:
FormData: Push the result of running the multipart/form-data encoding algorithm, with object as form data set and with utf-8 as the explicit character encoding, to stream.
You are generating a multipart/form-data body, but you are explicitly setting the content-type header to claim that it is application/x-www-form-urlencoded; charset=UTF-8.
Either:
Specify the correct content type
Don't specify the content type and let XHR set it for you
It seems like your httpHeader "application/x-www-form-urlencoded" is not compatible with FormData object.
Just comment it out like below:
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
to
//ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
If you prefer to use "application/x-www-form-urlencoded; charset=UTF-8" in your request. You have to write simple javascript code to make it as normal string like:
var form = "user=root&pass=root";
.....
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
.....
ajax.send(form);

unable to get parameters from javascript to php

Unable to get parameters passed from javascript to loginme.php
This is simple form in
index.php
<form method="POST">
<input type="text" id="userid" name="userid"></input>
<input type="password" id="pass" name="pass"></input>
<input type="button" value="Log in" onclick="letUserLogin()"/>
</form>
Javascript function :
myscript.js
function letUserLogin() {
var userid = document.getElementById("userid").value;
var pass = document.getElementById("pass").value;
if (window.XMLHttpRequest) {
xmlhttp=new XMLHttpRequest();
} else {
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
alert(xmlhttp.responseText); //only shows 'and'
}
}
xmlhttp.open("POST","loginme.php?userid="+userid+"&pass="+pass,true);
xmlhttp.send();
}
Simple echo statement in loginme.php
loginme.php
<?php
// username and password sent from form
$username=$_POST['userid'];
$password=$_POST['pass'];
echo"$username and $password";
?>
You are passing GET parameters:
xmlhttp.open("POST","loginme.php?userid="+userid+"&pass="+pass,true);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
... thus you need to fetch them from $_GET, not $_POST:
$username=$_GET['userid'];
$password=$_GET['pass'];
You possibly want to use the send() method instead to send your data. Right now, your payload is empty:
xmlhttp.send();
You can resolve this with JQuery quite easily if you want:
This method also allows you to put the URL within the action parameter of the form and uses POST which is more secured for transferring password information:
JQUERY:
$(document).on('submit', "form", function(e){ //We add a listener
e.preventDefault();
$.post($(this).attr('action'), $(this).serialize())
.done( function( data ) {
//Do something with response
});
});
Note that you can of course change the listener to only listen to a specific form. In this case all forms submits will be caught rather than a specific one in a page.
HTML:
<form action="/path/to/loginme.php">
<input type="text" name="userid">
<input type="password" name="pass">
</form>
PHP:
$username=$_POST['userid'];
$password=$_POST['pass'];
echo "$username and $password";
You are using POST but explicitly setting the values into the query string, GET style. So basically you are sending a blank POST.
You need to send the values like this:
xmlhttp.open("POST","loginme.php", true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("userid=" + userid + "&pass=" + pass);
try this:
var userid =encodeURIComponent(document.getElementById("userid").value)
var pass =encodeURIComponent(document.getElementById("pass").value)
var parameters="userid="+userid+"&pass="+pass
mypostrequest.open("POST", "loginme.php", true)
mypostrequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
mypostrequest.send(parameters)
use of encodeURIComponent() to encode any special characters within the parameter values.
Call setRequestHeader() and set its content type to "application/x-www-form-urlencoded". This is needed for any POST request made via Ajax.

Post parameters from AJAX request undefined in form scope in ColdFusion

I am working on a ColdFusion 8 training application where I'm making some AJAX requests (without any libraries such as jQuery) to support a very basic CRUD application.
The high level architecture includes a CFM view, a CFC with remote access methods which receive the AJAX requests, and a CFC which acts as a model and has all of the database queries.
For just retrieving data that doesn't require any sort of bind variables (like getting all rows from the table), the AJAX queries are working fine. When I try to post anything to the CFC middle layer, however, I'm getting errors about the values I'm looking for being undefined in the Form scope (which from my understanding is where post parameters will be stored). I even dissected the requests with Tamper Data and verified that the names and values of the post parameters are as I expect them to be.
Here is an example of the JS AJAX requests:
function addLocation(locToAdd) {
var thisAccess = new AccessStruct("POST", "jsontest.cfc?method=addNewLocation", getLocations, "newLoc=" + JSON.stringify(locToAdd));
accessWrapper("addLoc", thisAccess);
function accessWrapper(action, accessDef) {
var ajaxRequest = new XMLHttpRequest();
var nextStep;
if (action != "getLocs") {
nextStep = getLocations;
} else {
nextStep = buildTable;
}
ajaxRequest.onreadystatechange = function() { // using a closure so that the callback can
if (ajaxRequest.readyState == 4) { // examine the request and nextStep
if (ajaxRequest.status == 200) {
if (nextStep != null) {
nextStep(ajaxRequest);
}
return true;
} else {
alert("Request Could Not Be Completed; Errors On Page");
return false;
}
}
}
ajaxRequest.open(accessDef.method, accessDef.url, true);
ajaxRequest.send("newLoc=" + accessDef.params);
}
function Loc(locCode, parLocCode, name, addrL1, addrL2,
city, stateProv, postal, locTypeCode) {
this.locCode = locCode;
this.parLocCode = parLocCode;
this.name = name;
this.addrL1 = addrL1;
this.addrL2 = addrL2;
this.city = city;
this.stateProv = stateProv;
this.postal = postal;
this.locTypeCode = locTypeCode;
}
function AccessStruct(method, url, nextStep, params) {
this.method = method;
this.url = url;
this.nextStep = nextStep;
this.params = params;
}
Essentially what's happening on the page is that a table populated by all the location (loc) records is being rendered for a "user". There is a form to add a new user, and when they click the add button, a Loc structure is created containing the information they entered and is passed to the addLocation function. This creates an Access structure, which will include the request URL, method, the name of a function to act as a callback, and any post parameters. This is all passed into the accessWrapper function, which will create the XMLHttpRequest and process the AJAX request. I used a closure for the onreadystatechange callback function so that it could be aware of the XMLHttpRequest object and the callback function defined in the Access structure (this callback function will be generally be used to refresh the view table after a record is added, deleted, or edited).
Here is the cffunction within the middle-layer CFC where the problem is being reported from. I won't bother to post the DAO CFC as that has been tested elsewhere and is not even being reached during this process (because it's failing at the middle [or controller] level)
<cffunction name="addNewLocation" output="false" access="remote">
<cfset var deserializedLocation = "">
<cfscript>
deserializedLocation = DeserializeJSON(Form.newLoc);
</cfscript>
<cfobject component="locationDAO" name="locationDAOObj">
<cfinvoke
component="#locationDAOObj#"
method="addLocation">
<cfinvokeargument name="code" value="#deserializedLocation.locCode#">
<cfinvokeargument name="parentCode" value="#deserializedLocation.parLocCode#">
<cfinvokeargument name="name" value="#deserializedLocation.name#">
<cfinvokeargument name="addr1" value="#deserializedLocation.addrL1#">
<cfinvokeargument name="addr2" value="#deserializedLocation.addrL2#">
<cfinvokeargument name="city" value="#deserializedLocation.city#">
<cfinvokeargument name="stateProv" value="#deserializedLocation.stateProv#">
<cfinvokeargument name="postal" value="#deserializedLocation.postal#">
<cfinvokeargument name="locationType" value="#deserializedLocation.locTypeCode#">
</cfinvoke>
</cffunction>
The error in the request response is:
500 Element NEWLOC is undefined in FORM
Like I said before, I've checked the request in Tamper Data, and it looks fine there. Thanks in advance for any help you great folks might be able to offer!
There absolutely is a FORM scope when you do an Ajax post to a CFC.
This example POSTs form data via Ajax to a CFC function with no arguments and returns the JSON format of the FORM scope. Yes, you should have arguments to document, specify required/not required and data type, but they're not mandatory.
Is there any reason you aren't using jQuery? It would probably make your life much easier.
There must be something wrong with how you're sending the form data to the Ajax call. If you use FireBug to watch your Ajax calls, you can see the POSTed parameters.
HTML
<html>
<head>
<title>Ajax POST to CFC</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="test.js">
</head>
<body>
<form id="foo" action="" method="post">
<input type="text" id="a" name="a" value="Hello" />
<br />
<input type="text" id="b" name="b" value="Goodbye" />
<br />
<textarea id="data" cols="30" rows="10" disabled="true"></textarea>
<br />
<input type="button" id="btnSubmit" value="Do Ajax!" />
</form>
</body>
</html>
JavaScript
$(document).ready(function() {
$('#btnSubmit').on('click', function() {
$.ajax({
asynch : true,
type : 'POST',
dataType : 'json',
url : 'test.cfc?method=testing&returnformat=json',
data : {
a : $('#a').val(),
b : $('#b').val()
},
success : function(data, textStatus) {
$('#data').val(JSON.stringify(data));
}
});
});
});
CFC
<cfcomponent>
<cffunction name="testing" access="remote" output="false" returntype="string">
<cfreturn serializeJSON( form ) />
</cffunction>>
</cfcomponent>
Old School, no jQuery, just plain ol' JavaScript
I found a simple example of an Ajax POST without jQuery here:
http://www.openjs.com/articles/ajax_xmlhttp_using_post.php
HTML
Remove the jQuery SCRIPT tag, change the other SCRIPT to test-nojq.js and change the submit button to add an onclick event.
<input type="button" id="btnSubmit" value="Do Ajax!" onclick="doSubmit();" />
JavaScript: test-nojq.js
function doSubmit(){
var http = new XMLHttpRequest();
var url = "test.cfc";
var params = "method=testing&returnformat=json";
params += "&a=" + document.getElementById('a').value;
params += "&b=" + document.getElementById('b').value;
http.open("POST", url, true);
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
document.getElementById('data').value = http.responseText;
}
}
http.send(params);
}
Make newLoc into an argument and it should work.
<cffunction name="addNewLocation" output="false" access="remote">
<cfargument name="newLoc">
...
</cffunction>
update: not sure why I encountered no form scope one time calling a remote method. Anyway, it isn't true but the rest of the answer should still hold true.

Categories