Search code examples
perlcgi

just can't get perl working as expected ( conditionals and variable declaring )


EDIT:

I will try a better explication this time, this is the exact code from my script.

#use warnings;
#use Data::Dumper;
open(my $tmp_file, ">>", "/tmp/some_bad.log") or die "Can not open log file: $!\n";
#if( $id_client != "")
@allowed_locations = ();
#print $tmp_file "Before the if: ". Data::Dumper->Dump([\@allowed_locations, $id_client]) . "";
if( $id_client )
{
#    print $tmp_file "Start the if: ". Data::Dumper->Dump([\@allowed_locations, $id_client]) . "";
#    my $q = "select distinct id_location from locations inner join address using (id_db5_address) inner join zona_rural_detaliat using (id_city) where id_client=$id_client";
#    my $st =  &sql_special_transaction($sql_local_host, $sql_local_database, $sql_local_root, $sql_local_root_password, $q);
#    print $tmp_file "Before the while loop: ref(st)='". ref($st) . "\n";
#    while((my $id)=$st->fetchrow())
#    {
#       print $tmp_file "Row the while loop: ". Data::Dumper->Dump([$id])  . "";
#       my $id = 12121212;
#       push(@allowed_locations, $id);
#    }
#    print $tmp_file "After the while loop: ref(st)='". ref($st) . "\n";
#    my($a) = 1;
#} else {
#    my($a) = 0;    
}
#print $tmp_file "After the if: ". Data::Dumper->Dump([\@allowed_locations, $id_client]) . "";
close($tmp_file) or die "Can not close file: $!\n";
#&html_error(@allowed_locations);

First off all, somebody said that I should try to run it in command line, the script works fine in command line (no warnings, It was uncommented then), but when triyng to load in via apache in the browser it fails, please see this video where I captured the script behavior, what I tried to show in the video:

I have opened 2 tabs the first doesn't define the variable $id_client, the second defines the variable $id_client that is read from GET: ?id_client=36124 => $id_client = 36124; , both of them include the library in the video "locallib.pl"

  1. When running the script with all the new code commented the page loads
  2. when uncoment the line that defines the @allowed_locations = (); the script fails
  3. leave this definition and uncoment the if block, and the definition of my $a; in the if block; Now the script works fine when $id_client is defined, but fails when $id_client is not defined
  4. Uncoment the else block and the definition of my $a; in the else block. Now the script works fine with or without $id_client
  5. now comment all the my $a; definisions and comment the else block, the script fails
  6. but if I'm using open() to open a file before the IF, and close() to close it after the if it does't fail even if the IF block is empty and event if there is no else block

I have replicated all the steps when running the script in the command line, and the script worked after each step.
I know it sounds like something that cannot be the behavior of the script, but please watch the video (2 minutes), maybe you will notice something that I'm doing wrong there.

Using perl version:

[root@db]# perl -v
This is perl, v5.8.6 built for i386-linux-thread-mult

Somebody asked if I don't have a test server, answer: NO, my company has a production server that has multiple purposes, not only the web interface, and I cannot risk to update the kernel or the perl version, and cannot risk instaling any debuger, as the company owners say: "If it works, leave it alone", and for them the solution with my ($a); is perfect beacause it works, I'm asking here just for me, to learn more about perl, and to understand what is going wrong and what can I do better next time.

EDIT: I had success starting the error logging, and found this in the error log after each step that resulted in a failure I got this messages:
[Thu Jul 15 14:29:19 2010] [error] locallib.pl did not return a true value at /var/www/html/rdsdb4/cgi-bin/clients/quicksearch.cgi line 2.
[Thu Jul 15 14:29:19 2010] [error] Premature end of script headers: quicksearch.cgi

What I found is that this code is at the end of the main code in the locallib.pl after this there are sub definitions, and locallib.pl is a library not a program file, so it's last statement must returns true. , a simple 1; statement at the end of the library ensures that (I put it after sub definitions to ensure that noobody writes code in the main after the 1;) and the problem was fixed.
Don't know why in CLI it had no problem ...


Solution

    1. You need to explicitly check for definedness.

      If you want to enter the loop when $client is defined, use if ( defined $client ).

      If you want to enter the loop when $client is defined and a valid integer, use if ( defined $client && $client =~ /^-?\d+$/ ). I assume it's an integer from the context, if it can be a float, the regex needs to be enhanced - there's a standard Perl library containing pre-canned regexes, including ones to match floats. If you require a non-negative int, drop -? from regex's start.

      If you want to enter the loop when $client is defined and a non-zero (and assuming it shouldn't ever be an empty string), use if ( $client ).

      If you want to enter the loop when $client is defined and a valid non-zero int, use if ( $client && $client =~ /^-?\d+$/ ).

    2. Your @ids is "undef" when if condition is false, which may break the code later on if it relies on @ids being an array. Since you didn't actually specify how the script breaks without an else, this is the most likely cause.

    Please see if this version works (use whichever "if" condition from above you need, I picked the last one as it appears to match the closest witrh the original code's intent - only enter for non-zero integers):

    UPDATED CODE WITH DEBUGGING

    use Data::Dumper;
    open(my $tmp_file, ">", "/tmp/some_bad.log") or die "Can not open log file: $!\n";
    @ids = (); # Do this first so @ids is always an array, even for non-client!
    print $tmp_file "Before the if: ". Data::Dumper->Dump([\@ids, $client]) . "\n";
    if ( $client && $client =~ /^-?\d+$/ ) # First expression catches undef and zero
    {
        print $tmp_file "Start the if: ". Data::Dumper->Dump([\@ids, $client]) . "\n";
        my $st = &sql_query("select id from table where client=$client");
        print $tmp_file "Before the while loop: ref(st)='". ref($st) . "'\n";
        while(my $row = $st->fetchrow())
        {
           print $tmp_file "Row the while loop: ". Data::Dumper->Dump([row])  . "'\n";
           push(@ids, $row->[0]);
        }
        print $tmp_file "After the while loop: ref(st)='". ref($st) . "'\n";
        # No need to undef since both variables are lexically in this block only
    }
    print $tmp_file "After the if\n";
    close($tmp_file) or die "Can not close file: $!\n";