Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Variable being saved as a list?

by fiona (Initiate)
on Aug 06, 2014 at 18:03 UTC ( [id://1096487]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all, I am very new to Perl and am trying to update a pretty old shopping cart script to be able to show the info for estimating shipping. I have it almost all working the way I want but for some reason one of my variable when its updated instead of replacing the value it appends the new value on the end and comma separates. The code is identical to that used for another variable and that seems to function fine. I have included what are hopefully the relevant code sections below. Any input would be appreciated. Thanks
print "To estimate shipping please enter shipping country to generate +information for Fedex calulations then click estimate shipping to ope +n Fedex Estimator :<br> \n"; print "<input name=shipcountry value=$shipcountry>\n"; print "<input type=submit value=\"Show Shipping Info\"><br>\n"; open (REFFILE,"$reffile") || print "Content-type: text/html\n\n Can't +Open $reffile(r): $!\n"; my(@LINES)=<REFFILE>; close(REFFILE); $SIZE=@LINES; open (REFFILE,">$reffile") || print "Content-type: text/html\n\n Can't + Open $reffile(r): $!\n"; print REFFILE "$date\| $ENV{'REMOTE_HOST'}\| $ENV{'HTTP_USER_AGENT'}\| +$FORM{'discnt'}\|$FORM{'shipcountry'}\|\n";

Replies are listed 'Best First'.
Re: Variable being saved as a list?
by Anonymous Monk on Aug 06, 2014 at 18:13 UTC

    There seems to be nothing in that piece of code that obviously relates to the problem you describe. Also you haven't told us the name of the variable you have a problem with, the name of the variable that works, and what values they're supposed to contain vs. what they actually contain. Could you post the code that shows how those variables are set and used?

    Another thing that would help both us and you in debugging is if you can reduce the code with the problem down to a small, self-contained example that reproduces the problem.

    More tips in How do I post a question effectively?

      Sorry, as I said I am new to this. The variable I am having a problem with is $shipcountry, the variable $discnt works fine. I am trying to update $shipcountry via a form. It starts as "none" and I want it to change to whatever country is entered but what I end up with is, for example, "none, United States, Canada, United States" the number in the list depends on how many times you try and submit a change. I am not sure how I can make a self contained example but I will try.
        Sorry, as I said I am new to this.

        No problem, we're here to help. Pages such as "How do I post a question effectively?" are there to help people asking questions help the people answering them (despite their sometimes slightly patronizing titles).

        I suspect the problem actually lies with the code that sets $shipcountry in your script. Are you using some kind of library to handle the input from the form? If so, I'd also look there for how it handles $shipcountry and why it might be appending the values.

        A note on terminology for the future: A "list" in Perl is actually not what you've got with $shipcountry, that's a scalar (a single value) that contains a string (which happens to contain commas).

Re: Variable being saved as a list?
by Bloodnok (Vicar) on Aug 06, 2014 at 18:47 UTC
    Hiya fiona , Welcome to the monastry.

    my(@LINES)=<REFFILE>; doesn't look right, you tried my @LINES = <REFFILE>; ?

    Also, open (REFFILE,">$reffile") || print "Content-type: text/html\n\n Can't Open $reffile(r): $!\n"; appears to be wrong since, even if open() fails, the next line still tries to write to it - try open (REFFILE,">$reffile") || die "Content-type: text/html\n\n Can't Open $reffile(r): $!\n";

    A user level that continues to overstate my experience :-))

      die goes to STDERR unless set up specially otherwise. So that ostensibly HTML error goes nowhere but server error logs, if even there; again by setup.

        My point being, Your Mother, that the open failure could and indeed should, be better handled since if open() fails, the error log will get extended by the subsequent write failures.

        A user level that continues to overstate my experience :-))
      my(@LINES)=<REFFILE>; doesn't look right, you tried my @LINES = <REFFILE>; ?

      In this case it's the same thing.

      $ perl -MO=Deparse -e 'my @LINES=<REFFILE>; my(@LINES)=<REFFILE>;' my(@LINES) = <REFFILE>; my(@LINES) = <REFFILE>;

      The parens would make a difference if the thing on the left wasn't an array, and the thing on the right behaved differently in scalar and list context. In that case the parens would cause the thing on the right to be in list context. For example my $x = @foo; assigns the length of @foo to $x (scalar context), while my ($x) = @foo; assigns the first item of @foo to $x (list context). It's what makes sub { my ($arg0,$arg1,$arg2,@rest) = @_; ... } work.

Re: Variable being saved as a list?
by tangent (Parson) on Aug 06, 2014 at 20:53 UTC
    Can you show the code that creates the %FORM hash. My guess is that you have another field within your form that is also called 'shipcountry', perhaps a hidden field, that is populated with the previous value each time the form is submitted.
Re: Variable being saved as a list?
by Monk::Thomas (Friar) on Aug 07, 2014 at 10:23 UTC
    Just some code cleanup recommendations.

    original code:

    open (REFFILE,"$reffile") || print "Content-type: text/html\n\n Can't +Open $reffile(r): $!\n"; my(@LINES)=<REFFILE>; close(REFFILE); $SIZE=@LINES; open (REFFILE,">$reffile") || print "Content-type: text/html\n\n Can't + Open $reffile(r): $!\n"; print REFFILE "$date\| $ENV{'REMOTE_HOST'}\| $ENV{'HTTP_USER_AGENT'}\| +$FORM{'discnt'}\|$FORM{'shipcountry'}\|\n";

    Step 1 - DO IT!

    At the very least please do not use the 2 argument form of open. It ~might~ be safe if you have that variable under your control but maybe at some point you decide it would be a nice feature for the user to be able to specify the file name and then you're in trouble. Your application may be tricked into setting '$reffile' to '>file', '<file', '-|file' or any other 'interesting' file modes. Use the 3 argument form, explicitely state the file mode and stop worrying.
    my $htmlheader = "Content-type: text/html\n\n"; open (REFFILE, '<', $reffile) || print "$htmlheader Can't Open $reffil +e(r): $!\n"; [...] open (REFFILE, '>', $reffile) || print "$htmlheader Can't Open $reffil +e(r): $!\n";
    Check the return value of print and close. Both may fail!
    close(REFFILE) || print "$htmlheader Can't close filehandle for $reffile(r): $!\n"; [...] print (REFFILE "$date\| $ENV{'REMOTE_HOST'}\| $ENV{'HTTP_USER_AGENT'}\ +|$FORM{'discnt'}\|$FORM{'shipcountry'}\|\n") || "$htmlheader Can't write to $reffile(r): $!\n";

    Step 2 - Recommended

    Use 'or' instead of '||'. Both are 'logical or', but 'or' has a very low precedence allowing you to remove the parenthesis:
    my $htmlheader = "Content-type: text/html\n\n"; open REFFILE, '<', $reffile or print "$htmlheader Can't Open $reffile(r): $!\n"; my(@LINES)=<REFFILE>; close REFFILE or print "$htmlheader Can't close filehandle for $reffile(r): $!\n"; $SIZE=@LINES; open REFFILE, '>', $reffile or print "$htmlheader Can't Open $reffile(r): $!\n"; print REFFILE "$date\| $ENV{'REMOTE_HOST'}\| $ENV{'HTTP_USER_AGENT'}\| +$FORM{'discnt'}\|$FORM{'shipcountry'}\|\n" or "$htmlheader Can't write to $reffile(r): $!\n";;

    Step 3 - Suggested

    Use lexical variables (e.g. $fh_read, $fh_write) as filehandles. This is a precaution against name conflicts. You may accidentally define/import a function with the same name as one of your filehandles. Have fun debugging that. Lexical filehandles are safe and easy to use. Do yourself a favour and use them.

    Additional suggestion: brace file handles '{fh}' when writing to them. It doesn't matter to perl, but it makes the difference between printing a variable and writing to a file handle more obvious.

    my $htmlheader = "Content-type: text/html\n\n"; open my $fh_read, '<', $reffile or print "$htmlheader Can't Open $reffile(r): $!\n"; my(@LINES)=<$fh_read>; close $fh_read or print "$htmlheader Can't close filehandle for $reffile(r): $!\n"; $SIZE=@LINES; open $fh_write, '>', $reffile or print "$htmlheader Can't Open $reffile(r): $!\n"; print {$fh_write} "$date\| $ENV{'REMOTE_HOST'}\| $ENV{'HTTP_USER_AGENT +'}\|$FORM{'discnt'}\|$FORM{'shipcountry'}\|\n" or "$htmlheader Can't write to $reffile(r): $!\n";

    more DO IT!

    Since you are writing environment variables to your file you should definitely verify their content. At the very least $ENV{'HTTP_USER_AGENT'}, $FORM{'discnt'} and $FORM{'shipcountry'} must be seen as containing something dangerous unless proven otherwise. Simply trusting the user provided data is likely to lead to data corruption sooner or later.

    example scrubber for 'shipcountry'

    my $shipcountry; # shipcountry may contain letters, digits, underscores, spaces and das +hes # and nothing else if ($FORM{'shipcountry'} =~ /^([\w -]+)$/) { $shipcountry = $1; } else { print "$htmlheader Invalid input for shipping country detected!\n"; } print {$fh_write} "$date\| $ENV{'REMOTE_HOST'}\| $ENV{'HTTP_USER_AGENT +'}\|$FORM{'discnt'}\|$shipcountry\|\n" or "$htmlheader Can't write to $reffile(r): $!\n";

      Another important change is to control flow logic and code organization

      open ... or die Error(...);

      open ... or return ErrorPage(...);

      If you can't open the file, don't try to read from it or write to it, end the subroutine (the code should be in subroutines

      Don't generate your pages by interleaving print statements, make subroutines, so your program is

      Main( @ARGV ); exit( 0 ); sub Main { my $q = CGI->new; print SomeKindOfPages( $q ); } sub SomeKindOfPages { my( $q ) = @_; ... my( $headers, $body ) = ShippingEstimator( $q , ... ); return $headers, $body; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1096487]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-25 23:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found