Loading ...
Sorry, an error occurred while loading the content.

Re: [PBML] A better way (long) [was:Reading from and writing to a file on a Linux machine]

Expand Messages
  • Don Smith
    Charles, Once again, I thank you for the lesson. Sometimes I feel like I m walking through thick mud. I m addicted to this message board but what I m learning
    Message 1 of 1 , Jan 1, 2002
    • 0 Attachment
      Charles,

      Once again, I thank you for the lesson. Sometimes I feel like I'm walking
      through thick mud. I'm addicted to this message board but what I'm learning
      is how much I don't know. I appreciate the time you take to educate rather
      than just answer a question.

      Take care my friend.

      Don



      ----- Original Message -----
      From: "Charles K. Clarkson" <cclarkson@...>
      To: <perl-beginner@yahoogroups.com>
      Sent: Tuesday, January 01, 2002 6:06 AM
      Subject: [PBML] A better way (long) [was:Reading from and writing to a file
      on a Linux machine]


      > "Don Smith" wished:
      >
      > : Oh well, the script works so maybe someone new to
      > : perl can benefit from it and perhaps someone more
      > : experienced can show us a better way.
      >
      > Be careful what you wish for!
      >
      > : The script :
      > : 1) takes a user input from an HTML file ($direcn)
      > : 2) Opens "listing.dat" which lists all the directory names
      > : 3) Checks to see if the directory name is in the list.
      > : 4) If it is, it prints the "Already in use" error message
      > : and makes $test = 1.
      > : 5) If it isn't found, it closes the file.
      > : 6) The file Listing.dat is reopenned to be written to.
      > : 7) The directory name is added to the bottom of the list.
      > : 8) The file is then closed.
      > : 9) The directory is then created.
      > : 10) "OK" and the directory are printed to the browser.
      >
      > I edited Don's script for clarity. Mainly, I lined up
      > some of the comments and added some spacing. I did change
      > the order of some statements to illustrate a point or two.
      > If you read this in a monospaced font, like 'Courier New',
      > it may look less cluttered. The unedited version is at:
      > <http://groups.yahoo.com/group/perl-beginner/message/7991>
      >
      > : #!/usr/bin/perl -w
      > :
      > : use lib '/CGI.pm';
      > : use CGI::Carp 'fatalsToBrowser';
      > :
      > : use CGI qw/:standard/;
      > :
      > : $CGI::POST_MAX=1024 * 10; # max 10K posts - security
      > : $CGI::DISABLE_UPLOADS = 1; # no uploads - security
      > :
      >
      > perl modules come in 2 flavors. Object oriented and
      > function oriented. The push seems to be toward objects,
      > but functions are usually faster. In order to use the
      > function oriented interface, we have to import the
      > functions. The standard functions can be imported with
      > ':standard'.
      >
      > How many functions are in :standard? 140.
      >
      > Actually, it's 139. Tr and TR are the same sub.
      > Curiously enough we don't use any of them in this script.
      > It's like writing a 2000 line script and only using 20
      > lines to process the request.
      >
      > : my $foo = new CGI;
      >
      > In order to use the object oriented interface to
      > CGI.pm, we need only create a new object, as above. The
      > entire CGI.pm file is still read into memory, but no
      > subroutines are imported into our namespace.
      >
      > It is generally considered a 'good' habit to either
      > use the object or the function oriented interface, but
      > never both.
      >
      > : # Reads directory name from input form.
      > : my $direcn = $foo->param('direcn');
      >
      > Here we get the param passed to this script using
      > the $foo object. As a function we might have used:
      >
      > my $direcn = param('direcn');
      >
      > Either way, we should make certain something was
      > passed:
      >
      > die 'Incorrect Parameters' unless param('direcn');
      > or:
      > die 'Incorrect Parameters' unless $foo->param('direcn');
      >
      > CGI::Carp 'fatalsToBrowser' will handle this.
      >
      > : use strict; # Use only the variables in the
      > : # script - security
      >
      > I usually place this as the second line of *every*
      > script.
      >
      > : print "Content-type: text/html\n\n"; # Required - It could cause
      > : # a "500 server error" if
      > : # left out on the linux
      > : # machine.
      >
      > It's required by HTTP. The standard specifies an
      > Entity-header and an Entity-body. If you view the
      > source of a browser window (connected to a site), you
      > see the Entity-body. The head was received by the
      > browser and used to help render the page.
      >
      > You can read the spec at:
      > <ftp://ftp.isi.edu/in-notes/rfc2616.txt>
      > Check out chapter 7 (it's really suspenseful.)
      >
      > A blank line is used to separate the header from the
      > rest. That's why Content-type ends with: \n\n.
      >
      > :standard imported a function to handle this:
      >
      > print header;
      >
      > And we could use the $foo object:
      >
      > print $foo->header;
      >
      > Version 2.752 of CGI.pm prints:
      >
      > Content-Type: text/html; charset=ISO-8859-1
      >
      >
      > : # Change Path - linux format shown. Use full path on Windows.
      > : my $path = "/hdd/3/web/test/public_html";
      >
      > I get real picky about double quotes. It's more a
      > matter of style. I just hate to use double quotes on
      > a string that doesn't need interpolating:
      >
      > my $path = '/hdd/3/web/test/public_html';
      >
      > or, using a quote-like operator:
      >
      > my $path = q|/hdd/3/web/test/public_html|;
      >
      > : my $dir = "$path/$direcn"; # Do not change this
      >
      > I think I would have waited till later to do this.
      >
      > : my $filename = "$path/listing.dat";
      > : my ($test);
      > :
      > : open (FILEHANDLE, "<$filename") || die "Cannot open $filename.";
      > : while (<FILEHANDLE>) {
      > :
      > : # goto next line unless we get a match
      > : chomp $direcn;
      >
      > This shouldn't be necessary. $direcn was received via a
      > form and shouldn't have a newline character in it.
      >
      > : next unless /\b$direcn\b/i;
      >
      > The o option on the match will speed things up here.
      > Basically it tells perl $direcn is the same each time
      > /\b$direcn\b/ is proccessed. See perlre for more details.
      >
      > next unless /\b$direcn\b/io;
      >
      > : print "Content-type: text/html\n\n";
      >
      > We only need this once.
      >
      > : if ($direcn ne ""){
      >
      > Since $direcn isn't changing, we only need to check
      > this once. Inside the while block, we are checking it
      > on each pass. Imagine a listing.dat file with 20,000
      > entries.
      >
      > : print "<BR><BR><BR><BR><Center><H1>Sorry,
      > : the directory name \"" .
      > : $direcn . "\" is in use.</H1><BR>
      > : <H2>Please click your browser's back
      > : button and enter another directory
      > : name.</H2></Center>" ;
      >
      > Remember those 140 functions that were imported?
      > Three of them are above. <center> is not part of
      > the :standard import.
      >
      > Assuming we used: use CGI qw/:standard center/;
      > or: use CGI qw/param br h1 h2 center header/;
      >
      > print
      > br, br, br, br,
      > center(
      > h1(qq|Sorry, the directory name "$direcn" is in use.),
      > br,
      > h2( q|Please click your browser's back button|,
      > q|and enter another directory name.| )
      > );
      >
      > : $test = "1";
      >
      > Use numbers as numbers and strings as strings. Let perl
      > sort'em out:
      >
      > $test = 1;
      >
      > : }
      > : }
      > :
      > : close FILEHANDLE;
      > : if ($test ne "1"){
      > : open (FILEHANDLE2, ">>$filename")|| die "Cannot open $filename.";
      > :
      > : print FILEHANDLE2 "$direcn\n";
      > : close FILEHANDLE2;
      > : }
      > :
      > : mkdir ($dir,0777); #The 0777 is the chmod. It can be
      > : changed later.
      > :
      > : print "OK <BR><BR>";
      > : print $dir;
      >
      >
      > Before we continue, Let's take another look at our code
      > using the function oriented style. I changed some variable
      > names (to protect the innocent):
      >
      > use CGI qw/:standard center/;
      > use CGI::Carp 'fatalsToBrowser'; # send errors to the browser
      > $CGI::POST_MAX = 1024 * 10; # max 10K posts - security
      > $CGI::DISABLE_UPLOADS = 1; # no uploads - security
      >
      > # this really needs its own subroutine and nice message
      > die q|Incorrect Parameters| unless param('direcn');
      >
      > # Reads directory name from input form.
      > my $dir_name = param('direcn');
      >
      > # Change Path - linux format shown.
      > # Use full path on Windows.
      > my $path = q|/hdd/3/web/test/public_html|;
      > my $file_name = qq|$path/listing.dat|;
      >
      > my $test;
      > open FH, $file_name or die qq|Cannot open $filename: $!|;
      > while (<FH>) {
      > # goto next line unless we get a match
      > next unless /\b$dir_name\b/io;
      > print
      > br, br, br, br,
      > center(
      > h1(qq|Sorry, the directory name "$dir_name" is in use.|),
      > br,
      > h2( q|Please click your browser's back button|,
      > q|and enter another directory name.| )
      > );
      > $test = 1;
      > }
      > close FH;
      >
      > Personally, I don't like having all that stuff in the
      > while. This is a style issue, not a programming issue. That's
      > one problem with reviewing code. Some items are not wrong or
      > less efficient. They're just not the reviewer's style. I'd
      > rather separate the print from the while and close that file
      > ASAP.
      > I prefer a subroutine (or function):
      >
      > sub valid_directory {
      > # Reads directory name from input form.
      > my ($dir_name, $file_name) = @_;
      >
      > open FH, $file_name or die qq|Cannot open $file_name: $!|;
      > while (<FH>) {
      > # return 'undef' if we get a match
      > return if /\b$dir_name\b/io;
      > }
      > close FH;
      >
      > # directory name is valid - return it.
      > return $dir_name;
      > }
      >
      > We can use this fuction as:
      >
      > my $dir_name = valid_directory( param('direcn'), $file_name );
      >
      > If $dir_name is taken it will be defined undef.
      > Otherwise it will be defined by the directory name.
      > Also, the sub stops checking as soon as it finds a
      > match. The previous inline routine did not.
      >
      > Let's take another look:
      >
      > use CGI qw/:standard center/;
      > use CGI::Carp 'fatalsToBrowser'; # send errors to the browser
      > $CGI::POST_MAX = 1024 * 10; # max 10K posts - security
      > $CGI::DISABLE_UPLOADS = 1; # no uploads - security
      >
      > # Change Path - linux format shown.
      > # Use full path on Windows.
      > my $path = q|/hdd/3/web/test/public_html|;
      > my $file_name = qq|$path/listing.dat|;
      >
      > die q|Incorrect Parameters| unless param('direcn');
      >
      > my $dir_name = valid_directory( param('direcn') );
      >
      > if ( defined $dir_name ) {
      >
      > open FH, qq|>>$filename| or
      > die qq|Cannot open $filename: $!|;
      > print FH qq|$dir_name\n|;
      > close FH;
      > mkdir ("$path/$dir_name", 0777);
      > print
      > header, start_html(q|Invalid Directory|),
      > q|OK|, br, br, $dir,
      > end_html;
      >
      >
      > } else {
      > $dir_name = param('direcn');
      > print
      > header, start_html(q|Invalid Directory|),
      > br, br, br, br, center(
      > h1( qq|Sorry, the directory name "$dir_name" is in use.| ),
      > br, h2( q|Please click your browser's back button|,
      > q|and enter another directory name.| ) ),
      > end_html;
      > }
      >
      > sub valid_directory {
      > # Reads directory name from input form.
      > my ($dir_name, $file_name) = @_;
      >
      > open FH, $file_name or die qq|Cannot open $file_name: $!|;
      > while (<FH>) {
      > # return 'undef' if we get a match
      > return if /\b$dir_name\b/io;
      > }
      > close FH;
      >
      > # directory name is valid - return it.
      > return $dir_name;
      > }
      >
      > __END__
      >
      >
      >
      > HTH,
      > Charles K. Clarkson
      > Clarkson Energy Homes, Inc.
      > 254 968-8328
      >
      >
      > All generalizations are bad.
      > - R. H. Grenier
      >
      >
      >
      >
      >
      > Unsubscribing info is here:
      http://help.yahoo.com/help/us/groups/groups-32.html
      >
      > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
      >
      >


      ---
      Outgoing mail is certified Virus Free.
      Checked by AVG anti-virus system (http://www.grisoft.com).
      Version: 6.0.312 / Virus Database: 173 - Release Date: 12/31/01
    Your message has been successfully submitted and would be delivered to recipients shortly.