RE: Good Intro reading



Dave Adams <mailto:davidlamontadams@xxxxxxxxx> wrote:

I urge all readers *not* to use this site. Just don't visit it.
I won't even quote the url. If you want to learn about perl and
CGI visit Ovid's course at
http://users.easystreet.com/ovid/cgi_course/index.html.


: Being a junior perl programmer, I read a lot of docs and I came
: across a really good site that is well written and structured.
: If you are just starting out, I would highly recommend it.

No. This is an outdated tutorial. It was written between 1999
and 2001. The Author fails to emphasize the use of lexical
variables, strictures, and warnings.

The CGI section is impressive, but apparently omits taint
checking and again leaves out strict and warnings. Here's an
example which teaches several poor lessons. (I added the line
numbers.)

1: #!/usr/local/bin/perl
2: use CGI;
3:
4: $cgiobject=new CGI;
5:
6: print $cgiobject->header;
7:
8: #read in template page
9: $templateFile="smallville.html";
10: open(INFILE,"<$templateFile");
11: @templatePage=<INFILE>;
12: close(INFILE);
13:
14: #condense page array into one scalar variable
15: $resultPage=join("",@templatePage);
16:
17: #determine current date
18: ($sec,$min,$hour,$mday,
19: $mon,$year,$wday,$yday,$isdst)=localtime(time);
20: $curDay=(Sunday,Monday,Tuesday,Wednesday,
21: Thursday,Friday,Saturday)[$wday];
22: $curMonth=(January,February,March,April,
23: May,June,July,August,September,
24: October,November,December)[$mon];
25: $liveDate="$curDay, $curMonth $mday, ".($year+1900);
26:
27: #search-and-replace on date
28: $resultPage=~s/INSERT DATE HERE/$liveDate/g;
29:
30: #done, output page to browser
31: print $resultPage;

The author is obviously used to writing without strictures.
That date routine (lines 17-25) is very telling. Those are
barewords in lines 20 through 24. They're not wrapped by the
qw() operator.

Note the lack of error checking in I/O operations (lines 10
and 12), the use of double quotes when single quotes will do
(lines 9 and 15), and the lack of white space to improve
readability (though he does use good leading white space).

Note the inconsistency in the variable naming convention. Line
4 uses "$cgiobject" as a variable name while the mixed case
($cgiObject) seems to be the convention.

Many of these items may seem very minor mistakes. One mistake
is okay, but after six years, this should be a near perfect perl
guide.

Here's an untested, insecure rewrite. It requires a previous
introduction CGI security would be needed. Like this one:
http://users.easystreet.com/ovid/cgi_course/lessons/lesson_three.html

1: #!/usr/bin/perl -T
2:
3: use strict;
4: use warnings;
5:
6: use POSIX 'strftime';
7: use CGI::Carp qw(fatalsToBrowser);
8: use CGI;
9:
10: # Read template page.
11: my $file = 'smallville.html';
12: open my $fh, '<', $file or die qq(Cannot open "$file": $!);
13: my $template = do { local $/; <$fh> };
14: close $fh or die qq(Cannot close "$file": $!);
15:
16: # Current date.
17: my $date = strftime '%A, %B %d, %Y', localtime;
18:
19: # Search and replace fields.
20: $template =~ s/INSERT DATE HERE/$date/g;
21:
22: # Output page to browser.
23: my $cgi = CGI->new();
24: print $cgi->header(), $template;
25:
26: __END__

I prefer strftime() for dates because it is a fairly common
routine. In fact, the guide I used to write this format was
written for PHP.


Let's take a look at some typically bad subroutines (the
arbitrary line numbers are mine). We can see by line 3 that the
idea of getting return values from a subroutine is not foreign to
this script's author. Yet he consistently operates on external
variables in every subroutine in his script. Worse, there are
other examples in these pages where the author *does* use
lexically scoped variables. He even insists on it later on.

1: sub build_a_pizza()
2: #build the pizza form using old "build-a-pizza" script
3: { @allparams=$cgiobject->param();
4: if ($#allparams>-1)
5: {&get_state_variables}
6: else
7: {&init}
8:
9: if ($orderComplete)
10: { &complete_order }
11: else
12: { &build_order }
13: }
.
.
.
56: sub init()
57: #define initial values for pizza parameters
58: { $name="Your name";
59: $address="Where to?";
60: $phone="Your phone";
61: $deliver="deliver";
62: $toppings="pepperoni";
63: $size="large";
64: }
65:
66: sub get_state_variables()
67: #grab any parameters which were submitted
68: { $name=$cgiobject->param("order_name");
69: $address=$cgiobject->param("order_address");
70: $phone=$cgiobject->param("order_phone");
71: $deliver=$cgiobject->param("order_deliver");
72: $toppings=$cgiobject->param("order_toppings");
73: $size=$cgiobject->param("order_size");
74: $newOrderFlag=$cgiobject->param("newOrderFlag");
75: $orderComplete=$cgiobject->param("finish")
76: }


We can assume that the author just doesn't know better. But
only if we stop reading. Later the author agrees that
subroutine values *should* always be passed in and out. Here's
an excerpt.

<quote>
Along these lines, one generally wants to avoid global
variables, and subroutines tend to work on variables within
their own little mental space. Thus, we typically pass values
into subroutines - the values they need to know - and
subroutines can return values back to the calling expressions.
You scratch their back, they scratch yours.
.
.
.
sub mySub {
my ($value,$list,$hash)=@_;
...etc...
}
</quote>

This portion was written in March, 2001. The author has known
of these techniques for more than four years. So the author of
this particular perl guide should either pull it off the web or
rewrite it. I urge all readers *not* to use this site. Just don't
visit it.


HTH,

Charles K. Clarkson
--
Mobile Homes Specialist
254 968-8328

.