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

I'm trying to write a program in Perl that will allow me to keep track of recipes. It is my way of practicing my Perl coding and at the same time creating something I could actually use. I've unfortunately run into a problem with the following code:
# if the HTML has not yet been displayed, display it if ($formdata{'mode'} eq "setup") { open (HTML, "<../add_whole_meal.html") || die &show_error("Unable +to open add_meal.html: $!"); unless ($content_type == 1) { print "Content-type: text/html\n\n"; $content_type = 1; } while(<HTML>) { $_ =~ s/\$(\w+)/$formdata{$1}/eg; $_ =~ s/\+_errors_\+//; print; } close(HTML); } elsif ($formdata{'mode'} eq "check") { # first make sure there is at least one item that has been entered if (($formdata{'name1'} eq "") && ($formdata{'name2'} eq "") && ( +$formdata{'name3'} eq "") && ($formdata{'name4'} eq "") && ($formdata +{'name5'} eq "")) { $error_message = $error_message . "<li>You must enter at least + one item </li>"; $flag = 1; } # check to see if a name was given, that all other sections are fi +lled in if (($formdata{'name1'} ne "") && (($formdata{'ingredients1'} eq " +") || ($formdata{'instructions1'} eq ""))) { $error_message = $error_message . "<li>Please be sure all requ +ired parts of item1 are filled in</li>"; $flag = 1; } # removed some of the repetitive code # check to make sure all numbers are actually numbers if (($formdata{'calories'} !~ m/\d*/) || ($formdata{'calories'} !~ + m/\d*/) || ($formdata{'calories'} !~ m/\d*/) || ($formdata{'calories +'} !~ m/\d*/)) { $error_message = $error_message . "<li>Please be sure all of t +he general information is in numeric form</li>"; $flag = 1; } # display error if needed and regenerate form if ($flag == 1) { open (HTML, "<../add_whole_meal.html") || die &show_error("Una +ble to open add_meal.html: $!"); unless ($content_type == 1) { print "Content-type: text/html\n\n"; $content_type = 1; } # setup the error message $error_message = "<font face=verdana color=#333333 size=2><cen +ter><b>Unfortunately there was an error!</b></center></font><ul><font + face=verdana color=red size=1>" . $error_message . "</font></ul>"; + # replace as needed and then reprint HTML while(<HTML>) { $_ =~ s/\$(\w+)/$formdata{$1}/eg; $_ =~ s/\+_errors_\+/$error_message/; print; } close(HTML); } }
Everything compiles. The hash %formdata contains all of the parameters sent to the script through the URL. This part I know is working correctly. The first part, when the program receives action=add_meal and mode=setup works perfectly fine. The script displays all of the necessary HTML, replacing whatever needs to be replaced in the static HTML beforehand. In the second part, I'm attempting to check all of the "necessary" fields and display an error message if things aren't correct. In the case of an error message, the HTML is regenerated with the user's previous information stored in the form fields. The script gets passed all of the tests and even shows the correct error message. The problem, however, is that the HTML doesn't finish being displayed. When I run the script with action=add_meal and mode=check, a small portion of the HTML page is displayed and then the script seems to stall. I hit ESC to stop the script and about half of the HTML page appears, but the rest is left out. Any clue as to why this happening?

Here is some of my sample HTML code, incase this will help:
<!-- Commented out to maintain perlmonks.org page <tr> <td bgcolor="#FFFFFF"><font face="verd +ana" color="#333333" size="1"><b>Name:</b><br> Please choose a name for this +portion of the meal. All names are case sensitive</font></td> <td bgcolor="#FFFFFF"><input type="tex +t" size="35" name="name2" value="$name2"></td> </tr> <tr> <td bgcolor="#FFFFFF"><font face="verd +ana" color="#333333" size="1"><b>Ingredients:</b><br> Please enter the ingredients n +eeded for this portion of the meal. Each ingredient should be sepera +ted by a comma.</font></td> <td bgcolor="#FFFFFF"><input type="tex +t" size="35" name="ingredients2" value="$ingredients2"></td> </tr> <tr> <td bgcolor="#FFFFFF"><font face="verd +ana" color="#333333" size="1"><b>Instructions</b><br> Please enter the cooking instr +uctions for this portion of the meal. Enter the instructions exactly + how you want them to be displayed.</font></td> <td bgcolor="#FFFFFF"><textarea size=" +20" name="instructions2" cols="40" rows="5">$instructions2</textarea> +</td> </tr> <tr> <td bgcolor="#FFFFFF"><font face="verd +ana" color="#333333" size="1"><b>Notes</b><br> Please enter any additional no +tes you have about this portion of the meal. Enter the instructions +exactly how you want them to be displayed. (optional)</font></td> <td bgcolor="#FFFFFF"><textarea size=" +20" name="notes2" cols="40" rows="5">$notes2</textarea></td> </tr> -->
Thanks in advance. -Eric

updated by boo_radley : title change, readmore

Replies are listed 'Best First'.
Re: anyone have an answer?
by dws (Chancellor) on Jun 05, 2002 at 20:46 UTC
    A suggestion and a hint:

    You're always going to be emitting   Content-type: text/html so do so at the top of the script. Scattering "have I done this yet" logic throughout the script makes for a needless mess. A good place is right after you unbuffer stdout by doing   $|++; Now, when you've got a failure in one particular case, comment the bulk of that case out, substituting   print "Test\n"; or whatever. Then gradually comment less and less of the code for that case out until you find out what's causing the breakage.

    This is a variant of another standard piece of debugging advice: Find the smallest fragment of code that demonstrates the problem. Often this exercise is sufficient to help you locate the problem. Doing this is a good habit to adopt.

Re: anyone have an answer?
by George_Sherston (Vicar) on Jun 05, 2002 at 21:13 UTC
    Soon some monks are going to say use CGI or die; - and they'll be quite right, because I think many of the things you are doing cd be done quicker that way (and probably more robustly: I'd hazard that whatever mechanism creates %formdata is not an improvement on CGI.pm's data parsing).

    I'd like to encourage you to use two other CPAN modules, however (and if you need encouragement to use modules in principle, I'd like to offer that too - the modest effort in learning to use them is immediately repaid; and in fact looking through the guts of a module is a great way to learn Perl from the best):

    1 CGI::Carp - will put lots of useful error messages onto your browser and help you find where your code is going wrong:
    use CGI qw/:standard/; # you already did this! use CGI::Carp qw(fatalsToBrowser warningsToBrowser); print header; # and now you have sent a print header warningsToBrowser(1);
    2 HTML::Template. As far as I see, you are opening an html file, then going through it making changes to it and sending the changed data to the browser. A templating module does much the same. But a well-thought-through templating module (I think HTML::Template is good'un - there are others) will do this in a way that
  • offers lots of features you will find useful
  • cleans up your code
  • doesn't break when you try to do something new
  • "hides information" - in the good sense of putting bits of your programme inside a box where you know they're doing their job but you don't have to bother about how they do it - leaving you more brainpower to do your stuff.

    Oh... also you are putting a -w after your #! /usr/bin/perl and following it with use strict; ... I presume. If not, the monastery will afford you many good arguments for why. The main one is: they help you catch your mistakes before they grow out of control.

    § George Sherston
Re: anyone have an answer?
by emilford (Friar) on Jun 05, 2002 at 20:42 UTC
    Okay, I've narrowed down the problem to the line
    $_ =~ s/\$(\w+)/$formdata{$1}/eg;
    I'm not exactly sure what the problem with this line is, seeing how it works at a previous occurence of the exact same line. When I comment out this line, however, the HTML is displayed in full, but none of the form field values are replaced. Does anyone see the mistake? ?????
      A guess: some value in %formdata has the same name as a key and starts with '$'.