This recipe describes how to configure Apache for running Perl, Ruby, PHP, and Python scripts. It also illustrates how to write web-based scripts in each language.
There are typically several directories under the Apache root directory. Here I’ll assume that directory to be /usr/local/apache, although it may be different on your system. For example, on Windows, you might find Apache under C:Program Files. The directories under the Apache root include bin (which contains httpd—that is, Apache itself—and other Apache-related executable programs), conf (for configuration files, notably httpd.conf, the primary file used by Apache), htdocs (the root of the document tree), and logs (for logfiles). The layout might differ on your system. For example, you might find the configuration files in /etc/httpd and the logs under /var/log/httpd. Modify the following instructions accordingly.
To configure Apache for script execution, edit the httpd.conf file in the conf directory. Typically, executable scripts are identified either by location or by filename suffix. A location can be either language-neutral or language-specific.
Apache configurations often have a
cgi-bin directory
under the Apache root directory in which you can install scripts that
should run as external programs. It’s configured using a
ScriptAlias
directive:
ScriptAlias /cgi-bin/ /usr/local/apache/cgi-bin/
The second argument is the actual location of the script directory in your filesystem, and the first is the pathname in URLs that corresponds to that directory. Thus, the directive just shown associates scripts located in /usr/local/apache/cgi-bin with URLs that have cgi-bin following the hostname. For example, if you install the Ruby script myscript.rb in the directory /usr/local/apache/cgi-bin on the host localhost, you’d request it with this URL:
http://localhost/cgi-bin/myscript.rb
When configured this way, the cgi-bin directory can contain scripts
written in any language. Because of this, the directory is
language-neutral, so Apache needs to be able to figure out which
language processor to use to execute each script that is installed
there. To provide this information, the first line of the script
should begin with #!
followed by
the pathname to the program that executes the script. For example, a
script that begins with the following line will be run by Perl:
#!/usr/bin/perl
Under Unix, you must also make the script executable (use chmod
+x
), or it won’t run properly. The #!
line just shown is appropriate for a
system that has Perl installed as /usr/bin/perl. If your Perl
interpreter is installed somewhere else, modify the line accordingly.
If you’re on a Windows machine with Perl installed as C:Perlinperl.exe, the #!
line should look like this:
#!C:Perlinperl
For Windows, another option that is simpler is to set up a filename extension association between script names that end with a .pl suffix and the Perl interpreter. Then the script can begin like this:
#!perl
Directories used only for scripts generally are placed outside of your Apache document tree. As an alternative to using specific directories for scripts, you can identify scripts by filename extension, so that files with a particular suffix become associated with a specific language processor. In this case, you can place them anywhere in the document tree. This is the most common way to use PHP. For example, if you have Apache configured with PHP support built in using the mod_php module, you can tell it that scripts having names ending with .php should be interpreted as PHP scripts. To do so, add this line to httpd.conf:
AddType application/x-httpd-php .php
You may also have to add (or uncomment) a LoadModule
directive for php.
With PHP enabled, you can install a PHP script myscript.php under htdocs (the Apache document root directory). The URL for invoking the script becomes:
http://localhost/myscript.php
If PHP runs as an external standalone program, you’ll need to tell Apache where to find it. For example, if you’re running Windows and you have PHP installed as C:Phpphp.exe, put the following lines in httpd.conf (note the use of forward slashes in the pathnames rather than backslashes):
ScriptAlias /php/ "C:/Php/" AddType application/x-httpd-php .php Action application/x-httpd-php /php/php.exe
For purposes of showing URLs in examples, I’m going to assume that Perl, Ruby, and Python scripts are in your cgi-bin directory, and that PHP scripts are in the mcb directory of your document tree, identified by the .php extension. That means the URLs for scripts in these languages will look like this:
http://localhost/cgi-bin/myscript.pl http://localhost/cgi-bin/myscript.rb http://localhost/cgi-bin/myscript.py http://localhost/mcb/myscript.php
If you plan to use a similar setup, make sure that you have a cgi-bin directory that Apache knows about, and an mcb directory under your Apache document root. Then, to deploy Perl, Ruby, or Python web scripts, install them in the cgi-bin directory. To deploy PHP scripts, install them in the mcb directory.
Some of the scripts use modules or library files that
are specific to this book. If you have these files installed in a
library directory that your language processors search by default,
they should be found automatically. Otherwise, you’ll need to indicate
where the files are located. An easy way to do this is by using
SetEnv
directives in your httpd.conf file to set environment
variables that can be seen by your scripts when Apache invokes them.
(Use of the SetEnv
directive
requires that the mod_env Apache module be
enabled.) For example, if you install library files in /usr/local/lib/mcb, the following
directives enable Perl, Ruby, and Python scripts to find them:
SetEnv PERL5LIB /usr/local/lib/mcb SetEnv RUBYLIB /usr/local/lib/mcb SetEnv PYTHONPATH /usr/local/lib/mcb
For PHP, add /usr/local/lib/mcb to the value of include_path
in your php.ini
configuration file.
For background information on library-related environment variables and the php.ini file, see Writing Library Files.
After Apache has been configured to support script execution, restart it. Then you can begin to write scripts that generate web pages. The remainder of this section describes how to do so for Perl, Ruby, PHP, and Python. The examples for each language connect to the MySQL server, run a simple query, and display the results in a web page. The scripts shown here indicate whether there are any additional modules or libraries that web scripts typically need to include. (Later on, I’ll generally assume that the proper modules have been included and will show only script fragments.)
Before we proceed further, I should mention a couple of debugging tips:
If you request a web script and get an error page in
response, have a look at the Apache error log, which is a useful source of diagnostic
information when you’re trying to figure out why a script doesn’t
work. A common name for this log is error_log in the
logs
directory. If you don’t find any such file, check httpd.conf for an ErrorLog
directive to see where Apache
logs its errors.
Sometimes it’s helpful to directly examine the output that a
web script generates. You can do this by invoking the script from
the command line. You’ll see the HTML produced by the script, as
well as any error messages that it might print. Some web modules
expect to see a parameter string, and might even prompt you for
one when you invoke the script at the command line. When this is
the case, you might be able to supply the parameters as an
argument on the command line to avoid the prompt. For example, the
Ruby cgi
module expects to see
parameters, and will prompt you for them if they are
missing:
%myscript.rb
(offline mode: enter name=value pairs on standard input)
At the prompt, enter the parameter values and then enter Ctrl-D (EOF). To avoid the prompt, supply the parameters on the command line:
%myscript.rb "param1=val1;param2=val2;param3=val3"
To specify “no parameters” explicitly, provide an empty argument:
%myscript.rb ""
The following listing shows our first web-based Perl
script, show_tables.pl. It
produces an appropriate Content-Type:
header, a blank line to separate the header from the page
content, and the initial part of the page. Then it retrieves and
displays a list of tables in the cookbook
database. The table list is
followed by the trailing HTML tags that close the page:
#!/usr/bin/perl # show_tables.pl - Display names of tables in cookbook database # by generating HTML directly use strict; use warnings; use Cookbook; # Print header, blank line, and initial part of page print <<EOF; Content-Type: text/html <html> <head> <title>Tables in cookbook Database</title> </head> <body bgcolor="white"> <p>Tables in cookbook database:</p> EOF # Connect to database, display table list, disconnect my $dbh = Cookbook::connect (); my $stmt = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME"; my $sth = $dbh->prepare ($stmt); $sth->execute (); while (my @row = $sth->fetchrow_array ()) { print "$row[0]<br /> "; } $dbh->disconnect (); # Print page trailer print <<EOF; </body> </html> EOF
To try the script, install it in your cgi-bin directory and request it from your browser as follows:
http://localhost/cgi-bin/show_tables.pl
show_tables.pl generates
the Content-Type:
header
explicitly and it produces HTML elements by including literal tags
in print statements. Another approach to web page generation is to
use the CGI.pm module, which makes it easy to write web scripts
without writing literal HTML tags. CGI.pm provides an
object-oriented interface and a function call interface, so you can
use it to write web pages in either of two styles. Here’s a script,
show_tables_oo.pl, that uses the
CGI.pm object-oriented interface to produce the same report as
show_tables.pl:
#!/usr/bin/perl # show_tables_oo.pl - Display names of tables in cookbook database # using the CGI.pm object-oriented interface use strict; use warnings; use CGI; use Cookbook; # Create CGI object for accessing CGI.pm methods my $cgi = new CGI; # Print header, blank line, and initial part of page print $cgi->header (); print $cgi->start_html (-title => "Tables in cookbook Database", -bgcolor => "white"); print $cgi->p ("Tables in cookbook database:"); # Connect to database, display table list, disconnect my $dbh = Cookbook::connect (); my $stmt = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME"; my $sth = $dbh->prepare ($stmt); $sth->execute (); while (my @row = $sth->fetchrow_array ()) { print $row[0], $cgi->br (); } $dbh->disconnect (); # Print page trailer print $cgi->end_html ();
The script includes the CGI.pm module with a use
CGI
statement, and then creates a CGI
object, $cgi
, through which it
invokes the various HTML-generation calls. header()
generates the Content-Type:
header and
start_html()
produces the initial page tags up through the opening
<body>
tag. After
generating the first part of the page, show_tables_oo.pl retrieves and displays
information from the server. Each table name is followed by a
<br />
tag, produced by
invoking the
br()
method.
end_html()
produces the closing </body>
and </html>
tags. When you install the
script in your cgi-bin
directory and invoke it from a browser, you can see that it
generates the same type of page as show_tables.pl.
CGI.pm calls often take multiple parameters, many of which are
optional. To enable you to specify just those parameters you need,
CGI.pm understands -name
=>
value
notation in parameter lists. For example, in the start_html()
call, the title
parameter sets the page title and
bgcolor
sets the background
color. The -name
=>
value
notation also allows parameters to be specified in any order, so
these two statements are equivalent:
print $cgi->start_html (-title => "My Page Title", -bgcolor => "white"); print $cgi->start_html (-bgcolor => "white", -title => "My Page Title");
To use the CGI.pm function call interface rather than the
object-oriented interface, you must write scripts a little
differently. The use
line that
references CGI.pm should import the method names into your script’s
namespace so that you can invoke them directly as functions without
having to create a CGI
object.
For example, to import the most commonly used methods, the script
should include this statement:
use CGI qw(:standard);
The following script, show_tables_fc.pl, is the function call
equivalent of the show_tables_oo.pl script just shown. It
uses the same CGI.pm calls, but invokes them as standalone functions
rather than through a $cgi
object:
#!/usr/bin/perl # show_tables_fc.pl - Display names of tables in cookbook database # using the CGI.pm function-call interface use strict; use warnings; use CGI qw(:standard); # import standard method names into script namespace use Cookbook; # Print header, blank line, and initial part of page print header (); print start_html (-title => "Tables in cookbook Database", -bgcolor => "white"); print p ("Tables in cookbook database:"); # Connect to database, display table list, disconnect my $dbh = Cookbook::connect (); my $stmt = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME"; my $sth = $dbh->prepare ($stmt); $sth->execute (); while (my @row = $sth->fetchrow_array ()) { print $row[0], br (); } $dbh->disconnect (); # Print page trailer print end_html ();
Install the show_tables_fc.pl script in your cgi-bin directory and request it from your browser to verify that it produces the same output as show_tables_oo.pl.
This book uses the CGI.pm function call interface for Perl-based web scripts from this point on. You can get more information about CGI.pm at the command line by using the following commands to read the installed documentation:
%perldoc CGI
%perldoc CGI::Carp
Appendix D lists other sources of information for this module, both online and in print form.
The Ruby cgi
module provides an interface to
HTML-generating methods. To use it, create a CGI
object and invoke its methods to
produce HTML page elements. Methods are named after the HTML
elements to which they correspond. Their invocation syntax follows
these principles:
If an element should have attributes, pass them as arguments to the method.
If the element has body content, specify the content in a code block associated with the method call.
For example, the following method call produces a <P>
element that includes an
align
attribute and content of
“This is a sentence”:
cgi.p("align" => "left") { "This is a sentence" }
The output looks like this:
<P align="left">This is a sentence.</P>
To display generated HTML content, pass it in a code block to
the cgi.out
method. The following
Ruby script, show_tables.rb,
retrieves a list of tables in the cookbook
database and displays them in an
HTML document:
#!/usr/bin/ruby -w # show_tables.rb - Display names of tables in cookbook database require "cgi" require "Cookbook" # Connect to database, display table list, disconnect dbh = Cookbook.connect stmt = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME" rows = dbh.select_all(stmt) dbh.disconnect cgi = CGI.new("html4") cgi.out { cgi.html { cgi.head { cgi.title { "Tables in cookbook Database" } } + cgi.body("bgcolor" => "white") { cgi.p { "Tables in cookbook Database:" } + rows.collect { |row| row[0] + cgi.br }.join } } }
The collect
method iterates
through the row array containing the table names and produces a new
array containing each name with a <br>
appended to it. The join
method concatenates the strings in
the resulting array.
The script includes no explicit code for producing the
Content-Type:
header because
cgi.out
generates one.
Install the script in your cgi-bin directory and request it from your browser as follows:
http://localhost/cgi-bin/show_tables.rb
If you invoke Ruby web scripts from the command line so that
you examine the generated HTML, you’ll see that the HTML is all on
one line and is difficult to read. To make the output easier to
understand, process it through the CGI.pretty
utility method, which adds line
breaks and indentation. Suppose that your page output call looks
like this:
cgi.out {page content here
}
To change the call to use CGI.pretty
, write it like this:
cgi.out {
CGI.pretty(page content here
)
}
PHP doesn’t provide much in the way of tag shortcuts,
which is surprising given that language’s web orientation. On the
other hand, because PHP is an embedded language, you can simply
write your HTML literally in your script without using print
statements. Here’s a show_tables.php script that shifts back
and forth between HTML mode and PHP mode:
<?php # show_tables.php - Display names of tables in cookbook database require_once "Cookbook.php"; ?> <html> <head> <title>Tables in cookbook Database</title> </head> <body bgcolor="white"> <p>Tables in cookbook database:</p> <?php # Connect to database, display table list, disconnect $conn =& Cookbook::connect (); $stmt = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME"; $result =& $conn->query ($stmt); while (list ($tbl_name) = $result->fetchRow ()) print ($tbl_name . "<br /> "); $result->free (); $conn->disconnect (); ?> </body> </html>
To try the script, put it in the mcb directory of your web server’s document tree and request it from your browser as follows:
http://localhost/mcb/show_tables.php
The PHP script includes no code to produce the Content-Type:
header because PHP produces
one automatically. (If you want to override this behavior and
produce your own headers, consult the header()
function section in the PHP
manual.)
Except for the break tags, show_tables.php includes HTML content by
writing it outside of the
<?php
and
?>
tags so that the PHP
interpreter simply writes it without interpretation. Here’s a
different version of the script that produces all the HTML using
print
statements:
<?php # show_tables_print.php - Display names of tables in cookbook database # using print() to generate all HTML require_once "Cookbook.php"; print ("<html> "); print ("<head> "); print ("<title>Tables in cookbook Database</title> "); print ("</head> "); print ("<body bgcolor="white"> "); print ("<p>Tables in cookbook database:</p> "); # Connect to database, display table list, disconnect $conn =& Cookbook::connect (); $stmt = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME"; $result =& $conn->query ($stmt); while (list ($tbl_name) = $result->fetchRow ()) print ($tbl_name . "<br /> "); $result->free (); $conn->disconnect (); print ("</body> "); print ("</html> "); ?>
Sometimes it makes sense to use one approach, sometimes the
other—and sometimes both within the same script. If a section of
HTML doesn’t refer to any variable or expression values, it can be
clearer to write it in HTML mode. Otherwise it may be clearer to
write it using print
or echo
statements, to avoid switching
between HTML and PHP modes frequently.
A standard installation of Python includes cgi
and
urllib
modules
that are useful for web programming. However, we don’t actually need
them yet, because the only web-related activity of our first Python
web script is to generate some simple HTML. Here’s a Python version
of the MySQL table-display script:
#!/usr/bin/python # show_tables.py - Display names of tables in cookbook database import MySQLdb import Cookbook # Print header, blank line, and initial part of page print """Content-Type: text/html <html> <head> <title>Tables in cookbook Database</title> </head> <body bgcolor="white"> <p>Tables in cookbook database:</p> """ # Connect to database, display table list, disconnect conn = Cookbook.connect () cursor = conn.cursor () stmt = """ SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'cookbook' ORDER BY TABLE_NAME """ cursor.execute (stmt) for (tbl_name, ) in cursor.fetchall (): print tbl_name + "<br />" cursor.close () conn.close () # Print page trailer print """ </body> </html> """
Put the script in Apache’s cgi-bin directory and request it from your browser like this:
http://localhost/cgi-bin/show_tables.py
3.15.214.155