Chapter 18. Passing Parameters between Pages

Table of Contents

1. The HTTP Protocol: GET and POST Methods
2. Passing Parameters via a URL (GET Method)
2.1. Passing an Array in a URL
3. Passing Parameters via a HTML Form (POST Method)
3.1. Passing an Array in a HTML Form
3.2. Passing Data with the "multipart/form-data" Encoding

One of the main problems that need to be addressed when developing Web applications is maintaining state information when switching from a page to another.

We have described how this can be done in Biferno using variables that have the entire application as their scope (application, session or persistent variables), with the limitation that this technique is only useful when we implement parameters that have to be accessible from all application scripts (and, with the exception of session variables, from all users).

When the information we want to pass to a page is meaningful only in the context of that page and within a single connection, it is convenient to use the HTTP protocol parameters. A brief description of the GET and POST methods of the HTTP protocol will help understanding the association mechanism between variables and parameters supported in the HTTP protocol.

1. The HTTP Protocol: GET and POST Methods

The HTTP protocol is based on simple conversational interactions between client and server. The client connects to a server and sends a request. The server receives the request, processes it, and sends the answer to the client.

The message sent by the client to the server is structured as follows:

  • One line containing the specification of the method used, which can be GET or POST, the URL of the requested page, and the protocol version.

  • A header containing a number of additional data on the client and the request itself.

  • A body, which can be empty.

If the request uses the GET method, the body is empty because parameters are associated directly to the URL separating them with the ? character. If the request uses the POST method, the body contains the list of (optional) parameters with their values.

The GET method is preferable to the POST method when there is limited number of parameters and their values are short strings or numbers. When there is many parameters, or their values are long, it is better, and indeed often necessary, to use the POST method.

One of the reasons is that a request sent to the server via the GET method can not exceed 12 Kb in length. Furthermore, the GET method only supports text data, while the POST method can be used to transmit any kind of data, including images, music, movies, etc. The POST method must always be used instead of the GET method when parameters should be hidden from the user and can not be sent along with the URL of the requested page.

In general, the GET method is implicitly used in links implemented with the a HTML tag, while the POST method is the default for forms (for which the GET method can be optionally specified).

If the page requested by the client is a Biferno script, Biferno creates a new variable with the same name and value for each of the parameters submitted. This is done before the script is processed and regardless of the HTTP protocol method utilized to send data to the server. The new variables are normally all of the string class.

Let us see through some examples how to pass parameters to a Biferno script using the GET and the POST methods.

2. Passing Parameters via a URL (GET Method)

A generic URL corresponding to a Biferno script, complete with parameters, has the following form:

http://path/script.bfr?param1=value1&param2=value2&...&paramN=valueN
    

When the client requests the "script.bfr" page, Biferno associates to the param1 parameter a variable called param1 and having the value1 string as value. Decoding from the "UrlEncode" format is performed automatically (see the Section "String Encoding and Decoding" in Chapter 12, String Manipulation). Similarly, the param2 variable with value value2 is associated to the param2 parameter, and this process is repeated for all parameters up to and including paramN. Notice that parameter values passed with the GET method have to be encoded with the "UrlEncode" format, when necessary, before they are inserted into the URL string.

The default class for variables associated to HTTP parameters is string. This behavior can be modified by executing an explicit typecast directly on the URL. Assuming we want to pass a parameter to a script as an integer value, we can write in HTML:

<a href="script2.bfr?int(param1)=1&param2=2">Script 2</a>
    

The param1 parameter will be associated in the "script2.bfr" script to a variable of the int class with the same name and value 1, while the parameter param2 will be associated to a string class variable with value "2". Notice that the typecast syntax in the URL differs from the usual form, which is (class_name)variable_name. Conversely, in a URL the class identifier must be in front of the parameter name enclosed in round brackets.

If a typecast error occurs in a parameter passed to a Biferno script with the GET or POST methods, Biferno does not stop processing and creates anyway a string class variable with name and value corresponding to the parameter name and value. At the same time, and before starting script execution, Biferno assigns the Err_IllegalTypeCast value to the global err variable. This behavior allows to catch this kind of error at the beginning of the script. We will see in the following, when discussing passing parameters with the POST method, an example showing how to catch typecast errors in parameters.

2.1. Passing an Array in a URL

It is often necessary to pass an array to a Biferno script or to associate a sequence of homogeneous parameters passed to a script to the elements of an array, instead of distinct variables. This can be done by using the following syntax for the URL:

http://script.bfr?arr[1]=value1&arr[2]=value2&...&arr[N]=valueN
     

Parameter names correspond to the elements of a virtual array that are assigned parameter values. In the target script an array class variable called arr is created to store the values passed in the URL, according to the index references as described in the URL itself.

Assume we want to pass an array of three elements with values 1,2,3 to a Biferno script:

<a href="script2.bfr?myArr[1]=1&myArr[2]=2&myArr[3]=3">Script 2</a>
     

In the "script2.bfr" script the myArr variable of the array class is created, with three elements of the string class with values "1", "2" and "3", respectively. This syntax can be used also for multidimensional arrays, as in the following example:

<a href="script2.bfr?myArr[2][1]=1&myArr[2][2]=2&myArr[2][3]=3">Script 2</a>
     

In the "script2.bfr" script the myArr array of arrays is created, where the second array has three elements of the string class with values "1", "2" and "3", respectively. If we want to force the element class to be the integer class int we can write:

<a
href="script2.bfr?int(myArr)[1]=1&int(myArr)[2]=2&int(myArr)[3]=3">Script 2</a>
     

Biferno also supports an alternative syntax to denote a parameter as an array element. The indices between square brackets can be omitted, and in this case the sequence 1, 2, 3, etc. is assumed. This syntax is very efficient and elegant, but supports only one dimensional arrays (vectors), as in:

<a href="script2.bfr?myArr[]=1&myArr[]=2">Script 2</a>
     

An attempt to use this syntax for multidimensional arrays is invalid and generates the Err_InvalidArrayIndex error.

The following example shows how to dynamically build a URL to pass an array of strings to another script:

<?
	myArr = array("Primula Brandybuck", "Palo Alto", "Employee")
	paramStr = "?"
	
	arrSize = myArr.dim
	for (i = 1; i <= arrSize; i++)
		{
			if (i > 1)
				paramStr += "&amp;"
			paramStr += "myArr[" + i + "]=" + myArr[i].UrlEncode()
		}
?>
<html>
	<body>
		<a href="script2.bfr$paramStr$">Script 2</a>
	</body>
</html>
This script generates the following HTML code:
<html>
	<body>
		<a href="script2.bfr?myArr[1]= Primula%20Brandybuck 	
		&amp;myArr[2]=Palo%20Alto&amp;myArr[3]=Employee">Script 2</a>
	</body>
</html>
     

Notice the use of the UrlEncode method of the string class, which is necessary to correctly encode strings within the URL.

An array can also be passed as a whole in a URL, using the syntax:

<?
myArr = array(1, 2, 3)
?>
<a href="script2.bfr?myArr_ini=$object.ValueOfInput(myArr)$">Script 2</a>
     

and in the following page:

<?
myArr = Eval(myArr_ini)
?>

The object.ValueOfInput method provides the correct code invoking the constructor and can be applied on an object of any class. We suggest the reader experiments with it by invoking it on an array and printing the result. The same function is also used to pass an array via a HTML form or to pass variables of other non-primitive classes.

Note

URL and Forms variables input syntax has some limitations. In particular, given the URL as couples of Name=Value pairs the following rules apply: Name expressions cannot contain constructor other than that of primitive class. Value espressions are always evaluated as strings, also when they contain constructors. Examples:
myUrl?int(a)=1       // a is a int of value: 1
myUrl?array(a)=1     // error (constructor in Name not of primitive class)
myUrl?a=int(a)       // a is a string of value: "int(a)"

3. Passing Parameters via a HTML Form (POST Method)

The association between HTML parameters sent with the POST method and Biferno variables is realized by associating in the destination script (specified by the "action" attribute of the form) a variable to each input tag of a HTML form. The name of the variable is the string specified in the "name" attribute and its value is the string specified in the "value" attribute. In general, a Biferno variable is associated to every form element that is characterized by the "name" and "value" attributes.

The following HTML form send the three strings input by the user to a Biferno script:

<html>
	<body>
		<form method="post" action="script2.bfr">
			String 1: <input type="text" name="string1" value=""><br>
			String 2: <input type="text" name="string2" value=""><br>
			String 3: <input type="text" name="string3" value=""><br>
			<input type="submit" value="Send">
		</form>
	</body>
</html>
    

If we want to transmit numeric values we can execute a typecast similarly to what was done for the GET method, as in the following code:

<html>
	<body>
		<form method="post" action="script2.bfr">
			Name: <input type="text" name="first_name" value=""><br>
			Surname: <input type="text" name="last_name" value=""><br>
			Age: <input type="text" name="int(age)" value=""><br>
			<input type="submit" value="Send">
		</form>
	</body>
</html>
    

In this case the third input element of the form contains in its name also the typecast to the int class.

While the example above demonstrates the use of explicit typecast in HTML forms, particular care must be taken when the input element is an editable text field. In the case of the form produced by the example, the automatic typecast will fail if the user inputs non- numeric characters in the third field.

To avoid this, it may be necessary to limit the input to numeric characters, e.g. by using an ad hoc JavaScript function called when the user attempts to send the data in the forms. An alternative is to code the form target script in such a way that the script can handle the error. The following code, inserted at the beginning of the "script2.bfr" script (target script of the form in the last example), catches a typecast error in the "Age" field and outputs a corresponding message.

<?
	if (err == error.Err_IllegalTypeCast)
		{
			if (err.msg == "age")
				{
?>
		<p>Error! Please use only integer numbers in the Age field</p>
		<p>Please back up and correct </p>
<?
					stop
				}
		}
?>
    

3.1. Passing an Array in a HTML Form

Reconsider the example concerning passing an array in a URL presented in the previous section. The example can be rewritten using a form as follows:

<html>
	<body>
		<form method="post" action="script2.bfr">
			<input type="hidden" name="myArr[1]" value="1">
			<input type="hidden" name="myArr[2]" value="2">
			<input type="hidden" name="myArr[3]" value="3">
			<input type="submit" value="Send to script 2">
		</form>
	</body>
</html>
     

Three "hidden" elements have been used with names corresponding to array elements and values corresponding to the strings "1", "2" and "3". In this case it is always safe to use typecast to obtain elements of the integer class, because the values are hard-wired in the HTML code. The form of the previous example can be rewritten as:

<html>
	<body>
		<form method="post" action="script2.bfr">
			<input type="hidden" name="int(myArr)[1]" value="1">
			<input type="hidden" name="int(myArr)[2]" value="2">
			<input type="hidden" name="int(myArr)[3]" value="3">
			<input type="submit" value="Send to script 2">
		</form>
	</body>
</html>
     

The alternative syntax shown when discussing passing an array in a URL can be used also in this case.

Notice that the same result can be obtained by writing:

<?
myArr = array(1, 2, 3)
?>
<html>
	<body>
		<form method="post" action="index.bfr">
			<input type="hidden" name="myArr_ini" 			
			  value="$object.ValueOfInput(myArr)$">
			<input type="submit" value="Send to script 2">
		</form>
	</body>
</html>
     

And writing in the following page the code

<?
myArr = Eval(myArr_ini)
?>

Another technique to pass data to a Biferno script as an array is to use an input element of the select type supporting multiple selection. Normally, the variable associated to a HTML select is of the string class and contains the selected elements separated by the ", " characters (comma plus space). The HTML form in the following example sends a string containing the selected elements separated by a comma and a space to the "script2.bfr" script.

<html>
	<body>
		<form method="post" action="script2.bfr">
			<select name="selNum" multiple>
				<option value="1">1</option>
				<option value="2">2</option>
				<option value="3">3</option>
			</select><br>
			<input type="submit" value="Send to script 2">
		</form>
	</body>
</html>
     

If we select all three elements of the select and send the form, in the "script2.bfr" script the selNum variable of the string class will be defined with value "1, 2, 3".

A string in this format can simply converted into an array using the ToArray method of the string class. However, if we want the values selected in the select to be passed to the script in array form, we can just append a pair of parentheses to the name of the select, in the following fashion:

<select name="selNum[]" multiple>
     

Using this syntax the selNum variable will always be of the array class, even if we select a single element from the select. The typecast to the integer class can be realized by writing:

<select name="int(selNum)[]" multiple>
     

3.2. Passing Data with the "multipart/form-data" Encoding

Our discussion regarding passing parameters via HTML forms assumes that only textual (ASCII) data is sent using the default format "application/x-www-form-urlencoded". This format was mentioned in Chapter 12, String Manipulation in the discussion of the UrlEncode method of the string class.

The "application/x-www-form-urlencoded" encoding can not be used to transmit large quantities of binary data or text containing non-ASCII characters. To send this kind of data the "multipart/form-data" encoding should be used.

This encoding is normally used to transmit files (text or binary). The following example shows a HTML form with an input element of type file. The "enctype" attribute of a HTML form specifies the kind of content, and therefore the type of encoding, of the data set to be transmitted to the server.

<html>
	<body>
		<form method="post" action="handle_file.bfr" 
		enctype="multipart/form-data">
			File to send: <input type="file" name="the_file"><br>
			<input type="submit" value="Send file">
		</form>
	</body>
</html>
     

In the target Biferno script a variable of the multipart class is associated to the form input element of type "file". The properties of this class allow to obtain information on the received file:

  • The name property contains the name of the file.

  • The path property normally contains the complete path of the file, depending on the browser and platform used (in some cases only the file name is sent).

  • The contentType property contains the type identifier for the file content (MIME type).

  • The data property contains the actual content of the file.

The following script provides an example of management of the information concerning the file sent by the form.

<html>
	<body>
<?
	file_name = curScript.ValueOf("the_file.name")
	if (file_name)
		{
?>
			The file $file_name$ was sent.<br>
			The file size is $the_file.data.length$ byte<br><br>
<?
			// Store file on server
			new_path = "/upload/" + file_name
			the_file.ToFile(new_path)
		}
	else
		{
?>
			No file was sent.
<?
		}
?>
	</body>
</html>
     

The conditional statement verifies that a file has been effectively uploaded in the input field. Because the the_file variable of the multipart class associated to the form is always defined, the test checks that the name property of the variable does not contain an empty string.

If the the_file variable contains data, the name and size (in bytes) of the corresponding file are printed. Then, the file is stored in a directory called "upload" located in the server root (or more precisely in the site root). The ToFile method of the multipart class is used, with prototype:

void ToFile(string path)
     

The path parameter specifies the path of the file to be stored. The use of this method makes it easy to store on the server files submitted by users via HTML forms. Notice that, even though in the example above the file has been stored on the server using the same file name, any new name can be specified for the new file.

Limiting the Size of Data Sent to the Server

Biferno allows to limit the size of data sent to the server via a HTML form using the POST method. To set a limit, we add to the name of the Biferno page specified in the action attribute of the form tag the "?MAX=" string followed by the maximum size (in kilobyte) of the data block that can be passed by the POST method. An example is

<form method="post" action="page2.bfr?MAX=64">
      

This technique can be used to avoid that users are able to upload extremely large files that may cause problems on the server.

If the size of the file sent exceeds the maximum value set, the global err variable is set to the Err_HTTPBodyTooLong value when the execution of the script corresponding to the form starts, and no variable is passed from the form to the script.