Table of Contents
This Chapter introduces the concept of Biferno "application" and discusses how to determine the scope of a variable, i.e. its region of validity.
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.
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.
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/")
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.
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.
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.
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".
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.
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.
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.
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.
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>
<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.
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.