tags:

views:

247

answers:

5

EDIT:

I will try a better explication this time, this is the exact code from my script (sorry for all them coments, they are a result of your sugestions, and apear in the video below).

#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.

Thank you.

P.S. hope this new approach will restore some of my -1 :)

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 ...

Maybe I will get a lot of down votes now ( be gentle :) ) , but what can I do ...and I hope that some newbies will read this and learn something from my mistake.

Thank you all for your help.

+2  A: 

Note: this answer was deleted because I consider that this is not a real question. I am undeleting it to save other people repeating this.

Instead of

if( $client != "" )

try

if ($client)

Also, Perl debugging is easier if you

 use warnings;
 use strict;
Kinopiko
if($client) and if($client != "") is the same and does't solve the 3 issues ( just tried again with both of them ).
Radu
@Radu: `if ($client)` and `if ($client != "")` aren't the same. The first one will not proceed if `$client` is undefined or equal to zero.
Kinopiko
Also, if you're comparing a string use `ne` or `eq`
Htbaa
Additionally, if you want to check its length use `length()`
Htbaa
$client if defined is numeric, and if i'm using if($client) without the else I get the same result (the script fails when $client is not defined), tried $client = "" unless defined $client; I get the same result.
Radu
@Radu, did you try `use warnings;` and `use strict;`?
Kinopiko
for strict read the comment I left to @darrenmambo, for warnings ...how to use them, I put "use warnings;" in the script, but where they are printed ? I just get an "Internal Server Error" and nothing is printed in the httpd logs. Hope that it doesn't need a reconfiguration and restart to apache ( I cannot stop the intranet not even for 5 seconds ) :)
Radu
@Radu: you are just being ridiculous.
Kinopiko
@Radu - don't you have, like, a UAT or DEV or TEST web server??? I probably don't want to know the answer :)
DVK
@DVK or a command line or something. stackoverflow.com is turning into a bad joke.
Kinopiko
@Radu => just because your library is not running under `use strict;` doesn't mean that your code can't be...
Eric Strom
@Eric Strom => You gat that wright@DVK => Just one server, edited the original question, more details there.@Kinopiko => I am sorry if I'm being ridiculous, hope you will understand more from the video, in the command line, the script works just fine, in the web browser it doesn't.
Radu
+3  A: 

hi when checking against a string, == and != should be respectively 'eq' or 'ne'

if( $client != "" )

should be

if( $client ne "" )

Otherwise you don't get what you're expecting to get.

kaklon
$client when defined is numeric.
Radu
But you're testing it against an empty string. DVK probably has your answer.
kaklon
A: 

Oh my... Try this as an example instead...

# Move the logic into a subroutine
# Forward definition so perl knows func exists
sub getClientIds($);       

# Call subroutine to find id's - defined later.
my @ids_from_database = &getClientIds("Joe Smith");

# If sub returned an empty list () then variable will be false.
# Otherwise, print each ID we found.

if (@ids_from_database) {
    foreach my $i (@ids_from_database) {
        print "Found ID $i \n";
    }
} else {
    print "Found nothing! \n";
}

# This is the end of the "main" code - now we define the logic.

# Here's the real work    
sub getClientIds($) {
    my $client = shift @_;       # assign first parameter to var $client
    my @ids    = ();             # what we will return

    # ensure we weren't called with &getClientIds("") or something...
    if (not $client) {
        print "I really need you to give me a parameter...\n";
        return @ids;
    }

    # I'm assuming the query is string based, so probably need to put it 
    # inside \"quotes\"
    my $st = &sql_query("select id from table where client=\"$client\"");

    # Did sql_query() fail?
    if (not $st) {
        print "Oops someone made a problem in the SQL...\n";
        return @ids;
    }

    my @result;

    # Returns a list, so putting it in a list and then pulling the first element
    # in two steps instead of one.
    while (@result = $st->fetchrow()) {
        push @ids, $result[0];
    }

    # Always a good idea to clean up once you're done.
    $st->finish();

    return @ids;
}

To your specific questions:

  1. If you want to test if $client is defined, you want "if ( eval { defined $client; } )", but that's almost certainly NOT what you're looking for! It's far easier to ensure $client has some definition early in the program (e.g. $client = "";). Also note Kaklon's answer about the difference between ne and !=
  2. if (X) { stuff } else { } is not valid perl. You could do: if (X) { stuff } else { 1; } but that's kind of begging the question, because the real issue is the test of the variable, not an else clause.
  3. Sorry, no clue on that - I think the problem's elsewhere.

I also echo Kinopiko in recommending you add "use strict;" at the start of your program. That means that any $variable @that %you use has to be pre-defined as "my $varable; my @that; my %you;" It may seem like more work, but it's less work than trying to deal with undefined versus defined variables in code. It's a good habit to get into.

Note that my variables only live within the squiggliez in which they are defined (there's implicit squiggliez around the whole file:

my $x = 1;
if ($x == 1) 
{
    my $x = 2;
    print "$x \n";    # prints 2. This is NOT the same $x as was set to 1 above.
}
print "$x \n";        # prints 1, because the $x in the squiggliez is gone.
I will try your sugestion, use strict; is something that cannot be done beacause I'm adding this code to an old library (about 12 years old and not very well writen) that my company uses, and I will need to recode almost everiting to compile with strict :) I'm using PHP in my daily web scripts, but I need extend the perl library as well to add a new feature to the intranet.
Radu
mikegrb
mirod
2. Perl does not care about an empty else clause. `perl -e 'if (1) { print "stuff\n" } else { }'` causes no error.
cHao
1. `eval` here is overkill. `if (defined $client)` should work fine.
cHao
+4  A: 
  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";
DVK
strange as it seems, this does not work. Without the else when $client is not defined it breaks (Internal Server Error),and if client is defined it breaks, i put again in the if a variable declaration my $someVariableName=1; and now when client is defined it works. I realy don't understand why, but this is the only way it works. How to find out the exact error/problem, i have "use warnings;" but nothing is printed to the screen,and nothing in the http logs. Can i personalize the error handling to use my own sub to print to a specific file(I usualy write in PHP,and errors are send to http log)?
Radu
@Radu - it sort of depends on what web server you are running, but either CGI or mod_perl under Apache write standard error into Apache's error log
DVK
@Radu - one way to troubleshoot this is to try to print debugging checkpoints to an explicitly opened temp file from the library: use `File::Temp` or just open a file "/tmp/whatever.mine", and sprincle `print $tmp_filehandle "Checkpoing #N"` statements before the if, after the if, inside, etc..., and add contents of `Data::Dumper->Dump([])` to the print statements as appropriate to see contents of the variables
DVK
@Radu - see the updated code with sample prints
DVK
+3  A: 

Always begin your script with :

use warnings;
use strict;

these will give you usefull informations.

Then you could write :

my @ids;

if (defined $client) {
    @ids = (); # not necessary if you run this part only once
    my $st = sql_query("select id from table where client=$client");
    while( my ($id) = $st->fetchrow ) {
       push @ids, $id;
    }
} else {
    warn '$client not defined';
}

if (@ids) {  # Your query returned something
    # do stuff with @ids
} else {
    warn "client '$client' does not exist in database";
}
M42
To the OP (not M42): And quit debugging in the browser, and quit exposing yourself to bobby tables attacks (http://bobby-tables.com/)
runrig
@runrig => previosly in the library where we read the GET form HTML and define the variables we check against an array of allowed variables and there type, so id_client is checkd to be an INTEGER, if is NOT an INTEGER the script return an warning to the user, and stop execution. I think the solution is ok, if you don't please leave some arguments why is not a good solution, thank you.
Radu