Can't call method "id" on an undefined value - perl

recently my hosting company updated their servers, and i believe my code's inefficiency is being brought to light.
i have this code:
#!/usr/bin/perl
use CGI qw(:standard);
use CGI::Session;
$cgi = new CGI;
$sid = $cgi->cookie("CGISESSID") || undef;
$session = new CGI::Session(undef, $sid, {Directory=>'/tmp'});
$cookie = $cgi->cookie(CGISESSID => $session->id);
$sSid = $session->id();
print $cgi->header(-cookie=>$cookie);
print << "EOF";
HTML CODE
EOF
this was fine until (it seems) the update - now i'm getting this error in my logs:
Can't call method "id" on an undefined value at /home/users/web/XXXX/my-file.cgi line 10.
i then edited this into line 10:
$cookie = $cgi->cookie(CGISESSID => $session->id) || undef;
figuring that it would take care of the issue, but it didn't.
it seems to be causing a brief 500 server error, and then the site comes back online, with the session id persisting through the error.
i'm completely lost as to what is happening. what's worse is it isn't happening every time the page loads - it seems so random but i'm sure i'm just not encountering the specific situation to bring that error.
i've been using the same setup for all my cgi's for the past 7 years. not sure why it's causing a brief error now, but that's besides the point.

$session is undef, so that means new returned undef. The docs have the following to say about that:
Returns new session object, or undef on failure. Error message is accessible through errstr() - class method.
So call CGI::Session->errstr to find out what the problem is.

Related

Why is my perl Catalyst redirect_and_detach replacement plugin method failing?

Looking for help figuring out a stumping error.
I've created a perl Catalyst plugin that's intended to provide a drop-in replacement method for Catalyst 5.90115's redirect_and_detach ($c->redirect_and_detach). My replacement method does nothing but call Catalyst's redirect_and_detach:
package MyApp::Catalyst::Plugin::Logger;
...
sub my_redirect_and_detach {
my ($c, $uri, $status) = #_;
$c->redirect_and_detach($uri, $status);
}
I realize this adds no value, I'm just testing to make this simple case work first.
Then I replace this working call ...
$c->redirect_and_detach($someuri);
with this call to my new plugin method ...
$c->my_redirect_and_detach($someuri);
And I get the following (abbreviated/obfuscated) error:
Parameter #2 (undef) to Catalyst::Plugin::RedirectAndDetach::redirect_and_detach was an 'undef', which is not one of the allowed types: scalar
at /usr/local/share/perl/5.26.1/Catalyst/Plugin/RedirectAndDetach.pm line 18.
Catalyst::Plugin::RedirectAndDetach::redirect_and_detach(undef, "/myuri", undef) called at /var/app/lib/MyApp/Catalyst/Plugin/Logger.pm line 95
MyApp::Catalyst::Plugin::Logger::my_redirect_and_detach(MyApp=HASH(0x5628f93e4e60), "/myuri") called at ...
I understand the Catalyst method spec requires parameter #2 to be defined. But I don't understand why the stacktrace shows undef for the first argument (thought that would be $c's class/package). I verified $c is successfully passed as first argument, and works inside my_redirect_and_detatch() to pull request parameters.
Anyone see the issue?
Thanks in advance.
Turns out Catalyst's redirect_and_attach(), while $status defaults to undef if not supplied, does not like an actual undef $status parameter. Solution is to avoid passing $status if it's undef.

Perl-Mechanize posting hidden form value

I am attempting to create a perl script to test a web form for me. I am using mechanize for the automation and am having trouble finding documentation on the the field method. I am using the field method to return the value of a hidden form and this is causing my post to fail. The problem is probably a simple oversight but I am curious about $mech->field('name'); as it seems to be returning the hidden form's value for me.
Using perl v5.16.3 (w & w/o warnings)
$id = $test->field('MId');
print $id . " \n";
#This is printing the desired Id ,
#the post will not succeed as long as $id assigned this way.
print "This is where I am attempting to upload the images\n";
my $fileuploadresult;
$fileuploadresult = $mech->post($uploadURL,
'Content_Type' => "multipart/form-data",
'Content' => [
'myFile' => $file , 'MId' => $id
]
);
print $fileuploadresult->content() . "\n\n\n"; #If I set $id to something like 'test' it
#will work fine.
#I am using two agent because there are two POST's going on and they have to be sequential.
I was wondering why my submit failed when I grabbed the value of a form. I just changed the 'field' method to 'value' and realized this fixed my problem. Sorry noob question didn't look at the documentation enough. When field returned the value I assumed that was part of its functionality I did not realize it also set the value to null. (Or as far as I can tell that is what its doing)

perl log db query errors into a log file

So I started to get familiar with Perl and I wrote my first Db script.
Now I am trying to select data from atable which is huge and trying to insert into a summary table based on some criteria.
Now there are chances , that select query may fail or the insert query may fail due to timeout or other database issues that is beyond my control.
Eventually my script is going to be cron script.
Can I log just the errors that i encounter for the connection,inserts and selects into a file generated in the script?
$logfile = $path.'logs/$currdate.log';
here is my code:
my $SQL_handled="SELECT division_id,region_id, NVL(COUNT(*),0) FROM super_tab GROUP BY division_id,region_id;";
my $result_handled = $dbh->prepare($SQL_handled);
$result_handled->execute();
while (my ($division_id,$region_id,$count ) = $result_handled->fetchrow_array()){
my $InsertHandled="INSERT INTO summary_tab (date_hour, division_id, region_id,volume) VALUES ('$current',$division_id,$region_id,$market_id,'$service_type','$handled',$count);";
my $result_insert_handled = $dbh->prepare($InsertHandled);
$result_insert_handled->execute();
}
something like
if(DBI-query failed ) {
// log the error onto the above logpath
}
Its usually done like this
my $SQL_handled="SELECT division_id,region_id, NVL(COUNT(*),0) FROM super_tab GROUP BY division_id,region_id;";
my $result_handled = $dbh->prepare($SQL_handled);
my $retval = $result_handled->execute();
if(!$retval){
#open a log file and write errors
writelog();
die "Error executing SQL SELECT - $dbh->errstr";
}
while(my ($division_id,$region_id,$count ) = $result_handled->fetchrow_array()){....
}
---------------------------------
sub writelog{
my $path = "/path/to/logfile";
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
$mon++;
my $currdate = "$mon$mday$year";
$logfile = $path . "/$currdate.log";
open (OUT, ">>$logfile");
print OUT "There was an error encountered while executing SQL- $dbh->errstr \n";
close(OUT);
}
You can also use $dbh->err; which returns the native Oracle error code to trap the error and exit accordingly.
The above, basic exception handling can be performed for every execute() method call in your script. Remember, DBI will have AutoCommit set to 1 (enabled) by default, unless explicitly disabled. So your transactions would be auto committed per insert, in order to handle the ATOMICITY of the entire transaction, you can disable autocommit and use $dbh->commit and $dbh->rollback to handle when you want to commit, or may be use some custom commit point (for larger sets of data).
Or the below can be used while connecting to the DB
$dbh = DBI->connect( "dbi:Oracle:abcdef", "username", "password" , {
PrintError => 0, ### Don't report errors via warn( )
RaiseError => 1 ### Do report errors via die( )
} );
this would automatically report all errors via die. The RaiseError is usually turned off by default.
Also if I understand you correctly then, by cron you mean you would be calling it from a shell cron job. In that case, call to your perl script from the cron itself can be redirected to log files something like below
perl your_perl.pl >> out.log 2>> err.log
out.log will contain regular logs and err.log will contain errors (specifically thrown by DBI prepare() or execute() methods too). In this case, you also need to make sure you use proper verbiage in print or die so that the logs look meaningful.
First, bear in mind that if you put an email address at the top of your crontab file any output from the cron job will be emailed to you:
MAILTO=me#mydomain.com
Second, if you set DBI's RaiseError to 1 when you connect you do not need to check every call, DBI will raise an error whenever one happens.
Third, DBI has an error handler callback. You register a handler and it is called whenever an error occurs with the handle in error and error text etc. If you return false from the error handler, DBI works as it would without the handler and goes on to die or warn. As a result, it is easier to set RaiseError and create an error handler than as Annjawn suggested.
Lastly, if you don't want to do this yourself, you can use something like DBIx::Log4perl and simply ask for it to log errors and nothing else. Any errors will be written to your Log4perl file and they include the SQL being executed, parameters etc.

Can't get Extended SNMP output in Perl

I have written a Perl script to put back some SNMP values, which works fine. I have now written a script on the remote server and used the extend function in SNMP to put the value from the script into SNMP.
If I run:
snmpget -v2c -c public 10.0.0.10 'NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."cc_power"'
I get the result:
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."cc_power" = STRING: 544
But when I try to use my script to get the information back it doesn't get it. Here is the script:
#!/usr/bin/perl
use strict;
use SNMP;
use RRDs;
my $rrd_db = "/storage/db/rrd/cc_power.rrd";
my $sess;
my $val;
my $error;
$sess = new SNMP::Session(DestHost => "10.0.0.10", Community => "public", Version => 2);
my $power = $sess->get('NET-SNMP-EXTEND-MIB::nsExtendOutput1Line.\"cc_power\"');
$error=RRDs::error;
die "ERROR while updating RRD: $error\n" if $error;
my $date=time;
print "Data Script has been run - Output: ${date}:${power}\n";
but nothing is returned, and I have no idea why... no errors or anything, have I missed something stupid?
Hope someone can help as this is driving me nuts :)
I assume that you used netsnmp snmpget. Well, it hides too many details from you, as it loads MIB documents in background and nicely translate OIDs and SNMP values to all kinds of user friendly formats.
So next time pay attention to what decoration it performs and simulate that in your own code to achieve the same effects.

Problems with Perl Mechanize and Proxies

I've been frustrating myself with this for way too many hours. I think this should be simple but I obviously have something fundamental wrong. I've read:
I've read the cpan docs for :
WWW-Mechanize/lib/WWW/Mechanize/FAQ.pod
libwww-perl-5.837/lib/LWP/UserAgent.pm
And every bit of sample code or article I could find on Google.
This is my first time looking for help on Stack Overflow. Thanks for your help in advance. Here is the code:
#!/usr/bin/perl
use WWW::Mechanize;
my $mech = WWW::Mechanize->new ( agent => "Mozilla/5.0" );
my $proxy = 'http://fetch4.me';
$mech->no_proxy('localhost');
$mech->proxy(['http', 'https', 'gopher'], $proxy) or die $!;
$mech->get('http://www.google.com');
print $mech->uri(),"\n";
print $mech->content(),"\n";
print $mech->text(),"\n";
print $mech->status(),"\n";
Here is the output:
http://www.google.com
<html>Apache is functioning normally</html>
Apache is functioning normally
200
I'm running out of ideas here. Does this code work for you? Does it produce the same results? What's wrong with it? >.<
Thank you for your time.
The problem seems to be in the server fetch4.me. Try, for instance, instead
my $proxy = 'http://124.207.162.87:80';
Does saying:
my $mech = WWW::Mechanize->new ( agent => "Mozilla/5.0", noproxy => 1 );
help?
The doc implies you need to do that to avoid an implicit call to LWP's env_proxy.