Session data not being updated by script using that session - perl

Thinking I have narrowed down the issue, here is a better question.
My script, 'index', opens an existing session - because a session does exist from when it was created by a login script.
It does correctly use values from that session in the page output so evidently, it's accessing the session from either memory or the server's sessions_storage dir.
The script is written so as to add two values to the session but, that's not actually happening. And this is where it gets annoyingly frustrating.
After running the script, I check the session file in filezilla. Those two values do not exist. However, if I output a dump of the session, at the bottom of my script, the two values show in that output.
If I delete the session from my browser and then reload the page, those two values and a few others are showing in the new session file but, of course, the other values stored from previous files (eg login) are missing.
This I have worked out thus far:-
All other files (from login thru to this 'index') are creating and/or storing and retrieving to/from the session without issue.
'Index' script is not adding to the existing session file.
New session forced by deleting session cookie from browser shows the data is being stored as expected in the correct server dir.
Using flush(); at the end of my script (or anywhere after session creation/loading); has made no difference.
Can any of you with fresh eyes tell me what's (not) going on?
my $sessions_dir_location = '/' . $var . '/' . $www . '/' . $vhosts . '/' . $domain . '/name_of_sessions_storage_dir/';
my $session = new CGI::Session(undef, $cgi, {Directory=>"$sessions_dir_location"}) or die CGI::Session->errstr;
my $session_id = $session->id();
$session->flush();
my %vars = $cgi-Vars;
my $business_id = $vars{'business_id'};
print qq(<pre>bid=$business_id</pre>); #successful
$session->param('business_id', $business_id); #unsuccessful
print qq(<pre>session_id = $session_id); #successful
print $session->dump; # shows the business_id value as being stored.
print qq(</pre>);

The following works for me, it increases the session parameter business_id by one for each call:
use strict;
use warnings;
use CGI;
use CGI::Session;
my $cgi = CGI->new();
my $sessions_dir_location = "/tmp/sessions";
# Data Source Name, defaults to "driver:file;serializer:default;id:md5"
my $dsn = undef;
# new() : returns new session object, or undef on failure. Error message is
# accessible through errstr() - class method.
my $session = CGI::Session->new(
$dsn, $cgi, {Directory=>"$sessions_dir_location"}) or die CGI::Session->errstr();
my %vars = $cgi->Vars;
my $cgi_bsid = $vars{business_id};
my $session_bsid = $session->param("business_id");
my $new_bsid = $cgi_bsid // $session_bsid // 0;
$new_bsid++;
$session->param('business_id', $new_bsid);
$session->flush() or die CGI::Session->errstr();
# CGI::Session will use this cookie to identify the user at his/her next request
# and will be able to load his/her previously stored session data.
print $session->header();
my $session_id = $session->id();
print $cgi->start_html();
print join "<br>",
qq(session_id=$session_id),
qq(cgi_bsid=$cgi_bsid),
qq(session_bsid=$session_bsid),
qq(new_id=$new_bsid);
print $cgi->end_html();

Related

Get a list of all Oracle data sources via DBI

I'm creating a perl program where the user has to enter the name of a database, in addition to a username and password, and the program connects to that database using DBI->connect. What I'd like to do is to have the program present a list of names of databases that it can connect to, and all the user has to do is input their username and password, for ease of use. I took a look at the DBI documentation for data sources, thinking it was what I need but when I call DBI->data_sources('Oracle') it doesn't return anything (but no errors are encountered either). I don't see how this can happen, as the program is able to connect without any hitches if the user supplies the database name. Is there something that I'm doing wrong, or something that I'm not getting?
And yes, I realize I can just manually open the tnsnames.ora file and parse that. In fact, that's what I did first but I'd like to use DBI preferably.
Try this:
#!/usr/bin/perl -w
use DBI;
my #drivers = DBI->available_drivers();
die "No drivers found!\n" unless #drivers; # should never happen
foreach my $driver ( #drivers ) {
print "Driver: $driver\n";
my #dataSources = DBI->data_sources( $driver );
foreach my $dataSource ( #dataSources ) {
print "\tData Source is $dataSource\n";
}
print "\n";
}

RequestTracker and Mason destroying my class over and over again

I'm hacking on Request Tracker, which is written in perl and uses Mason
for the web interface. I'm trying to make a customized page, that involves an autohandler, an html page, and pulls in some methods in other comps. I have a simple class that I want to use to track a few things that I need for my parts of the interface. Right now all it
tracks is a database handle.
package RTx::FooBar::Web;
use strict;
use warnings;
use RTx::FooBar::Handle;
sub new
{
my $proto = shift;
$RT::Logger->debug("creating new");
my $class = ref($proto) || $proto;
my $self = {};
bless( $self, $class);
my $handle = RTx::FooBar::Handle->new();
$handle->Connect();
$self->{cfHandle} = $handle;
return $self;
}
sub DESTROY {
my $self = shift;
$RT::Logger->debug("destroy");
delete $self->{cfHandle};
}
sub CFHandle
{
my $self = shift;
return $self->{cfHandle};
}
1;
I tried sticking that into the session so I could use it wherever I needed
it in the web interface. So I try to use it in one web page - the autohandler does:
% $m->call_next;
<%INIT>
$RT::Logger->debug("my autohandler");
use RTx::FooBar::Web;
$session{cfWeb} ||= RTx::FooBar::Web->new();
</%INIT>
The thing that's bugging me right now (other than the fact that it's not
working) is that the logging in the "new" method prints out once, but the
logging in the DESTROY method prints out 56 times. And each time, the
debug in RTx::FooBar::Handle->DESTROY prints out as well, indicating that
$self->{cfHandle} wasn't removed. Can anybody suggest why this might be
happening? Is it because session is a tied hash?
*Update* I'm no longer using $session, and it's STILL destroying my handle 56 times after creating it once.
Just a guess here - $session is re-creating your objects from an externalized version (perhaps via Storable or the like). So it gets the object back without calling new so no logging. Not sure why it would be getting destroyed every time tho.
It looks like $session is in fact a tied hash, to an Apache::Session or something implementing the same interface (the docs talk about db backing for sessions).
If you want to have a global persistent object (i.e., not tied to a single request) then give it a fully-qualified name, e.g., $RTx::FooBar::Web::TheObject ||= RTx::FooBar::Web->new(); or use something like Cache::MemoryCache. Alternately, set up your own global variable in the MasonAllowGlobals setting, although you might need to get into RT's config files to change that.

Connecting to multiple databases in a perl script

How can I connect to multiple databases in perl without it bailing out if it can't connect to one? If I have the database names in an array and go trough them in a loop, I want to try and connect and perform a query and disconnect. I am going to report it back to the big brother server monitoring page we have. I don't want the script to terminate if it can't connect to one, since it obviously needs to check every one in the array. Right now i use the DBI modules state method but I don't know that it works correctly. Thanks for everyone's time!
Can we see the code? I don't think a call to DBI->connect() will die unless you explicitly tell it to, as in:
DBI->connect($dsn, $user, $pass) or die "Can't connect: $DBI::errstr\n";
I'm pretty sure even using {RaiseError => 1} won't make it die automatically. So, if you are calling or die... just don't do it!
EDIT:
Given the code that #squiguy posted, I would do it like this:
foreach my $host (#hosts) {
$dbh = DBI->connect("dbi:Oracle:; host=$host; port=$port", $username, $password);
next unless $dbh;
if ($dbh->state()) {
# Do stuff with state information
}
}
You should look up exception handling in Perl. I don't use Perl so I do not know the syntax for exception handling, should be easy enough to find online though.
I have the database names in an array and go trough them in a loop, I want to try and connect and perform a query and disconnect.
If you're looping, there's no reason to open multiple databases. In your loop, open a database, do your stuff, and close.
How can I connect to multiple databases in perl without it bailing out if it can't connect to one?
I'm assuming that this is in your loop. You can always use eval whenever you are doing any Perl command that might error out and stop your program from executing.
You do something like this:
for my $database (#database_list) {
my $dbh;
eval {
$dbh = DBI->connect($database, $user, $password);
};
if (not $#) {
yadda, yadda, yadda
}
}
The eval will catch any sort of ordinary deadly error. If $# has a value, the call failed, and eval returned an error description. If $# is empty, no error, and you can simply continue.
HOWEVER, BY default, DBI doesn't automatically die if it can't connect. Instead, it merely returns an undefined value. You should be able to use that to determine whether you've succeeded, or need to go to the next database:
for my $database (#database_list) {
my $dbh = DBI->connect($database, $user, $password);
if ($dbh) {
yadda, yadda, yadda
}
}
If I remember correctly, there's an attribute called RaiseError that if set will cause your program to die in a failed DBI call. However, the default should be not set, so you shouldn't be having any issues.

Perl: Uploading a file from a web page

I am trying to upload a file from a web page without using:
my $query = CGI->new;
my $filename = $query->param("File");
my $upload_filehandle = $query->upload("File");
My form has several input fields and only one of them is a file name. So when I parse the form I parse all of the input fields in one pass. This means that I have the filename withough using my $filename = $query->param("File"); but, as far as I can tell, this means I can't use my $upload_filehandle = $query->upload("File"); to do the actual uploading.
Any advice is appreciated.
Regards.
How are you parsing the input fields? More importantly why are you using CGI and reimplementing some of its functionality?
This should still work:
my %args = how_you_are_parsing_the_url();
my $query = CGI->new; #this parses the url as well
my $upload_filehandle = $query->upload("File"); #assuming the input is named File

How can I fix the "Couldn't create file parser context for file ..." bug with Perl libxml on Debian?

When I try to read an XML file with XML::Simple, sometimes I get this error message:
Couldn't create file parser context for file ...
After some googling, it seems to be a problem with libxml-libxml-perl and is supposed to be fixed in the version I use (1.59-2).
Any ideas?
Edit: (code)
sub Read
{
my ($file, $no_option) = #_;
my %XML_INPUT_OPTIONS = ( KeyAttr => [], ForceArray => 1 );
if ((defined $file) && (-f $file))
{
my #stats = stat($file);
if ((defined $XML_CACHE{$file})
&& ($stats[9] == $XML_CACHE{$file}{modif_time}))
{
return ($XML_CACHE{$file}{xml});
}
else
{
my $xml = eval { XMLin($file,
(defined $no_option ? () : %XML_INPUT_OPTIONS)) };
AAT::Syslog("AAT::XML", "XML_READ_ERROR", $#) if ($#);
$XML_CACHE{$file}{modif_time} = $stats[9];
$XML_CACHE{$file}{xml} = $xml;
return ($xml);
}
}
return (undef);
}
And yes, I should & will use XML::Simple cache feature...
Does the error continue "No such file or directory at..."? If so, then I think that the problem is that (for whatever reason) when you get to that point in the script, whatever you are passing to XML::Simple has no xml file in it. Long story short, the script you are using may be passing a bad variable (blank? empty?) to XML::Simple at which point the module chokes. To debug, add a check on whatever you hand to XML::Simple before you pass it along. (See the next paragraph for a concrete example explaining why I think this may be your problem.)
A few months ago, I had a similar problem with Weather::Google. In a nutshell, the weather module was trying to get data from Google via LWP::Simple without a user agent. Google began (apparently) to reject requests without a user agent. I had to backtrack through the modules because the error appeared to come from XML::Simple. In fact, it was caused by what was done in LWP::Simple and Weather::Google. Or rather, the error was a result of Weather::Google not checking the data that was in an object created via LWP::Simple. In a case like this, it can be hard at first to see what's going wrong and where.