Chapter 9. Applications and Variable Scope

Table of Contents

1. Applications
2. Application Variables
3. Reloading and Flushing Biferno
4. Local Variables
5. Global Variables
6. Persistent Variables
7. Session Variables
8. Communication between Applications

This Chapter introduces the concept of Biferno "application" and discusses how to determine the scope of a variable, i.e. its region of validity.

1. Applications

A Biferno script, i.e. a text file with ".bfr" extension containing Biferno code and, optionally, HTML code, can implement stand-alone functionality or be part of a very complex Web site with hundreds of interlinked pages.

As far as the Web server is concerned, a Biferno script is always identified by a URL, a string that represents the Web location of an internet resource. E.g. the string "http://www.mysite.com/information/index.bfr" identifies a Biferno script called "index.bfr" in the "information" directory of the Web site found at address "www.mysite.com". In this case the path of the "index.bfr" file is relative to the site root (i.e. relative to the absolute path of the directory containing the site) as defined in the configuration of the Web server.

In Biferno a number of script contained in a directory (and possibly in its subdirectories) can be identified as belonging to the same "application".

To define a Biferno application a file called "Biferno.config.bfr" must be created in the root directory of the application. This file contains the values of some standard parameters of the application (called "preferences") and additionally may define some more environment parameters, implemented via the use of application scope variables.

The "Biferno.config.bfr" must contain at least the following line:

<?
     APPLICATION_NAME = "MyApplicationName"
?>

Other configuration preferences that can be used in the "Biferno.config.bfr" file are described in the Section 2, “Application Variables”. The configuration file "Biferno.config.bfr" is interpreted and executed by Biferno once, usually when the server receives the first request for a script that belongs to the application (or to a subapplication, as we will see soon).

The "Biferno.config.bfr" file is protected. For security reasons it is not possible to execute the code contained in this file by requesting execution by directly typing the corresponding URL in a browser.

File Protection

A script can be protected by assigning either the ".x.bfr" or the ".s.bfr" extension to the corresponding file. All files with these special extensions can not be executed by requesting the corresponding URL via a browser, but can always be executed by other scripts via the include instruction.

While it is not necessary to create an application to execute a Biferno script, it is important to understand how a script is always part of an application.

When a client requests a file with extension ".bfr", Biferno looks for a "Biferno.config.bfr" file in the same directory of the requested file. If no configuration file is found, Biferno traverses the directory hierarchy upwards (until either the disk root or the Biferno home directory is reached) looking for a directory containing a file called Biferno.config.

If a configuration file is found in one of the folders, the search stops and the requested file is associated to the application of the directory in which the configuration file was found. If no other files belonging to the application had been previously requested, the Biferno.config script is executed and the application is initialized.

The Biferno home is:

  • the folder [startup disk]:BifernoHome on MacOS classic

  • the /home/BifernoHome directory on Linux

  • the /Users/BifernoHome directory on MacOSX

  • the directory specified by the user at installation time on Windows (default: [Program files]\Biferno\BifernoHome).

In a script the path of the Biferno home directory can be obtained by calling the predefined property biferno.home.

If no configuration file is found no new application is initialized and the requested script is considered part of an application called "BifernoMain". The relative configuration file can always be found in the Biferno home directory. The BifernoMain application is automatically initialized when Biferno starts and is associated to the directory identified by biferno.home.

This mechanism leads to the concept of subapplication and application inheritance. If we create a configuration file in a subdirectory of an application we have created a subapplication. Subapplications inherit as default the preferences of the parent application (the parent configuration file is executed before the child application configuration file). All applications running on the same Web server are subapplications of the "BifernoMain" application.

The application search mechanism explained above is performed only the first time a file is executed. In successive executions, the file path is directly associated to the application it belongs to for optimization reasons.

A list of all applications active at a certain time can be obtained with the predefined property biferno.applications, which returns an array of strings containing the names of all active applications.

How is a Biferno application started?

To start an application when the Web server is started, without waiting for the first user click, it is possible to use a code line similar to the following in the "Biferno.config.bfr" file of the Biferno Main" application:

curApp.RegisterNewApp(application_name, root_path)
     

Application_name is the name of the application we want to initialize (defined by the APPLICATION_NAME parameter of the "Biferno.config.bfr" file) and root_path is the absolute path of the application root directory (see Chapter 13, File Management for file path rules).

An example is:

curApp.RegisterNewApp("MyWebSite", "file://C/MySite/")
     

2. Application Variables

An application variable is a variable whose value is known and modifiable by all scripts belonging to a single Biferno application. The variable has the same value for all site users (clients). The scope of an application variable is the entire application. It is necessary and useful to use application variables to implement parameters whose value is associated to overall aspects of our application and influences the behavior of all its scripts. Notice that application variables have the same value for all users and therefore can not be used to pass parameters that are user-specific, such as search strings.

As a simple but significant example assume we want to define a single background color for all pages of a Web site. This can be obtained in other ways, e.g. by defining the background color for the HTML body tag in an external style sheet, but also by using a Biferno variable to store a single value for all our scripts. First, we have to add a parameter to the "Biferno.config.bfr" configuration file of our application (the precise meaning and use of standard parameters is discussed in the following). This can be accomplished by adding the following line:

application body_background = "#e3e4fa"
    

It is necessary to use the application identifier to specify an application variable when the variable is defined. While this allows to define application variables in any Biferno script, the most appropriate place for such definitions is the application configuration file. The variable identifier body_background is now defined in all scripts that are located in the directory of the "Biferno.config.bfr" file or in one of its subdirectories. To use the value of the variable within our HTML code we can write:

 <body bgcolor="$application body_background$">
    

Using this method the value assigned to the body_background variable in the configuration file can be changed to modify the look of all pages of our site.

When should the scope identifier be used?

The explicit use of the scope identifier is mandatory:

  • when a non local variable is initialized (application, global, persistent or session)

  • when a non application variable is initialized (local, global, persistent or session) in Biferno.config.bfr

  • when a non local variable has to be referenced within the body of a function

The scope identifier is optional in the main body of a script when an already initialized variable is referenced. It is good practice to always use a scope identifier, except for local variables, as it increases the readability of the code.

In the following example we show how the standard content of a configuration file of a Biferno application looks like, with the most commonly used configuration variables. The scope identifier in front of variable names has been omitted. This is possible because the default scope for variable defined within the "Biferno.config.bfr" is application.

<?
     APPLICATION_NAME = "BifernoMain"; /* Name of the application */
     SESSION = false; /* Use session variables? */
     SESSION_TIMEOUT = 15; /* Timeouts for session users (minutes) */
     MAX_ERRFILES = 2048; /* Max error files in folder ERRORS_FOLDER */
     DEVELOPER_IP = "*,local"; /* IPs of developers */
     ERRORS_FOLDER =	""; /* Folder for error files */
     ERROR_PAGE = ""; /* Page error for non-developer users */
     ADMIN_PASSWORD = ""; /* Password for bifernoadmin */
     object.Hide(ADMIN_PASSWORD);
     ADMIN_IP = ""; /* IPs allowed to access bifernoadmin */
     ADMIN_PROTOCOL = "https"; /* Protocols allowed by bifernoadmin */
     FILE_NOT_FOUND_PAGE = ""; /* Page to serve if file not found */
     CACHE = false; /* Cache files in memory? */
     TIMEOUT = 2; /* Scripts Timeout (minutes) */
     HEADER = ""; /* Header file path */
     FOOTER = ""; /* Footer file path */
     ACCESS_CONTROL = ""; /* Security check file */
     ACCESS_CONTROL_NOACCESS = ""; /* Security no access file */
     ACCESS_CONTROL_REALM = ""; /* Security realm name */
     DATE_FORMAT = "d-m-y h:m:s"; /* Default format for dates */
     WEBMASTER = "webmaster@mysite.com"; /* WebMaster */
     MAIL_HOST = "smtp@mysite.com"; /* Smtp Mail Server Host */
     NOTIFY_MAIL_ERR = false; /* Send mail to webmaster if error */
     DECIMAL_SEP = ","; /* Decimal separator */
     THOUSAND_SEP = "."; /* Thousand separator */

     SEARCH_AND = "&"; /* Default search AND operator */
     SEARCH_OR = "|"; /* Default search OR operator */
     SEARCH_NOT = "!"; /* Default search NOT operator */
     SEARCH_WILD = "*"; /* Default search WILD char */
?>
    

In the following we explain some of the variables (see Appendix C for the full variable list).

The APPLICATION_NAME variable (string class) contains the name of the Biferno application identified by this configuration file. The application name can not contain the \ character and therefore none of the special characters (\t, \v, \r, \n) discussed in the description of the string class. Furthermore, the application name must be a literal (constant) string. We can not write:

appName = "MyApp"
APPLICATION_NAME = appName
    

The above code generates the Err_BadSyntaxInApplicationName error. This parameter is the only parameter needed to uniquely identify an application (and the only one to impose the above restrictions). All other parameters we mention in the following (see Appendix 3, Complete Preferences Listing for a complete listing) can be omitted, in which case they will inherit the value they have in the parent application.

The CACHE variable (Boolean class) determines if a script is cached in volatile memory on the server. The default value for this parameter is false (see Chapter 22, Cache Management for the details).

The DECIMAL_SEP and THOUSAND_SEP variables (string class) specify the separation character used for decimals and thousands for our application. Notice that when assigning a numerical value to a variable a dot has to be used as the decimal separator. The default values for these parameters depend on the locale settings of the machine where Biferno has been installed.

The SESSION variable (Boolean class) specifies if the use of session variables in our application is allowed (the meaning and use of these variables is explained in the following). The default value for this parameter is false.

The SESSION_TIMEOUT variable (int class) specifies the lifetime of session variables in minutes, i.e. the maximum time that such variables can exist unused after creation before being deleted. The default value for this parameter is 15 and the minimum value is 2.

The HEADER and FOOTER variables (string class) can contain a file path that will be always prepended (header) or appended (footer) to all scripts in our application.

The DEVELOPER_IP variable (string class) contains one or more IP addresses (when the wildcard character * is used instead of an octet). The addresses specify to Biferno which machines are allowed to receive detailed information on variable state if a script generates an error. Typically this variable contains the IP address of the machine where our application is being developed. When an error occurs, all users receive a simple message containing the error code and an invitation to email an error report to the webmaster, whereas the developer needs much more information, such as variable values. Notice that full error descriptions as made available to developers are also stored in log files in a directory specified by the ERRORS_FOLDER application variable. The protection mechanism also avoids security issues when variable values in a script that generates an error contain sensitive data such as passwords or credit card numbers that should be kept confidential.

Biferno also allows developers to debug an application by connecting from any machine (not necessarily one with IP address stored in the DEVELOPER_IP variable). To gain full access the developer has to connect to the bifernoadmin login page ("http://www.mysite.com/myapplicationPath/bifernoadmin/") and type in the password (that has to match the ADMIN_PASSWORD variable). If the administrator login succeeds, full debugging capability is available for that connection from any IP (see the "Biferno: bifernoadmin Guide" document for details).

If suitable values have been assigned to the MAIL_HOST (set to an email server address), NOTIFY_MAIL_ERR (set to true) and WEBMASTER (set to the email address of the individual to be notified), the complete error screen will be automatically sent via email to the webmaster with no need for user intervention. The user will be displayed the error page or, if no error page is defined, a message containing the error string "An error occurred while processing a script. The webmaster has been notified".

The local keyword in the DEVELOPER_IP variable denotes that local scripts (see Appendix 2, Executing and Scheduling Local Scripts) are enabled to display the complete Biferno error screen (tipically on the system console).

The ERRORS_FOLDER variable (string class) contains the path of a directory where error logs are stored. If this variable is not declared or does not contain a valid path, no logs will be stored.

The MAX_ERRFILES variable (int class) specifies the maximum number of error files that can be stored in the directory defined by the ERRORS_FOLDER variable. The default value of this variable is 2048.

The WEBMASTER variable (string class) specifies the email address of the staff member responsible for application support. This address is also used in the error message that invites the user to submit an error report to the webmaster. The default value is "webmaster@yoursite.com".

The TIMEOUT variable (int class) specifies the maximum processing time (in minutes) that the server will wait for any Biferno script to complete. The default value is 3. When non-zero, the timeout can not be less than 2 minutes. This mechanism allows to avoid situations in which a script is caught in an infinite loop and never terminates. If the timeout is set to zero, all scripts belonging to the application have no time limit. This is dangerous because infinite loops in scripts can not be prevented.

The remaining variables will be described in the following chapters when the relevant aspects of the language will be discussed.

To modify an application variable, the Biferno.config.bfr file needs to be modified. After this modification the application has to be reloaded to force processing of the configuration file, which happens only when the first application script is executed.

Modifying script timeout

It is sometimes necessary to implement scripts that may take a long time to complete, e.g. to execute database backup or update procedures. In these cases the timeout can be changed for a single script modifying the value of the curScript.timeout property:

curScript.timeout = t

where t is a parameter of class unsigned. Setting the property to a value of 0 (zero) removes the timeout limit. Removing the timeout limit is dangerous because infinite loops in a script can no longer be prevented.

Examining the value of the curScript.timeout property the timeout value for the current script can be obtained at any time.

3. Reloading and Flushing Biferno

The reload operation reinitializes an application so that the Biferno.config.bfr file is executed again at next user click. A reload also reinitializes all application variables. Similarly, a flush operation reloads all files in the application cache (see Chapter 22, Cache Management).

A reload or flush can be executed either using bifernoadmin or by the administrator on the command line. The reload and flush procedures for an application and its subapplications are described in "Biferno: bifernoadmin Guide".

4. Local Variables

Every time a script (other than "Biferno.config.bfr") initializes a variable without explicitly specifying its scope, a local variable is created. The scope of a local variable is limited to the area or program block in which the variable has been initially instantiated. Neither read nor write access to the variable from outside that block is possible.

Functions constitute stand-alone program blocks. If we create a variable in the main block of a script, this variable will not be visible from within a function and it will not be visible from another script. Similarly, local variables used within a function are not visible outside of the function itself (we will discuss functions further in this document). Notice that the body of a function, i.e. the code delimited by curly brackets that follows the header of the function (its prototype, i.e. class, name and parameter list), is a code block which is different from the main block of a script. Conversely, simply enclosing code between curly brackets (a legal syntax in Biferno) does not define a different code block and is used only to improve code readability.

The scope identifier for a local variable is local. In practice it is not necessary to explicitly declare the scope of a local variable (except in Biferno.config.bfr), as local is the default scope when a new variable is initialized.

5. Global Variables

A global variable is visible from all blocks within a script, i.e. its scope is the entire script. This implies that the value of a global variable defined in the main body of a script can be read and modified from within a method or function.

A global variable defined in a script is not visible from other scripts within the same application and is reinitialized every time script execution is requested by a client.

Global variables are created by specifying their scope using the global keyword in front of the variable name. E.g. if we write <? global myVar = 1 ?>, we have created a global variable of int class and with value 1. We can reference the myVar variable from within a function called by the same script by using the global keyword in front of the variable name. If we do not specify the global keyword, a local variable called myVar is referenced. This will generate an error if the variable is not defined, or reference the wrong variable if a local variable with the same name is indeed defined, without any warnings or errors.

6. Persistent Variables

A persistent variable is visible from the entire application but, unlike an application variable, its value is stored in persistent memory on the Web server. In fact, its value is written to a file. This type of variables is useful to hold data that has to be stored indefinitely, even after Biferno has been terminated.

Assume we need to implement a counter to measure the number of accesses to the home page of our application. In the configuration file of the application we can add the following code:

if (!curScript.IsDef("persistent home_counter"))
	persistent home_counter = 0
    

The code initializes the persistent variable to zero only if the variable had not been previously define. This avoids that the variable be reset to zero every time the server is started.

In our home page script we will write:

persistent home_counter++
    

The home_counter variable is incremented every time the script is executed. The home_counter variable will store indefinitely the last assigned value, which can then be used to count and visualize the total number of hits on our home page.

Persistent variables can not be instantiated for some classes (e.g. this is not possible for the db and file classes). Also, it is not possible to create persistent variables for user defined classes (see Chapter 11, User classes).

The classInfo(className).persistentAllowed property can be examined to query the ability of a class named classInfo to support persistent variables.

How can a persistent variable be deleted?

Persistent application variables are stored in a file called "biferno_pst.s.bfr" in the root directory of the application together with the "Biferno.config.bfr" file. To delete one or more persistent variables it is sufficient to open this file with a text editor and manually remove the lines corresponding to the variable to be deleted. After this, Biferno should be reloaded to execute the modifications (see Chapter 9, Applications and Variable Scope).

Notice that in this file the persistent scope is not used in front of declarations, because the default scope within this file is "persistent". This is similar to the mechanism used in the Biferno.config file, where the default scope is "application".

This file is generated by Biferno and should not be modified by the user other than to delete persistent variables as explained. New variable declarations should always be inserted in the Biferno.config file as in the example above. Notice that a file "biferno_pst.x.bfr" is present in the same directory as "biferno_pst.s.bfr". This is an internal Biferno file containing essential application information and should never be moved, removed or modified.

If an application seems to have trouble with persistent variables, check that the two aforementioned files are owned by the Biferno user and that the owner has read/write permission on these files. Permissions are set correctly by Biferno and should be always correct unless they have been manually modified.

7. Session Variables

Similarly to persistent variables, session variables are visible to the entire application and are used to save information specific to a single user that has to be accessible from all site pages.

Session variables are unique for each user that connects to the site. This allows different users to create/modify different variables or access variables with the same identifiers but different values. Instead, application and persistent variables are shared by all users of the same application.

Cookies are used to associate session variables to the users that created them. A cookie is a mechanism that is available to server side applications, such as Biferno, to store information on the client side, i.e. in the browser application that executes user connection requests. The cookie, initially created by the server and sent to the client, is resent to the server by the client upon each connection. Biferno uses the cookie to store a unique session identifier (containing, among others, the IP address of the client), which allows Biferno to distinguish among users. Notice that application pages will generate an error message for a user that has disabled cookies on his browser.

Session variables have a lifetime defined by the SESSION_TIMEOUT parameter (the default is 15 minutes). A session variables dies (is removed from server memory) either when the associated user is disconnected from the site for a period of time greater than the defined lifetime or when the user terminates his browser application.

A typical use of session variables is in the implementation of user-specific preferences for a site. We have seen in one of the examples how to use an application variable to define a common background color for all pages of a site. Assume now that we want to still make available a default color, but allow each user to choose the preferred background color.

The following script, contained in the "color.bfr" file, can be used:

<?
if (!curScript.IsDef("color"))
{
	color = application body_background //Uses the application variable
}
else
{
	session user_color = color //Set the session variable
}
?>
<html>
	<body bgcolor="$color$">
		<p>Select a background color for all pages of this site </p>
		<form name="setcolor" method="post" action="color.bfr">
		<select name="color">
		<option value="$application body_background$">Default</option>
		<option value="#ffffff">White</option>
		<option value="#fffedc">Light yellow</option>
		<option value="#e0ffff">Light blue</option>
		</select>
		&nbsp;<input type="submit" name="set" value="Set color">
		</form>
	</body>
</html>
    

Let's look at the first few rows of the script. The color variable is passed to the "color.bfr" script via the "color" select of the HTML form "setcolor". We will explain methods to pass parameters between Biferno scripts in the following. At this time it will suffice to say that HTML protocol parameters passed using the GET and POST methods are automatically associated to variables with the same name and value of the corresponding parameter. In our case the color variable is not defined when the page is requested by the browser for the first time, because it has never been initialized. When this is the case, we create the color variable and assign it the value of the application variable body_background, which has been defined in the configuration file. If the color variable exists, then the page has been reloaded by the user by sending data via the "setcolor" form. In this case we create a session variable (user_color) and assign it the value of color.

From now on, this instance of the user_color variable is visible only to the user (or better to the client) that has just loaded the "color.bfr" page. To use the user_color variable in other site pages we use the following self-explanatory code:

<?
	if (curScript.IsDef("session user_color"))
	{
		color = session user_color //Use session variable 
	}
	else
	{
		color = application body_background //Use application variable 
	}
?>
<html>
	<body bgcolor="$color$">
	</body>
</html>
    

In summary, a unique session identifier is assigned to each user that requests a Biferno page. Users can create different instances of a session variable that have, in general, different values. From the point of view of the server (i.e. for Biferno), each instance of a session variable with the same name but associated to a different user is a different variable that has its own space in memory.

To be able to use session variables in an application the parameter SESSION in the "Biferno.config.bfr" file must be set to true.

8. Communication between Applications

Biferno has a mechanism that makes it possible for an application to access variables with application, persistent, or session scope belonging to another application.

The predefined static method curApp.Publish makes a variable visible to all active applications. Only variables with application, persistent or session scope can be published. E.g. we can write:

<?
	application aWebMasterName = "John Smith"
	curApp.Publish(aWebMasterName)
?>
    

To access the value of a variable published by another application we use the predefined static method curApp.GetPubVariable, with the following prototype:

obj curApp.GetPubVariable(string application, string scope, string name)
    

The name of the application that published the variable, as well as the scope and name of the published variable, must be specified. The function returns a copy object of the published variable, and therefore modifications of the returned variable have no effect on the original variable.

The following script loads in an array the names of all active applications (using the predefined static property biferno.applications) and, for each application found, inserts an element in another array that holds either the value of the webMast variable, if published by the corresponding application, or the null string if the aWebMasterName variable was not published.

<?
	arr_apps = biferno.applications
	nApps = arr_apps.dim
	arr_wm = array()
	error.Resume()
	for (i = 1; i <= nApps; i++)
	{
		app_name = arr_apps[i]
		wm = curApp.GetPubVariable(app_name, "application", "webMast")
		arr_wm.Add(app_name:curScript.ValueOf("wm"))
	}
?>
    

If the requested variable does not exist (i.e. has not been published by the application), the curApp.GetPubVariable method generates the Err_VariableNotDefined error and its result is undefined. The error.Resume method allows to catch this error condition and is discussed in Chapter 16, Error Handling and Debugging.

The complementary curApp.UnPublish method can be used to undo the effect of the curApp.Publish method:

<?
	curApp.UnPublish(aWebMasterName)
?>
    

Notice that, before a variable published by an application can be requested, the publishing application must have been initialized. Remember that an application is automatically initialized when one of its scripts is requested or when the curApp.RegisterNewApp() method is called (see the note How is a Biferno application started?). If the publishing application has not been initialized, the curApp.GetPubVariable method returns the Err_NoSuchApplication error.