Form/URL scope variables with same names. Inconsistencies across Java and ColdFusion.

Community Beginner ,
Nov 22, 2020 Nov 22, 2020

Copy link to clipboard

Copied

Goal: To have consistent behavior of handling form and URL scope variables as structures containing arrays, therefore, eliminating issues with comma-separated values.

 

Form fields and URL query parameters can have the same names. If two form fields (or query parameters) share the same name, ColdFusion will concatenate their values, separated by commas, and assign them to a single key in the form scope. The same applies to the URL scope. Therefore, a user-submitted value that contains a comma can cause program flow issues/errors later on.

 

Years ago, ColdFusion added "sameFormFieldsAsArray" as an application setting. This is great, but it is limited to only the form scope. It does not affect the URL scope which can also have multiple parameters with the same name.

 

While trying to find a solution that works for both form and URL scopes, I found documentation on using getPageContext().getRequest().getParameterMap().

 

This is where I ran into the first issue.

 

With URL query parameters on a GET request (no form submission), getParameterMap() correctly retrieves all URL query parameters in a structure of arrays.

 

When submitting a form via POST, getParameterMap() correctly retrieves all form fields in a structure of arrays.

 

However, when submitting a form via POST, AND with URL parameters in the form action attribute, getParameterMap() retrieves ONLY the form fields and ignores the URL query parameters. This is unexpected.

 

In the Java docs, the following is mentioned about getParameterMap "For HTTP servlets, parameters are contained in the query string or posted form data." I guess the keyword is "or" meaning that form fields override query parameters.

 

I have seen several comments on StackOverflow that state the getParameterMap method can have both query parameters as well as form fields. However, these comments are nearly a decade old.

 

Continuing on where this does work, sort of, is when the form is POSTed using "enctype='multipart/form-data'". In this case, URL parameters are returned by getParameterMap and form fields are returned by [request].getParts() or [form].getPartsArray() methods.

 

There are several directions I can take with this:

  • I can leave things the way they are and deal with commas in the values.
  • I can set "sameFormFieldsAsArray" and enjoy arrays of form field values, but not URL values.
  • I can use getParameterMap() and if a form was POSTed, I'll have to parse the query string into a structure of arrays.
  • Ensure all forms are set to "enctype='multipart/form-data'" and have access to the URL values using getParameterMap() and have access to form field values through getParts(). I'm aware of the additional overhead using this method, but our forms are not so large that this would be a much of a concern. My primary concern is making sure my coworker correctly uses "enctype" on every form created.

 

Does anyone else have any suggestions? Can we get an Application.cfc setting for "sameQueryParametersAsArray"?

 

Below is the code I'm using to work through this issue. Ignore the inefficient, improper code. I'm only concerned about reaching my goal at this point.

 

Request the following code with this URL, for example.

https://[domain]/index.cfm?id=123&foo=bar&foo=fubar

 

The code will initially dump the parameters in the URL query string.

Submitting the first form will lose the URL query parameters, but will display the form field values.

Submitting the second form will retain the URL query parameters, and will display the form field values.

 

Application.cfc

 

component output="true" {
	pageEncoding("utf-8");
	setEncoding("url", "utf-8");
	setEncoding("form", "utf-8");

	thisContext = getPageContext();
	thisRequest = thisContext.getRequest();

	this.subdomainRootDirectory = thisContext.getFusionContext().getWebRoot().reReplaceNoCase("\w+$", "");
	this.name = hash(this.subdomainRootDirectory);
	this.mappings["/includes"] = this.subdomainRootDirectory & "includes\";

	writeOutput("<br>");
	writeDump(var: thisRequest.getParameterMap(), label: "thisRequest.getParameterMap()");

	parameterNames = thisRequest.getParameterNames();
	while(parameterNames.hasMoreElements()) {
		thisParameterName = parameterNames.nextElement();
		writeOutput("<p><strong>#thisParameterName#</strong></p>");
		writeDump(thisRequest.getParameterValues(thisParameterName));
	}

	writeOutput("<br>");
	writeDump(form.getPartsArray());
}

 

Index.cfm

 

<cfprocessingdirective pageencoding="utf-8">

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
<cfoutput>

<cfset thisURL = getPageContext().getRequest().getRequestURL().toString()>
<cfset thisQueryString = (structKeyExists(cgi, "QUERY_STRING") and cgi.QUERY_STRING.len()) ? "?" & cgi.QUERY_STRING : "">

	<hr>
	<form action="#thisURL##thisQueryString#" method="post">
		<label>firstname <input type="text" name="firstname"></label><br>
		<label>lastname <input type="text" name="lastname"></label><br>
		<label>group <input type="text" name="group"></label><br>
		<label>group <input type="text" name="group"></label><br>
		<label>group <input type="text" name="group"></label><br>
		<button type="submit">Submit</button>
	</form>

	<hr>
	<form action="#thisURL##thisQueryString#" method="post" enctype="multipart/form-data">
		<label>firstname <input type="text" name="firstname"></label><br>
		<label>lastname <input type="text" name="lastname"></label><br>
		<label>group <input type="text" name="group"></label><br>
		<label>group <input type="text" name="group"></label><br>
		<label>filename <input type="file" name="filename"></label><br>
		<button type="submit">Submit</button>
	</form>

</cfoutput>
</body>
</html>

 

 

TOPICS
Advanced techniques

Views

115

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct Answer

Adobe Community Professional , Nov 24, 2020 Nov 24, 2020
"However, when submitting a form via POST, AND with URL parameters in the form action attribute, getParameterMap() retrieves ONLY the form fields and ignores the URL query parameters. This is unexpected. In the Java docs, the following is mentioned about getParameterMap "For HTTP servlets, parameters are contained in the query string or posted form data." I guess the keyword is "or" meaning that form fields override query parameters." That is in fact the expected behaviour. In a POST request...

Likes

Translate

Translate
Adobe Community Professional ,
Nov 24, 2020 Nov 24, 2020

Copy link to clipboard

Copied

"However, when submitting a form via POST, AND with URL parameters in the form action attribute, getParameterMap() retrieves ONLY the form fields and ignores the URL query parameters. This is unexpected.

 

In the Java docs, the following is mentioned about getParameterMap "For HTTP servlets, parameters are contained in the query string or posted form data." I guess the keyword is "or" meaning that form fields override query parameters."

 

That is in fact the expected behaviour. In a POST request the parameters are contained in the request body and the query-string is customarily ignored.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Nov 24, 2020 Nov 24, 2020

Copy link to clipboard

Copied

LATEST

Thank you for the reply.

 

I should be able to work around this by storing the query string params in hidden form fields, then rebuild a redirect URL using these fields after the form is processed.  This is my usual process, but I was hoping for something better.

 

I appreciate the help.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines