Perl: Practical Extraction and Report Language
Perl is a very powerful and popular
language for writing Web Server-side CGI scripts and
for system administration. It is free and available in UNIX, PC, and Mac
platforms.
We will use Robert
Pepper's tutorial on Basic Perl programming for Perl and Lincoln
Stein's CGI module for using Perl in Common Gateway Interface (CGI) programming.
The following is the set of related links.
- Nix
Silver's tutorial
- Perl Tutorial by Robert Pepper
http://perl.sioc.org/win32perltut.html
- Perl
manpage (syntax, builtin function) and modules web pages on www.perl.com
- Perl
Regular Expression Summary
- FAQ
on Perl
- Lincoln
Stein's CGI.pm (a Perl5 CGI Library) module
- References: Oreily
publisher has the whole series of perl books.
- Learning
Perl 3rd edition is a good introductory book for beginners using perl
UNIX systems.
- CGI
Programming with Perl, 2nd Edition. demonstrate current techniques available
with the CGI.pm module. Topics include incorporating JavaScript for form
validation, working with databases, creating simple search engines, maintaining
state between multiple sessions, generating graphics dynamically.
- Learning
Perl on Win32 systems is a good introductory book for beginners using
perl on Win32 systems (95,98?,NT).
- We will use unix machines in
our software engineering lab, such as wetterhorn, redcloud, blanca, crestone,
to carry out the Perl and CGI related exercises. You can remote login to carry
out these exercises.
- To
spread out the load, use the following table to pick the computer for your
exercises. If the designated computer is down, you are allowed to use other
computers and viva.uccs.edu. But be aware for debugging of CGI scripts, the error msg will be
kept on the /etc/httpd/logs/error_log of the machnie that run the server side
CGI script. See Debugging CGI Script Section for
more information.
|
Student
ID % 6 |
Designated Computer for Web Programming Exercises |
|
0 |
sanluis |
|
1 |
blanca |
|
2 |
shavano |
|
3 |
crestone |
|
4 |
wetterhorn |
|
5 |
redcloud |
Any one with 995-99-xxxx or those students from CYU will use viva.uccs.edu for their exercises.
Setup your cgi-bin directory
on CS Unix Machines
- Create a cgi-bin subdirectory
in your public_html directory.
- Testing the setup:
- copy form.html to your own public_html
cp ~cs301/public_html/form.html
~<login>/public_html
Here <login> is your CS Unix machine login.
- modify the action attribute
in the form.html, Replace
<form
action="http://cs.uccs.edu/cgi-bin/cs301/fullecho.cgi" method=post>
with
<form
action="http://blanca.uccs.edu/~<login>/cgi-bin/fullecho.cgi" method=post>
Here blanca is your assigned web server and <login> is your CS Unix machine login.
- form tag is used to create
form for collecting user input. See http://www.w3.org/TR/1998/REC-html40-19980424/interact/forms.html
for more info.
- If you are assigned with CS Unix machines, run the following command "cp -r ~cs301/public_html/cgi-bin/* ~<login>/public_html/cgi-bin"
- If you are asssigned with viva.uccse.edu,
cd public_html/cgi-bin
scp cs522p1@windom:~cs301/public_html/cgi-bin/*
.
- If your designated machine
is sanluis, type "sanluis.uccs.edu/~<login>/cgi-bin/sessionvar.cgi"
as URL to the browser.
You should see a list of environment variables passed to the CGI program,
sessionvar.cgi. That indicates your cgi-bin directory is set up right.
- Note that we did not turn on cgiwrap
on cs.uccs.edu yet. The url http://cs.uccs.edu/~cs301/cgi-bin/sessionvar.cgi
will return "access forbidden" or the actual source code depends
on the access right of your sessionvar.cgi
- Type "sanluis.uccs.edu/~<login>/form.html"
in Address box and see if the form data get echoed back.
- If you got Internal server error,
you need to check the access rights of the cgi-bin and files just created.
- The cgi-bin directory the cgi
scripts needs to have read and execute permissions for the owner. Make
sure it has -drwx------ or --rwx------ setting.
- We are using a software package
called cgiwrap so that users
on our CS Unix machines can create their server side cgi scripts in their
own cgi-bin directory.
- Besides remote login to the
CS Unix machine, you can practice programming in perl and CGI scripting on
your home PC by downloading and setting up xampp software from apachefriends.org,
which include Apache, Perl, PHP, and MySQL. You can then scp or sftp
the CGI programs to the CS Unix machines for testing. Note that the first
line of Perl CGI script needs to be changed since it indicates the location
of interpreter on the web server.
- Click here for the
info on downloading and setup of Apache, Perl, PHP, MySQL on windows.
- FAQ
on ntperl: Perl for WIN32 PC.
- But be aware there are system
related differences between UNIX and Win32 (95, 98 or NT). For example,
- Path
name difference: Use "c:\\temp\\test.pl" to refer the file name
c:\temp\test.pl since \ is a specal escape character in perl.
- Remember we use \ in \n for
representing newline.
- You can use "c:/temp/test.pl"
unix-style forward slash for path name. Now you know perl for WIN32 is 2nd
class citizen in perl world. "c:\temp\test.pl" will not be a legal file
name, since it is a string with c: followed by tab character, followed by
emp, then tab, finally est.pl.
- Input
operation difference: For indicating the end of input string,
- on PC, use control-Z to
represent no more input for the program on PC. If you try to use control-D
to indicate no more input on PC, the program will keep waiting.
- on UNIX, use control-D to
represent no more input for the program on UNIX. If you use control-Z
on UNIX, it will put your program on hold until you type fg to bring it
back or bg to start background processing.
- System
command/utility difference: The available command and utility
routines are different. Try to use those provide by the Perl library
for portability.
Quick Summary of Perl
Setup: Editing and Running Perl
Literals
-
Numeric literals are specified
in any of the customary floating point or integer formats:
12345
12345.67
.23E-10
0xffff
# hex
0377
# octal with 255 decimal value. Each octal digit is 3 bits.
4_294_967_296
# underline for legibility
-
String literals are usually
delimited by either single or double quotes. They work much like shell
quotes.
-
double-quoted string literals
are subject to backslash and variable substitution;
single-quoted strings are not. For example:
$name
= "Perl Scripts";
print
'$name'; # print exactly the 5 characters between '.
print
"$name"; # print 12 characters, 'Perl Scripts' $name
is substituted with that.
Variables
-
The types of the variables in
Perl can be easily recognized by the first character of the name/identifier.
-
$
for scalar variable (single value, can contain integer value, real number,
or string. Perl is not a strong typed language.) For example,
$counter,
$classname, $semester
-
@
for array variable (0-based numberic indexed
array with multiple values). For example,
@cookies
= ("camel delites", "peanet butter patties", "shortbread", "thin
mints", "peanut butter sandwich");
-
indvidual
element can be accessed as $cookies[0] ("camel delites"), $cookies[2] ("shortbread").
-
The index
of the last element in the array can be obtained through $#cookies.
-
The length
of the array can be obtained by assigning @cookies to a scalar variable.
$length=@cookies;
if
(@cookies == 0) { print "cookies array is empty!\n" }
-
%
for associate array varaible (string indexed array with multiple values).
For example,
%nameValuePairs = ("name"
=> "Edward Chow", "email" =>"chow@cs.uccs.edu", "phone" => "262-3110");
- indvidual
element can be accessed as $nameValuePairs{"name"},
$nameValuePairs{"email"}.
- Note that instead
of [], {} is used for wrapping around the string index.
- A string index for
an associate array is called key, e.g., in the above nameValuePair, name,
email, and phone are keys.
- The
set of keys in the associate array can be obtained through "keys
%nameValuePairs"
-
The scalar variables in Perl
have the name starting with '$'.
-
A typical identifier for scalar
variable consists of '$', followed by letter or '_', followed by
letter or '_' or digits.
-
Special Variables:
-
$<digits> : These are variables
contain the matching results of regular expression execution. e.g., $1
is the first text pattern matched, $3 is the 3rd text pattern matched.
Therefore we typically avoid using these names as identifiers.
-
$ARGV[n]: This is nth parameters
in the command line (or called the nth elements in the command line argument
vector) . n is a number.
-
$_: a variable used to
contain the result of the last operation.
-
Variable interpolation: This
refers to a power feature in construction string literal. The double
quote string can contain variables and their values will be replaced
for the final content of the double quote string. For example,
print "The first cookie
is $cookies[0].\n";
The string "The first cookie
is camel delites" will be printed out followed by end of line.
Operators
-
Operator precedence rule: the
order of the operators in an expression are evaluated according to their
relative
precedence level (from highest to lowest)
-
Perl operators have the following
associativity and precedence, listed from highest precedence to lowest.
-
Note that all operators borrowed
from C keep the same precedence relationship with each other, even where
C's precedence is slightly screwy.
-
With very few exceptions, these
all operate on scalar values only, not array values.
| associativity |
operators |
Example |
| left |
terms and list operators
(leftward) |
print
"List of ", $class, " students\n";
@array=(1, 3, sort
4, 2); |
| left |
-> (infix dereference
operator) |
print $query->header('text/html'); |
| nonassoc |
++
-- |
$counter++;
print ++($foo = 'Az');
# prints 'Ba'! |
| right |
** (Exponential) |
-2**4 is -(2**4),
not (-2)**4. |
| right |
! (logical not)
~ (bitwise negate, 1's complement)
\ (create reference
variable)
unary + and - |
if (!$found) { print "not
found.\n"; exit 1;}
0666 & ~ 027 is 0640.
here it is octal code.
$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
$minus10 = -10; |
| left |
=~ !~ |
left operand is scalar variable
with data, right operand is search pattern, substitution, or translation.
$fullname =~
s/,.*//; |
| left |
* / %
x (repetive operator) |
print '-' x 80;
# print row of dashes
@ones = (5) x @ones;
# set all elements to 5 |
| left |
+ -
. (concatenate operator) |
$filename=$class . $semester
. "Photo.html"; |
| left |
<< >> (shift operator) |
$i= 5 << 2; # equivalent
to 5*4 |
| nonassoc |
named unary
operators, e.g.
-e File exists |
print "file exsit" if -e
$filename; |
| nonassoc |
< > <= >= (numeric
comparsion)
lt gt le ge (stringwise
comparison) |
$foo=291;
$bar=30;
if ($foo < $bar) {print "$foo is less than $bar (numeric)\n"; }
if ($foo lt $bar) {print "$foo is less than $bar (string)\n";} |
| nonassoc |
== != <=>
eq ne cmp |
<=> return -1, 0, 1 for
< , =, >
cmp return -1, 0, 1 for
string comparsion |
| left |
& (bitwise AND) |
|
| left |
| (bitwise
OR) ^ (bitwise XOR) |
|
| left |
&& |
short circuit logical AND |
| left |
|| |
short circuit logical OR |
| nonassoc |
.. ... |
for (101 .. 200) { print;
} # print $_ 100 times
@alphabet = ('A' .. 'Z'); |
| right |
? : (c compact if then else) |
($n == 1) ? "_": "s"; |
| right |
= += -= *= etc. |
|
| left |
,
=> (digraph, for documenting
arguments that come in pairs) |
print start_html(-title=>'Update
confirmed',
-bground=>'#ff9977'), |
| nonassoc |
list operators
(rightward) |
open HANDLE, "filename"
or die "Can't open: $!\n"; |
| right |
not |
low preference logical not |
| left |
and |
low precedence logical AND |
| left |
or xor |
low precedence logical XOR |
Selection Structures
-
if (condition1) {
} elsif (condition2) {
} else {
}
-
Unlike C or Java, Perl requires
both branches to be wrapped around with { }.
Iterative Structures
Associate Array and DBM
- initialize associate array.
Use ( followed by key=>value pairs).
@cookies =
sort qw(chocolate mint peanut butter mm);
%cookieJug
= (chocolate => 10,
mint => 20,
peanut => 30,
butter => 40,
mm => 50);
foreach $type
(@cookies) {
print "cookie type=$type, noOfBoxes=$cookieJug{$type}\n";
}
- update
the associate array element, updateAssocArray.pl
%cookieJug
= (chocolate => 10,
mint => 20,
peanut => 30,
butter => 40,
mm => 50);
print "Enter
the cookie shipping just arrived:";
chop($type=<STDIN>);
print "Enter
the number of boxes that arrived:";
chop($boxno=<STDIN>);
$boxInStore
= $cookieJug{$type};
print "The
no. of $type boxes in store before=$boxInStore\n";
$boxInStore
+= $boxno;
$cookieJug{$type}
= $boxInStore;
print "The
no. of $type boxes in store after=$boxInStore\n";
- The content of associate array
disappears after the Perl script execution. You can save it to a file with
file format arrangement, or you can use DBM file that map automatically to
an associate array without file conversion.
- Tie associate array with DBM
file for data persistence.
- Initializes the associate array
bound with DBM file, dbminit.pl
%cookieJugInit
= (chocolate => 10,
mint => 20,
peanut => 30,
butter => 40,
mm => 50);
dbmopen %cookieJug,
"cookieData", 0666; #octal code 0666 for write access
foreach $type
(keys %cookieJugInit) { # keys function return an array of all keys in
an assoc array
$cookieJug{$type}
= $cookieJugInit{$type};
print
"$type $cookieJug{$type}\n";
}
dbmclose %cookieJug;
- Read associate array bound with
DBM file, dbmread.pl
dbmopen %cookieJug,
"cookieData", 0444; # 0444 for read access
print "cookie
noOfboxes\n";
print "=" x
25 , "\n";
foreach $type
(keys %cookieJug) {
$paddedType
= pad($type, 14);
# use subroutine call to pad string size to 14
print
"$paddedType $cookieJug{$type}\n";
}
dbmclose %cookieJug;
sub pad
{
my ($type, $maxChars) = @_;
#
print "parameter type=$type, maxChars=$maxChars\n";
$length = length $type;
#
print "no of characters in $type=$length\n";
for ($i=0; $i<$maxChars-$length; $i++) {
$type .= " "; # if use += it will be error
}
return $type;
}
- Order
processing: Substract value from associate array bound with DBM file, dbmUpdate.pl
print "Enter
the order cookie type:";
chop($type=<STDIN>);
print "Enter
the order cookie amount:";
chop($amount=<STDIN>);
# check if
inventory has enough
dbmopen %cookieJug,
"cookieData", 0666;
$inventory
= $cookieJug{$type};
if ($inventory
< $amount) {
print "Not in stock! We will order for you. Take about a week.\n";
} else {
print "In stock! Ship within 24 hours.\n";
$cookieJug{$type} -= $amount;
}
dbmclose %cookieJug;
- Note that
the dbm file created by you during the debugging by default only your login
with write access. To allow web server running as nobody to write, you
need to change the access right of the dbm file to 0666.
- Here is
an example of using dbm for creating password list and perform password checking.
It consists
of two scripts: password.pl and updatePassword.pl
- password.cgi
will be accessed as http://sanluis.uccs.edu/~cs301/cgi-bin/password.cgi
#!/usr/bin/perl
use CGI qw(:standard);
print
header();
print start_html(-title=>'Update
Password',
-bgcolor=>'#EDDF99'),
h1('Update
Administrator User Password'),
hr;
# retrieve
the current password list
dbmopen
%passwordList, "order/password", 0666;
print start_form(-method=>'POST',
-action=>'updatePassword.cgi');
print
p("Here is the current list of login and password\n");
print "<TABLE
border=1 BGCOLOR=\"#EDDFC9\">\n";
print "<TR><TH>Login</TH><TH>Password</TH></TR>\n";
foreach
$login (keys %passwordList) {
$password = $passwordList{$login};
print "<TR><TD>$login</TD><TD>$password</TD></TR>\n";
}
dbmclose
%passwordList;
print "</TABLE>\n";
print p("Enter
your administrator login and password for updating the password.\n");
print "<TABLE
border=1 BGCOLOR='#93DDDB'>\n";
print "<TR><TD>Login:</TD><TD><INPUT
type=text name=\"adminLogin\"></TD></TR>\n";
print "<TR><TD>Password:</TD><TD><INPUT
type=password name=\"adminPassword\"></TD></TR>\n";
print "</TABLE>\n";
print p("Enter
the new user login and password.\n");
print "<TABLE
border=1 BGCOLOR='#ff99DB'>\n";
print "<TR><TD>Login:</TD><TD><INPUT
type=text name=\"login\"></TD></TR>\n";
print "<TR><TD>Password:</TD><TD><INPUT
type=password name=\"password\"></TD></TR>\n";
print "</TABLE>\n";
print submit(-value=>"Update"),
reset, end_form;
print end_html;
- updatePassword.cgi
will be called when the submit button is pressed by the user when access the
web page created by the password.cgi.
#!/usr/bin/perl
use CGI qw(:standard);
print header();
print start_html(-title=>'Update
Password',
-bgcolor=>'#DD9999'),
h1('Update
Password');
# get the
current password
dbmopen %passwordList,
"order/password", 0666;
$adminLogin
= param('adminLogin');
$adminPassword
= param('adminPassword');
if ($adminLogin
eq 'root') {
if ($adminPassword ne 'cs301') {
print "Illegal login or password.", end_html;
exit();
}
} elsif ($passwordList{$adminLogin}
ne $adminPassword) {
print "Illegal login or password.", end_html;
exit();
}
# legal admin
print "Correct
Admin Password!<BR>\nCreating User Login and Password...<BR>\n";
$login =
param('login');
$password
= param('password');
print "login=$login,
password=$password<BR>\n";
$passwordList{$login}
= $password;
dbmclose
%passwordList;
print "New
Login and Password Created!\n", end_html;
- If you
are concerned about the security, you can use https instead of http. Also
it is usally not a good practice to hard coded the password in the script.
Since if there is a glitch in server configuration, the intruder may see the
source of the script:-)
- Exercise:
Write the Perl script, dbmadd.cgi, that allows an authorized person
to update inventory when cookies shipping arrives. Copy the password.cgi
and updatePassword.cgi to your cgi-bin directory and create a testing login=cookie
and password=monster as an authorized account for us to test your dbmadd.cgi.
Subroutine
-
syntax:
sub
<name of subroutine> {
.....
}
-
Here is an example, a subroutine
that pad the string with space characters to make up certain length, the
first parameter is the string, the second parameter is the length of final
padded string :
sub
pad {
my ($text, $maxChars) = @_;
$length = length $text;
for ($i=0; $i<$maxChars-$length; $i++) {
$text .= " "; # if use += it will be error
}
return $text;
}
-
Here is
how the subroutine will be called:
$paddedType
= pad($type, 14);
-
When pad
is called, $type and 14 will be put in a special array, @_.
-
We can
use my($p1, $p2, ..., $pn) = @_; to retrieve individual parameter.
-
You can
also use $parameter = shift; to get/remove the first parameter from the
implicit stack variable @_.
#!/usr/bin/perl
$text=
291;
$paddedText
= pad($text, 12);
sub
pad {
my $t = shift;
my $n = shift;
print "text=$t, length=$n\n";
}
I/O
- Reading from STDIN (console
input)
print "Please
Enter your name: ";
chop ($name=<STDIN>);
# remove end of line
print "Thanks
for making me happy, $name !";
- Reading from a file called shoppingCart.txt
open(IN, "shoppingCart.txt");
while (<IN>)
{ # equivalent to $_=<IN>
print; # equivalent to
print $_;
}
# loop thru each line of the file
- Append
to a file
%cookiePrice
= (chocolate => 1.0,
mint => 2.0,
peanut => 3.0,
butter => 4.0,
mm => 5.0);
print "Enter
new item to be added to the shopping card:";
chop ($item=<STDIN>);
print "Enter
the quantities:";
chop ($quantity=<STDIN>);
$price = $quantity
* $cookiePrice{$item};
open(OUT, ">>shoppingCart.txt";
# >> mean append, > mean write (overwrite)
print OUT "$item
$quantity $price\n";
close(OUT);
- Note that
to print to a specifc file we use OUT (the file handle) as the first
parameter.
Use $. for the line number.
open IN, "c:\\perl\\sub.pl";
while (<IN>)
{
print "Line number $. is : $_";
}
- Command
line processing
#!/usr/bin/perl
$class = $ARGV[0];
$semester =
$ARGV[1];
print "command
paramerters: \n1st argument is class=$class\n2nd argument is semester=$semester\n";
- To print
multiple lines of text (use <<string delimiter):
print <<END;
You can change
the appearance of this page by submitting
the fill-out
form below. If you return to this page any time
within 30
days, your preferences will be restored.
END
;
print
<<EOF;
<html><head><title>$TITLE</title></head>
<frameset
cols="50,50">
<frame
src="$script_name/query" name="query">
<frame
src="$script_name/response" name="response">
</frameset>
EOF
;
- Common
Mistake: Add space after ending string delimiter. There should not be any
space after EOF or END.
- Here is an example for adding
new user to a dbm file, addpd.pl:
#!/usr/bin/perl
use CGI qw(:standard);
dbmopen
%passwordList, "order/password", 0666;
print "current
password list\n=============\n";
foreach $login
(keys %passwordList) {
$password
= $passwordList{$login};
print
"login=$login password=$password\n";
}
print "\nenter
new login:";
$login =
<STDIN>;
chomp $login;
print "enter
password:";
$password
= <STDIN>;
chomp
$password;
print "login=$login,
password=$password\n";
print "=====\n
Here is the password list\n";
$passwordList{'root'}
= "cs301";
$passwordList{$login}
= $password;
dbmclose
%passwordList;
dbmopen
%pdList, "order/password", 0444;
foreach $login
(keys %pdList) {
$password
= $pdList{$login};
print
"login=$login password=$password\n";
}
dbmclose
%pdList;
Split
-
A powerful function to
separate the fields in a text string based on some delimiters (: , ; ,
tab, or white space). The result is an array.
-
$line="aanan:PqxLPda:4211:15:Arvin
Anan:/users/server/students/aanan:/bin/csh";
@fields
= split(/:/, $line); # $fields[0]=aanna; $fields[2]=4211
print
"The login of $fields[4] is $field[0].\n";
# the $line is an
entry in the password file, $field[1] is the encrypted password
-
Here is a line of an excel spreadsheet
file save in tab delimited text file format.
It contains the full name,
login, SS#, grades of hw1, hw2, hw3, and letter grade, separated by tab
character.
We use the split to separate
them into an array.
$gradeLine="Chow,
Edward\tchow\t454000000\t93\t33\t22\tA";
$array=split(/\t/,
$gradeLine);
print
"$array[0] your hw1 grade is $array[3]\n";
Regular Expression for pattern
matching
CGI
Debugging
CGI Scripts
-
When your CGI scripts contain
compiling errors or logic error, you will see messages from web servers
indicating
Internal
Server Error
The
server encountered an internal error or misconfiguration and was unable
to complete your request.
Please
contact the server administrator, root@localhost and inform them of the
time the error occurred, and anything you might have
done
that may have caused the error.
Premature
end of script headers: /users/server/students/www/cgi-bin/cs301/debugipaddr.pl
- To get more detail error message
for our CS Unix apache web servers, login in to the specific machine
and
-
cd /etc/httpd/logs
(it actually goes to /var/log/httpd. You will see access_log and
errro_log)
-
tail -f error_log
(-f mean follow up, new updates to log, will show up. tail shows
last par fo the file)
-
You may see something like the
following:
[Tue
Feb 22 11:26:52 2000] [error] [client 128.198.161.177] Premature end of
scr
ipt
headers: /users/server/students/www/cgi-bin/cs301/debugipaddr.pl
syntax
error at /users/server/students/www/cgi-bin/cs301/debugipaddr.pl line 7,
near
"@testdata ("
Execution
of /users/server/students/www/cgi-bin/cs301/debugipaddr.pl aborted due
to
compilation errors.
-
Note that the syntax error msg
may not show up on the error log until next error requests, due to buffering.
-
The above syntax error is exactly
the same error if you run the script standalone. You should get rid
of the syntax error by running your scripts standalone before, debugging
it through the web access.
Common Programming Mistakes:
- If you miss ending double ",
you will see
Can't find
string terminator '"' anywhere before EOF at debugipaddr.pl line 24.
- If at the beginning line you
spell the path to perl wrong, this is what you get
[Tue Feb 22
11:47:19 2000] [error] [client 128.198.161.177] Premature end of scr
ipt headers:
/users/server/students/www/cgi-bin/cs301/debugipaddr.pl
[Tue Feb 22
11:47:26 2000] [error] (2)No such file or directory: exec of /users/
server/students/www/cgi-bin/cs301/debugipaddr.pl
failed
- Forget to include "print header();"
which generates content type metaheader.
[Tue Feb
22 11:26:52 2000] [error] [client 128.198.161.177] Premature end of scr
ipt headers:
/users/server/students/www/cgi-bin/cs301/debugipaddr.pl
Common
but Tricky End-of-Line Problem when transfers cgi scripts from Window to Unix:
-----Original Message-----
From: CS301 Web Programming Mail List [mailto:cs301-l@uccs.edu] On Behalf Of
Edward Chow
Sent: Sunday, October 03, 2004 12:42 AM
To: CS301 Web Programming Mail List
Subject: [cs301-l]Re: CGI error
Heidi,
This is a tricky but common error!
If you use vi to edit your file, you will find at the bottom of the display
there is an indication of "dos" file.
If you ftp the catalog.cgi file from home PC, the dos file will contain additional
character at the end of each line.
I use the bigend program I wrote to display the byte content of your catalog.cgi
sanluis.uccs.edu> ~cs520/bin/bigend catalog.cgi
argv=catalog.cgi
LOC 0: 23 21 2f 75 73 72 2f 62 69 6e 2f 70 65 72 6c 0d
"#!/usr/bin/perl.p B"
LOC 16: 0a 0d 0a 75 73 65 20 43 47 49 20 71 77
28 3a 73 "...use CGI qw(:sp B
It shows after "perl" which is 70 65 72 6c in hexa decial, your dos
file has 0d 0a (carriage return, line feed) for
the end of line.
The next line is empty therefore we saw another 0d 0a follows.
If I switch to ~cs301/public_html/cgi-bin/catalog.cgi
sanluis.uccs.edu> ~cs520/bin/bigend catalog.cgi
argv=catalog.cgi
LOC 0: 23 21 2f 75 73 72 2f 62 69 6e 2f 70 65 72 6c 0a
"#!/usr/bin/perl.p B"
LOC 16: 75 73 65 20 43 47 49 20 71 77 28 3a 73 74 61 6e "use CGI qw(:stanp
B"
You will find there is only one 0a for representing the end of line, not 0d
0a. My catalog.cgi file is created on Unix machine.
The Window and Unix have different ways to representing the end of line.
Why this is causing the problem? Why the CGIWrap complains that it can not find
the file or the Perl interpreter?
The reason is that CGIWrap or the web server will treat the catalog.cgi as a
Unix file (since the web server is run on a Unix machine) and try to read the
first line. It finds the first two characters is #! and understand it needs
to find a shell program or a Perl interpreter. The file name of the shell or
the Perl interpreter is followed #! Until 0a (line feed). Since your dos catalog.cgi
has 0d (carriage return) before 0a. The cgiwrap will consider 0d as the last
character of the file name, when it tries to find /usr/bin/perl(0d) with 5 character
as its file name, it will not be able find any file there. The perl interpreter
in /usr/bin directory only has 4 characters as its file name.
The error message generated by CGIWrap actually is pretty good. It indicates
this could be caused by uploading file. But it says control-M was at the end
of the first line, instead of 0d for ascii code.
How can we fix the problem?
The best way is to start vi in binary mode and remove the 0d carriage return
character of your dos catalog file.
- vi -b catalog.cgi
here -b stands for starting vim editor in binary mode.
- You should see at end
of the first line after "perl" is a ^M character. The equivalent
of 0d character.
- Move your curser on
top of the ^M character and hit x to remove it.
- Save your file. It should
solve the problem.
One of the old way I used
is to
- Rename your catalog.cgi
as catalogDOS.cgi.
- On unix machine, create
a new file catalog.cgi
- Enter #!/usr/bin/perl
as the first line.
- Read in the content
of catalogDOS.cgi, in vi type the following editing command ":r catalogDOS.cgi"
- Delete the 2nd line
in the file which is #!/usr/bin/perl with 0d at the end.
- Save the file as catalog.cgi.
The CGIwrap error message
suggests change the ftp transfer mode from binary to ascii. But I found it does
not work. The od in the DOS end of line was not removed by ftp.
Edward
-----Original Message-----
From: Hparsaye@aol.com [mailto:Hparsaye@aol.com]
Sent: Saturday, October 02, 2004 9:51 PM
To: chow@cs.uccs.edu
Subject: Re: CGI error
Dr Chow,
I put -- at the end of the first line to see what is going to happen and make
sure perl will see my file, but with out it I get this error:
Thanks
CGIWrap encountered an error while attempting to execute this script:
Error Message: No such file or directory
Error Number: 2
This message usually indicates there is a problem with the script itself. Often
this indicates either that the #! line of the script is incorrect, or the script
was uploaded in binary mode instead of ascii mode. Check to make sure that the
script does not have control-M's at the end of every line. That will prevent
it from executing. An easy fix that takes care of this most of the time is to
put '#!/.../perl --' instead of '#!/.../perl' on the first line of the script.
This is typically a problem if the script was edited or uploaded from a DOS/Windows/Macintosh
station to a unix based server.
If you are not the owner of this script, please forward this error and the URL
that caused it to the script owner. That is often the component in the URL right
after /cgiwrap/.