How to check if a form variable is equal to something in Perl? - perl

I'm new to perl and I've mainly worked with php in the past,
usually to check if a get variable is equal to something and then do something else if it is, i'd simply do
if ($_GET['page'] == 'news') {
echo 'yessss';
}
but I'm not really sure what to do with perl :$ could anyone help me out? :)
Thanks!

In Perl, the module of CGI exists,
http://perldoc.perl.org/CGI.html#SYNOPSIS
and ->param gets an input parameter.
use CGI;
my $q = CGI->new;
print $q->header();
if ($q->param('page') eq 'news') {
print "...";
}

In perl you have different operators for checking string versus integer equality
"==" returns true if the left argument is numerically equal to the right argument.
"eq" returns true if the left argument is stringwise equal to the right argument.

Related

Changes in CGI.pm function param() behavior? [duplicate]

I am a little confused as which way to test parameters. Here are two examples from source code posted below. First is this
if(!defined($DBHdl) || !defined($acct_no));
the way to test for undefined parameters?
Second, after assigning to a hashref
$ptMtrRecRef = $ptSelHdl->fetchrow_hashref;
is the best way to test for $ptMtrRecRef being defined to use
if(!$ptMtrRecRef)
or
if(!defined($ptMtrRecRef))?
###############################################################################
# Returns count of meters per account number.
# $PkNam -- package name discarded
# $DBHdl -- ICS database handle
# $acct_no -- water account number
sub mgbl_get_meter_count
{
my ($PkNam, $DBHdl, $acct_no) = #_;
die("mgbl_get_meter_count passed undef handles.\n")
if(!defined($DBHdl) || !defined($acct_no));
my $ptSelHdl;
my $ptMtrRecRef;
my $sql_statement =
"select count(*) from meter m where m.acct_no = ".$acct_no.";";
$ptSelHdl = $DBHdl->prepare($sql_statement);
die("Cannot prepare select count(*) from meter m\n")
if(!$ptSelHdl || !$ptSelHdl->execute);
$ptMtrRecRef = $ptSelHdl->fetchrow_hashref;
return $ptMtrRecRef;
}
$sth->fetchrow_hashref will either return undef or a reference to a hash. As such
if (defined($row))
and
if ($row)
are equivalent here. (undef is false, and reference is always true.) I opt for the simpler alternative.
Same idea for $dbh->prepare.
In the case of the code you posted, I would also do as ikegami said, and use the shorter form.
There are occasions when that isn't suitable, however, for example if a variable could have a legitimate value that would be treated as false if simply used in a true/false test. For example:
my $value = 0;
print "defined\n" if defined $value; # prints 'defined'
print "true\n" if $value; # does not print anything
Well , in perl script language, defined($a) is just a sub routine to test if $a is "undef",nothing else. So ,you will ask ,what is undef?
To be accurate, it is a perl subroutine ,the same as defined.But when it has no parameter, it can be considered as a perl-special scalar . For example , when you pop a value from an empty array ,it will return an undef.When you call subroutine "undef $b",then $b will become undef($b must be an left value),nothing else. Only in this case, defined($b) will return false.But if $c is an empty string like "" ,number zero ,or string "0" ,defined($c) will still return true;
But if you use a simple boolean expression instead of defined,it becomes totally different. A simple Boolean test will not distinguish among undef, zero, the empty string, and "0" .So , it absolutely depends on your pratical requirement when determining using defined() or just a boolean test.

'=' is working in place of 'eq'

Hi I am writing a perl script to accomplish some task.In my script I am using one if loop to compare two strings as shown below.
if($feed_type eq "SE"){
...........}
The above code is not giving me any warning but the output is not as I expected.
Instead of 'eq' if I use '=' I am getting a warning saying expectng '==' but '=' is present. But I am getting the expected output.
Ideally for string comparison I must use 'eq' and for numbers '=='. In this case it's not working. Can anyone figure out what is the problem here?
More info:
This if loop is present in a subroutine. $feed_type is an input for this subroutine. I am reading the input as below:
my $feed_type=#_;
The problem is fixed. I just changed the assignemet statement of feed_type as below
my $feed_type=$_[0];
and it's reading the value as SE and the code is working.
but I still dont know why my $feed_type=$_[0]; didn't work.
= might well work in place of eq, but not for the reason you think.
#!/usr/bin/env perl
use strict;
use warnings;
my $test = "fish";
my $compare = "carrot";
if ( $test = $compare ) {
print "It worked\n";
}
Of course, the problem is - it'll always work, because you're testing the result of an assignment operation.*
* OK, sometimes assignment operations don't work - this is why some coding styles suggest testing if ( 2 == $result ) rather than the other way around.
This is about a core Perl concept: Context. Operators and functions work differently depending on context. In this case:
my $feed_type = #_;
You are assigning an array in scalar context to the variable. An array in scalar context returns its size, not the elements in it. For this assignment to work as you expect, you have to either directly access the scalar value you want, like you have suggested:
my $feed_type = $_[0];
...or you can put your variable in list context by adding parentheses:
my ($feed_type) = #_;
This has the benefit of allowing you to perform complex assignments, like this:
my ($first, $second, #rest) = #_;
So, in short, the problem was that your comparison that looked like this:
if($feed_type eq "SE")
Was actually doing this:
if(1 eq "SE")
And returning false. Which is true. Consider this self-documenting code:
sub foo {
my $size = #_;
if ($size == 1) {
warn "You passed 1 argument to 'foo'\n";
return;
}
}
Which demonstrates the functionality you inadvertently used.
= is used to assign the variable a value, so you would need '==' to compare numerical values and 'eq' for strings.
If it's complaining about not using '==', then it's because $feed_type is not a string.
I can't tell as there's no more code. Whatever $feed_type is set by you need to confirm it actually contains a string or if you're even referencing it correctly.

Why does this (mostly) empty Perl subroutine return an empty string?

Here is a Perl program:
use strict;
use warnings;
use Data::Dumper;
sub f {
foreach (()) { }
}
print Dumper(f());
This outputs:
$VAR1 = '';
Since no value is explicitly returned from f, and no expressions are evaluated inside it, shouldn't the result be undef? Where did the empty string come from?
It hasn't quite returned the empty string; it has returned "false", an internal Perl value (called PL_no). This false value is numerically zero but stringily empty. Data::Dumper can't represent it directly as PL_no and so chooses a representation which will work.
Other ways you can generate it:
$ perl -MData::Dumper -E 'say Dumper(1 eq 2)'
$VAR1 = '';
Since no value is explicitly returned from f, and no expressions are evaluated inside it, shouldn't the result be undef?
Nope. perldoc perlsub says the return value is unspecified:
If no return is found and if the last statement is an expression, its value is returned. If the last statement is a loop control structure like a foreach or a while, the returned value is unspecified.
"Unspecified" is short for "we're not going to document the exact behavior because we could change it at any time and you shouldn't rely on it." Right now, it returns PL_no as LeoNerd explained; in a future Perl version, it could return undef, or something else altogether.

Perl: If always returning true

I am just getting back into Perl programming so I appologize if this is an easy/stupid question.
My If statement is returning true (never going to the else) and I'm not really sure why. For example this code never prints "getshere":
#showName = ("Matt","Matt","Matt","Gym","Gym");
$counter=0;
foreach (#showName)
{
if ($showName[$counter]==$showName[$counter+1])
{
print "$showName[$counter] equ $showName[$counter+1]\n";
}
else
{
print "getshere";
}
$counter++;
}
Can you please tell me what I am doing wrong?
Thank you!
== is numeric comparison, and strings like 'Matt' and 'Gym' all have the numeric value 0, so they're all == to each other. For string comparison, use eq instead:
if ($showName[$counter] eq $showName[$counter+1])
(I recommend enabling warnings, by the way, by adding use warnings; near the start of your script. Had you done that, you would have received a helpful message warning you that you were applying a numeric equality-test to non-numeric values.)
The == operator converts strings to numbers and does numeric comparison. To compare strings, use eq. To test if strings are greater or less than eachother, use cmp.
if ($showName[$counter] eq $showName[$counter+1])

Perl thinks all strings are equal

Edit: I did try using eq instead of == earlier, and it did not work. For some reason now it does. It's possible that there was another error at that point which prevented it from working, but now this has been resolved. Thank you.
I'm trying to do some simple validation. I want to make sure the redirect url being fed through a variable begins with a particular site or not. If it does, the redirect goes through, if not, it redirects to the root of the site. Seems pretty straight forward, right?
$redir = $input{'redirect'};
$redir_sub = substr($redir, 0, 21);
if ($redir_sub == "http://www.mysite.com") {
print "Location: $redir \n\n";
}else{
print "Location: http://www.mysite.com \n\n";
}
The thing is, no matter what variable I place in there, it the "if" returns as true. I could put my favorite webcomic in there and it'll redirect to it, despite the string not matching. For example this:
$redir = $input{'redirect'};
$redir_sub = "http://www.yahoo.com"
if ($redir_sub == "http://www.mysite.com") {
print "Location: $redir_sub \n\n";
}else{
print "Location: http://www.mysite.com \n\n";
}
That redirects to yahoo! What is going on?
if ($redir_sub == "http://www.mysite.com")
should be
if ($redir_sub eq "http://www.mysite.com")
as eq is string equality operator, and using == forces number comparison so in this case condition always evaluates to trues as 0 == 0 is true.
Operator == is used to compare numbers. You should replace it with operator eq
TL;DR: use eq not ==!
Perl as a language seems to have a problem: It uses the same data type (the scalar) for a lot of different things, including strings and numbers. A scalar is both at the same time, not just one of those. Perl has no type annotations, and there is no way to indicate if a variable holds a string or a number.
This produces problems when we consider equality tests. Assuming two scalars $a = "42.0" and $b = 42. Are they equal? Yes and no:
The strings "42" and "42.0" are not the same thing! These are not equal.
The numbers 42 and 42.0 are equal!
As indicated above, Perl does not use a type system to solve this ambiguity. Rather, it uses different sets of operators for string and numeric operations:
eq ne lt le gt ge cmp
== != < <= > >= <=>
Your problem is that you are not using
use warnings;
Which is why Perl is allowing you to make this mistake. You are using the numeric equality operator to compare strings. Hence, Perl first tries to convert each parameter to a number. And since your strings do not begin with numbers (and do not look like numbers), they are converted to zero 0. Hence your expression
if ($redir_sub == "http://www.mysite.com")
Really means this
if (0 == 0)
Which of course always returns true.
If you had been using warnings, you would have gotten the errors:
Argument "http..." isn't numeric in numeric eq (==) at ...
Argument "http..." isn't numeric in numeric eq (==) at ...
Which would have been a hint as to your problem that you should be using eq and not == to compare strings.
== does numeric comparison. eq does string comparison. When you use a string as a number, perl passes your string through your c library's aton(). So you're really asking your computer if 0 == 0 which is true.