CGI Scripting
Sharing Perl Code - Example #3
The emphasis within these pages has been on code sharing to maximise the efficiency of a website and simplify its management.
So far it has been possible to share all resources, CSS, JS and even parts of the pages themselves as SSIs, Perl code is no different.
In Perl it is possible to extract any subroutines that you wish to share between programs and package them in a separate script: A Perl Module. The module can then be included within any programs which reference its subroutines. The general method is common practice in many languages and certainly in all languages that you are likely to encounter in CGI programming.
Packaging subroutines like this is a handy way to make them portable. With this in mind it is important to code the subroutines carefully so that they can work under the widest possible range of conditions.
Here we will apply this principle to a revised version of our example program: »Temperature Converter v3 we have used as an example so far...
The basic syntax of a perl module is as follows...
require 5.000;
use Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
output_ssi
function2
);
sub output_ssi
{my $file = $_[0];unless((defined($file)) && ($file)) {return;}
open(SSI,"$file") || die "Cannot open $file for read: $!";
while(<SSI>) {print $_;}
close(SSI) || die "Cannot close $file after read: $!";
}
sub function2
{ ... }
1;
This is saved as a distinct file (in this case dwd.pm
this must
match the declared name at the top of the module script) and
placed within /cgi-bin
or within your Perl library.
Note the 1;
at the very end, this is the return code to tell
the Perl interpreter that this module has loaded. Each subroutine that you wish
to make available to the other programs needs to be listed in the
@EXPORT
array, another Perl environment variable.
use Exporter
is a directive to use another Perl module.
As the name suggests this is a key part of the module export function.
On execution Perl will look in all of the directories specified within its @LIB
environment array and load all recognisable modules that it finds.
Note! For /cgi-bin
to be included this variable will need to include '.' (dot - the current working directory) Consult your Perldocs for more information on how to change this.
Within the program the module is included at the start of the script
as follows...
...and from thereon within the program, the subroutines are referenced as usual.
use strict;
use dwd;
So far we have described one subroutine which would be useful in this module as it will be required by all of the CGI programs used and described on this website. This is: output_ssi
As discussed in a previous section, the idea here is to make all of the dynamic pages appear the same as the static ones, in so doing some subroutines were created in the last example to output the top and bottom sections of the page. These too are ideally placed within the shared module, although they will need to be in a slightly different form so as to allow for differences in titles, headings and page meta-data.
In practice this is not hard to do although it does require some careful thought beforehand to ensure that the function does not constrain the page in any way.
We can apply this idea to the previous temperature converter widget...
Instead of having the page section subroutines within the program we
can make them more generic and add them into a perl module called by
the program. This reduces the volume of program code and ensures that all
subsequent programs use the exact same routines and thus give a consistent
output.
»Execute the program - Temperature Converter v3, see the sidebar links for v3 source code...
Program Enhancements
Apart from having pulled much of the subroutines out into the dwd.pm module the program has some additional changes too. The new sections are highlighted within the source code view.
In the previous section mention was made of the hard-coded values for the SSI files, and that this is generally bad practice. For this reason the various SSI files are now all defined in one section at the start of the program.
Rather than clutter up the Perl environment space with multiple scalar
variables, one for each SSI file or other definitions, we instead use a
single hash %G
(G for Global!) Because we only have a single
data structure containing all of the values it is a simple matter to pass
this hash by reference between functions. This comes into its own when
calling functions within the module as variables declared within the scope
of the program are not available to the module subroutines.
This is done in the do_top
function for example
where the call is: do_std_head(\%G);
The <title>
string is also stored within the
%G
hash. By so doing we can now use a single highly generic
function for all of that part of the page as this will be identical for
every page on the website except for this <title>
value.
Another handy use for the global data hash, storing page specific values
for later reference.
In the case of a single program this is all that is needed, the definitions are easy enough to change. But if this data is to be shared amongst many programs within a website then a more technical approach is called for. This will be explained in the next section where we will create a CGI program suite where all of these requirements are taken care of with the minimum of fuss, leaving you free to concentrate on the program function!