koacamper has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I am working on a redirection script that will allow the an administrator to enter a specific name with url link into a database. So, it would saved like this:
$name\|$url


The problem that I am running into is on the users side. I want to use a <input type=text value=name>,not a drop-down menu. Here's the problem, when a $name is entered in the box, that is not in the database, I get a "file not found" . I'm trying to figure out how to set up the script so that if the $name is invalid they get a preset error message.

Here's the script I'm working with:
#!/usr/bin/perl $datafile = "/home/sites/www.yourname.com/users/web/mysites.txt"; ############ THE ACTUAL PROGRAM ############ &parse; &incomplete unless $FORM{'name'}; $name = "$FORM{'name'}"; &findurl; &doit; ############ SUBROUTINES ############ sub doit { print ("Location: $url\n"); print ("Content-type: text/html\n\n"); } ############ FIND URL ############ sub findurl { open (INFO, "$datafile"); @information = <INFO>; foreach $information (@information) { ($title, $location) = split(/\|/ , $information); { if ($title eq $name) { $url = $location; } } } close (INFO); } ############ PARSE ############ sub parse { read(STDIN, $input, $ENV{'CONTENT_LENGTH'}); $input = $ENV{'QUERY_STRING'} if $ENV{'QUERY_STRING'}; @pairs = split(/&/, $input); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } } sub incomplete { print "Content-type: text/html\n\n "; print <<"HTML"; <HTML><HEAD><TITLE>Incomplete</TITLE></HEAD> <BODY bgcolor=white> <H1>Form not complete</H1> <p> <hr noshade size=1> <p> Sorry, you forgot to enter something. <a href=\"$ENV{'HTTP_REFERER'}\">You should go back and try again</a>. </BODY> </HTML> HTML exit; }
Any help would be greatly appreciated

Replies are listed 'Best First'.
Re: Error 404 fix
by chromatic (Archbishop) on Sep 30, 2000 at 20:28 UTC
    Simple fix. You have an if check in your findurl subroutine. Don't set a global variable $url, but return it. Something like this:
    sub findurl { my $url; open (INFO, $datafile) or die "Can't open $datafile: $!"; while (<INFO>) { my ($title, $location) = split(/\|/ , $_); if ($title eq $name) { $url = $location; } } close (INFO); return $url; }
    That means you'll have to call it slightly differently:
    my $url = findurl(); if (defined $url) { doit(); } else { incomplete(); }
    I'd try to get rid of the global variables as far as possible, passing $name as an argument to findurl(), and $url as an argument to doit().

    As for general coding advice, you ought to look into using the -w flag and strict. In CGI scripts, you should also use -T for taint checking (see perlsec), and there's usually no good reason not to use CGI instead of your parse subroutine. Yours doesn't handle checkboxes, for example.

    Don't worry, these things will help you in the long run.

      chromatic,
      Thank you for your answer to my question concerning my question. I am very new to perl and am trying to learn as quickly as possible. I've looked through the list of books and was wondering what book would you suggest for someone as "Green" as me?
      Thanks again,
      koa
      i want to learn
(Ovid) Re: Error 404 fix
by Ovid (Cardinal) on Sep 30, 2000 at 21:01 UTC
    As a follow up to some other answers, here is your script rewritten (but untested and not production quality) to use CGI.pm, with security added and comments:
    #!/usr/bin/perl -wT use strict; use CGI; my $query = new CGI; my $datafile = "/home/sites/www.yourname.com/users/web/mysites.txt"; use vars qw($title $location $name $url); ############ THE ACTUAL PROGRAM ############ # regex should only allow characters that you # know are acceptable. In this case a-z, A-Z, _, 0-9 # The way we're assigning $1 to $name is called "taint checking" if ($query->param('name') =~ /^(\w+)$/) { $name = $1; } else { # If we got here, there were illegal characters entered (or no cha +racter) &incomplete; } $url = &findurl; if ($url) { # Send 'em where they want to go print $query->redirect($url); } else { # No url, so do something different } ############ FIND URL ############ sub findurl { # always check the return calls on an open open INFO, "<$datafile" or die "Can't open $datafile: $!"; my @information = <INFO>; foreach (@information) { ($title, $location) = split /\|/; } if ($title eq $name) { $url = $location; } close (INFO); return $url; } sub incomplete { print $query->header, $query->start_html(-title => "Incomplete", -bgcolor => "white"), $query->h1("Form not complete"), $query->p(), $query->hr(), $query->p("Sorry, you forgot to enter something."), $query->p("Please hit the back button on your browser and tr +y again."), $query->end_html; exit; }
    Note that in the &incomplete sub, we no longer print the HTTP_REFERER. Some Web servers will execute a server side include that's generated from a CGI (though I understand that this isn't common). If that happens, someone could easily spoof the REFERER variable to be an SSI and enter a bogus name. Then, when the &incomplete subroutine prints it out, it will execute whatever the SSI is. Something like <!--#exec cmd="rm -fr /"--> will delete all of the files on the server that your Web server would have the rights to delete (I am assuming that it's a *nix box, and I might have the actual syntax slightly off).

    Please see CGI.pm and perlsec for more information on these issues.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

Re: Error 404 fix
by clemburg (Curate) on Sep 30, 2000 at 20:51 UTC

    First of all, learn to use use strict;, and how to return values from your subroutines. All this global data flying around will hurt you again and again, especially without use strict;.

    And my god, you are parsing the CGI stuff yourself. Big no no. Use the CGI module (see perldoc CGI).

    As for your problem: why not set $url to a standard location containing your error message in findurl() before entering the loop over your data:

    sub findurl { open (INFO, "$datafile"); @information = <INFO>; $url = "http://mysite/error_message.html"; foreach $information (@information) { ($title, $location) = split(/\|/ , $information); { if ($title eq $name) { $url = $location; } } } close (INFO); }

    And please, Fellow Clueful Monks, do not kill me for giving an answer to a request like this.

    And for you poor soul that asked this question: get a decent book on Perl programming, quick, quick, run to the next bookstore, don't walk, and buy "Learning Perl" or something similar. See Tom Christiansen's book review list for other book suggestions. No no, don't tell me you can't afford that (if that is really the case, start with perldoc perlfaq and read through the online-docs). May the spirit finally come upon you.

    Christian Lemburg
    Brainbench MVP for Perl
    http://www.brainbench.com