...

View Full Version : session variables



Fishhead
03-06-2010, 01:17 AM
I need help setting a session variable. I can usually get things to work by reading and a lot of trial and error, but session variables has got me very lost. In a php script I constructed a simple site counter that tested for the existence of a variable and if not set it added one to the counter value. I then set the variable as the IP address. As the user viewed various pages, the counter would no longer increment, because the variable was now set. In php this is easy with the $_SESSION['variable']. But in Perl I can not figure this out.

Can some one point me in the direction of a good tutorial on this or better provide me with some sample code? Thanks.

SSCR9
03-06-2010, 01:24 AM
I'm pretty sure that in Perl all you need to do is type this:


$session = new CGI::Session();
#save the IP somehow...
$session{"IP_ADDRESS"} = $q->param("$IPaddress");


I don't know if that helps. That's what I've always used for session storage, but I don't really know a lot about Perl.

Fishhead
03-06-2010, 04:10 AM
Thanks for the response. When I use your code I get this error message:


Can't call method "param" on an undefined value at ...

The code that I have is:


$_start=$ENV{'REMOTE_ADDR'};
$session = new CGI::Session();
$session{"IP_ADDRESS"} = $q->param("$_start");

I tried entering my $_start above these lines but that did not stop the error message.

I am looking for suggestions.

SSCR9
03-06-2010, 05:47 AM
(facepalm)
I'm not really great with Perl, but don't you need to actually give it a parameter?
(and you can read that in an incredibly sarcastic tone of voice)

bazz
03-06-2010, 06:07 AM
Hi,

You might fins that there is some confusion caused by the naming of your variable. $_ is a default perl variable so I never start a var name with _

Better, I think to use $start or in this case, $ip_address




use CGI;
use CGI::Session;
use strict;
use CGI::Carp qw(fatalsToBrowser);


my $cgi = CGI->new;
my $session = new CGI::Session($cgi) or die CGI::Session->errstr;

$session->param('ipAddress', $ENV{REMOTE_ADDR});

my $ip_address = $session->param('ip_address');



Doing it that way, you store the ip_address and cal it in for use in the script, all in one go.

The longer way to do it could be:



my $session = new CGI::Session($cgi) or die CGI::Session->errstr;

my $ip_address = $ENV{REMOTE_ADDR};

$session->param('ipAddress', $ip_address);

$ip_address = $session->param('ip_address');


hth

bazz

Fishhead
03-06-2010, 03:32 PM
Thanks bazz

I took your suggestions and modified my code and the error has ceased, however, the variable does not behave as I expected a session variable to behave. Below is the relevent part of my code. Here the session variable is set once the counter has incremented when the user first visits the site. As the vistor views other pages and returns to the home page the session variable should be set and therefore no further increments in the counter. But that is not working. If I move code so the session variable is set before the counter increment, the count does not increment.

I also tried echoing the session variable in other pages to test whether it truly is a session variable and that does not work either.

I have wondered if SESSIONS is installed, but I assume that an error would have occurred when I stated - use CGI::Sessions, if it were not available.

Any additional advice?


use CGI;
use CGI::Session;
use strict;
use CGI::Carp qw(fatalsToBrowser);



my $val;
my $count;
my @data;
my $ipaddress;
my $session;
my $cgi;


open(COUNTER,"$log")or die;
@data=<COUNTER>;
close(COUNTER);
foreach $val (@data)
{
chomp($val);
($count)=split(/\|/,$val);
}

if (!defined($ipaddress)){
$count = $count + 1;
}
open(COUNTER, ">$log")or die;
print COUNTER $count;
close(COUNTER);

$session = new CGI::Session($cgi) or die CGI::Session->errstr;
$ipaddress=$ENV{'REMOTE_ADDR'};
$session->param('ipaddress', $ipaddress);
$ipaddress= $session->param('ipaddress');

bazz
03-06-2010, 06:07 PM
Hi Fishhead,

The code I gave has to be at the top of your scripts - all of them.

To check that the session is persisting from script to script, you can use this line to show you the session_id,

print $session->header;

or add this below the code of my earlier post.



my $session_id = $session->id;
print qq( sess_id = $session_id );


That value should be the same on all pages otherwise the session is not being retained and we then need to see why that would be. Have you got an online page to look at?

bazz

bazz
03-06-2010, 06:13 PM
Further to that last post, I am slightly confused with this sentence.



As the vistor views other pages and returns to the home page the session variable should be set and therefore no further increments in the counter.


I assume you meant that 'as they view other pages'... the session is set and so there would be no further increments of the counter'. Are you counting the number of home page views or the number of page views in total??

I think the way you are doing it could be better and it should be done in a mysql table. Get all that data you can and compile the stats you need.

I can say that because I went along your route in the past and FishMonger coaxed me to MySQL since when, I ain't looked back. But if you are trying solely to learn perl, then that suggestion may not be best for you.

bazz

Fishhead
03-06-2010, 06:44 PM
Thanks again bazz,

My goal was to count the total number of visits to the site, regardless of how many pages the user may view. A view of the home page is one visit. A person viewing 8 pages is still only one visit. Right now the counter is clicking on each page.

As I mentioned in my first post, I was able to accomplish this in php using a session variable which was set following the counter increment on the first visit to the home page. But perl is new to me and similar but different than php.

I am in a series of meetings this weekend and through most of next week, so I am visiting my coding during breaks or when the discussion is to boring. I will try inserting your code at the top of each .pl file and see if that solves my current problem.

Fishhead

Fishhead
03-07-2010, 06:22 AM
bazz

I am feeling a bit on the slow side with this aspect of perl. My efforts to establish a session variable are failing. When I paste the code into each file, the variable changes when each page is viewed and the counter keeps increasing. If I do not place the code in each page the counter keeps incrementing by one for each page.

As I have stated before, I have done very little with perl programing todate. But the input, lay out, booleen stuff, has been fairly straight forward. Storing a variable for use through a session is becoming evasive. Why I do not know, but it just is not working for me.

The counter that I wish to create is certainly not a deal breaker, but it bugging me that I can not figure this out. I must be making more difficult than it truly is.

Fishhead

FishMonger
03-07-2010, 10:02 PM
Your script has several problems.

First, you should use file locking on your counter file. We can that locking code to what you have, however, a better approach would be to use the File::CounterFile module, which handles everything for you.

You have a discrepancy in data format of your counter file. The first time you access it (for reading), you split the line by the | character, so presumably that line has multiple values/items. However, when you write to the file, you only output a single integer.

Incrementing the counter needs to be in a conditional that checks the 'ipaddress' session param.

Try this example.

page1.pl

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use CGI::Session;
use CGI::Carp qw(fatalsToBrowser);
use File::CounterFile;
use Data::Dumper;

my $cgi = CGI->new;
my $session = CGI::Session->new;
my $counter = File::CounterFile->new("./COUNTER", 0);
my $visits = $counter->value;

if ( !$session->param('ipaddress') ) {
$visits = $counter->inc;
$session->param('ipaddress', $ENV{'REMOTE_ADDR'});
}

print $session->header,
$cgi->start_html('page1');

print $cgi->h1($session->param('ipaddress').
" has visited this site $visits time(s)"),
$cgi->a({href=>"/cgi-bin/page2.pl"}, 'Next Page');

#print '<pre>', Dumper($session), '</pre>';
print $cgi->end_html;

page2.pl

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use CGI::Session;
use CGI::Carp qw(fatalsToBrowser);
use File::CounterFile;
use Data::Dumper;

my $cgi = CGI->new;
my $session = CGI::Session->new;
my $counter = File::CounterFile->new("./COUNTER", 0);
my $visits = $counter->value;

if ( !$session->param('ipaddress') ) {
$visits = $counter->inc;
$session->param('ipaddress', $ENV{'REMOTE_ADDR'});
}

print $session->header,
$cgi->start_html('page2');

print $cgi->h1($session->param('ipaddress').
" has visited this site $visits time(s)"),
$cgi->a({href=>"/cgi-bin/page1.pl"}, 'Previous Page');

#print '<pre>', Dumper($session), '</pre>';
print $cgi->end_html;

Fishhead
03-08-2010, 05:00 AM
FishMonger

Thanks for your help. The script for this website is located on a remote server where space is bought. I am receiving the following error message from using your code. I can contact the server company and request that modules are added, but I do not have a clue whether they will give a damn.


Can't locate File/CounterFile.pm in @INC ...

This is a very new world for me. This scipts is stored in cgi-bin and has been and still is a learning experience for me.

Any suggestions on how to install the needed modules or get around the CounterFile modules would be greatly appreciated.

Fishhead

FishMonger
03-08-2010, 03:53 PM
You can easily install the module yourself into your own directories.

The CounterFile.pm module is a small pure Perl module that doesn't need compiling. It would be best, but not required, to create a 'MyModules' directory under your cgi-bin dir and under that dir create a 'File' dir and put the CounterFile.pm file in that directory.

You can download the module from here:
http://search.cpan.org/~gaas/File-CounterFile-1.04/CounterFile.pm

Once you have it installed, you need to add one more line to the script, prior to loading the CounterFile module.

use lib 'MyModules';
So, the beginning of your script would look like this:

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use CGI::Session;
use CGI::Carp qw(fatalsToBrowser);
use lib 'MyModules';
use File::CounterFile;


That's the manual process, but there are other/better ways.
http://perldoc.perl.org/perlfaq8.html#How-do-I-keep-my-own-module/library-directory?

Fishhead
03-08-2010, 05:17 PM
FishMonger

thanks for the help. this could be my bad eyes but I am now getting an error message telling me the module can not be fould.


Can't locate File/CounterFile.pm in @INC (@INC contains: MyModules /usr/local/lib/perl5/5.6.1/

I placed CounterFile.pm within cgi-bin/MyModules/File/ and added the use lib 'MyModules'; line in my code.

Fishhead

FishMonger
03-08-2010, 06:50 PM
Sorry, my fault.

You need to specify the absolute or relative path in the use lib statement.

use lib './MyModule';

Fishhead
03-08-2010, 09:20 PM
Thank you FishMonger

I made it '../MyModule' not './MyModule' and it works just fine. This resolves my current issue in structuring a counter, but I am still not grasping the session coding. I will give it a rest for a while, before diving back into that issue.

Fishhead

Fishhead
03-09-2010, 12:22 AM
FishMonger

One last question - how can I reset the counter? Where exactly is the counter file stored?

FishMonger
03-09-2010, 01:37 PM
You can reset the counter by either manually editing the file, or by simply deleting the file. If the file is deleted, the script will recreate it the next time it's called.

The counter file's name and location is specified in the 1st parameter when creating the "counter" object.

e.g.,

my $counter = File::CounterFile->new("./COUNTER", 0);
In this case the filename is COUNTER and the relative path points to the current directory i.e. the same directory where the script is located.

Fishhead
03-13-2010, 12:50 AM
FishMonger

I hate to keep bugging you with my counter issue, but some side effects are occurring. The code that you provided is causing a conflict with the login cookie code of my script. A user can login and their username and password will be stored and automatically inserted in forms where needed. The conflict has stopped this from occurring.

Additionally, when the user logs in, the code
"set-cookie: LoginCookieID=$alias\01raymondevery0026378483lostrader$pw" is printed at the top of the page. If the user logs out then the code
"set-cookie: LoginCookieID=" is shown.

Below are the cookie sections of my code:

my $CookieName = 'LoginCookie';
# $cookieExpires = 1; Days for login cookie to expire,
# set to 0 to store no cookies in the web browser and to expire
# the cookie when the users closes the web browser
my $cookieExpires = 0;
foreach my $rel(split /; /, $ENV{HTTP_COOKIE}){
next unless $rel=~s/^\Q$CookieName//;
my($bufName, $bufVal) = split(/=/, $rel);
$bufVal =~ s/%([a-fA-F0-9]{2})/pack("H2",$1)/eg;
$cookie{$bufName} = $bufVal;}
my ($loginalias, $loginpassword) = setlogin();
$loginalias =~ s/[\*\#\"\'\}\{\)\(\%\&\@\+]//g;
$loginpassword =~ s/[\*\#\"\'\}\{\)\(\%\&\\@+]//g;
$loginalias =~ s/\W//g;
$loginalias = ucfirst(lc($loginalias));
my($password, $undef) = &read_reg_file($loginalias);
if(lc $password ne lc $loginpassword || $password eq ''){ $loginalias = $loginpassword = '' }

#-#############################################
# Print The Page Header
#
print "Content-type: text/html\n\n";

print $config{'header1'};


print $config{'header2'};
if ($loginalias ne '') {
print "<table align=\"center\" width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">";
print "<TR><TD WIDTH=\"100%\" align=\"center\"><center>Welcome<b> $loginalias </b>
( <a href=\"$ENV{'SCRIPT_NAME'}?newlogin=1\">Log Out</a> )</center></TD></TR>";
print "</table>";
}


if ($form{'loginalias'} ne "") {
$form{'loginalias'} =~ s/\W//g;
$form{'loginalias'} = ucfirst(lc($form{'loginalias'}));
&checksuspendeduser($form{'loginalias'});
&oops('Your alias could not be found') unless (open(REGFILE,"$config{'regdir'}/$form{'loginalias'}.dat"));
my($password,$email,$add1,$add2,$add3,$phone1,$phone2,$phone3,$phone4,@past_bids) = <REGFILE>;
chomp($password,$email,$add1,$add2,$add3,$phone1,$phone2,$phone3,$phone4,@past_bids);
close REGFILE;
&oops('You did not enter a password') if ($form{'loginpassword'} eq "");
&oops('Your password is incorrect.') unless ((lc $password) eq (lc $form{'loginpassword'}));
}


# Cookie login form

sub cookielogin {

print <<EOF;
<FORM ACTION="$ENV{'SCRIPT_NAME'}" METHOD="post">
<INPUT TYPE="hidden" NAME="setlogin" VALUE="1">
<TABLE ALIGN=CENTER WIDTH="45%" BORDER="0" CELLPADDING="0" CELLSPACING="0" BGCOLOR="$config{'colortablehead'}">
<TR><TD COLSPAN=2><B><FONT SIZE="+2" FACE="Times New Roman">Automatic Login</FONT></B></TR></TD>
<TR><TD COLSPAN=2><FONT FACE="Times New Roman"><B>This feature automatically fills in all the user name and password forms, that you will come across while navigating the site.<P></B></FONT><FONT COLOR="#FF0000" SIZE="+1">(You must have the "accept cookies" feature enabled, in your browsers preference settings).</FONT><P><CENTER><A HREF="$ENV{'SCRIPT_NAME'}?action=lostalias">Forgot User Name</A> <B>|</B> <A HREF="$ENV{'SCRIPT_NAME'}?action=lostpass">Forgot Password</A><P></CENTER></TD></TR>

<TR><TD BGCOLOR=$config{'colortablebody'}><B>Username:</B></TD>
<TD BGCOLOR=$config{'colortablebody'}><INPUT TYPE="text" NAME="loginalias" VALUE="$form{loginalias}"><FONT COLOR="#ff0000">** Required **</FONT></TR></TD>
<TR><TD BGCOLOR=$config{'colortablebody'}><B>Password:</B></TD>
<TD BGCOLOR=$config{'colortablebody'}><INPUT TYPE="password" NAME="loginpassword"><FONT COLOR="#ff0000">** Required **</FONT></TD></TR>
</TABLE>
<BR>
<CENTER><INPUT TYPE="SUBMIT" VALUE="Enter"></CENTER></FORM>
EOF
}

###############################
# make cookie sub

sub makecookie{
my ($name, $expires, $value) = @_;
$value =~s/(\W)/'%'.unpack('H2', $1)/eg;
my $cookie = "Set-Cookie: $CookieName$name=$value";
if($expires>0){
my @months = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
my @days = qw/Sun Mon Tue Wed Thu Fri Sat/; my($sec,$min,$hour,$mday,$month,$year,$wday) = gmtime(time+86400*$expires);
$year += 1900;
$expires = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",$days[$wday],$mday,$months[$month],$year,$hour,$min,$sec );
$cookie .= "; expires=$expires";
}
return "$cookie\n";
}

########################################
# set cookie login sub

sub setlogin {

if($form{'newlogin'}) {
print makecookie("ID", 0, '');
}
elsif($form{'setlogin'}) {
my $alias = $form{'loginalias'};
my $pw = lc $form{'loginpassword'};
$alias =~ s/\W//g;
print makecookie("ID", $cookieExpires, "$alias\01raymondevery0026378483lostrader$pw");
return($form{'loginalias'},lc $form{'loginpassword'});
}
elsif($cookie{ID} ne ''){
#my($alias,$pw) = split /\01/, $cookie{ID};
my($alias,$pw) = split /\01raymondevery0026378483lostrader/, $cookie{ID};
return($alias,$pw);
}
}

Do you have any suggestion to remedy this conflict?

FishMonger
03-13-2010, 02:48 AM
I need to take a closer look at that code, but I don't see any conflict. However, I do see a lot of questionable code.

This thread started out as a question regarding server side sessions, and now it appears that you switched to storing all of your state info in cookies. Why the change?

Fishhead
03-13-2010, 03:15 AM
FishMonger

The code that I have called mine has its origins in "MakeBid Auctions" which I obtained and have modified extensively to look and do what I need done. My perl coding experience began last summer when I purchased the code for $65. As I have learned more about perl, I have also wondered and questioned the efficiency of some of the auction code. That said, I also believe that if it works "use it".

As to your question about shifting my topic from session variables to cookies, it is simply the way the discussion has flowed. Originally, I was attempting to construct a counter in a similar manner that I have done in php using session variables. I ran into difficultives and kind folks such as you provided suggestions on a different approach, which work fine but are causing problems with the existing cookie code in the script.

I thought of starting a new thread, but chose to go with the existing thread since you helped me out with the alternative counter code.

Fishhead

bazz
03-13-2010, 01:25 PM
You 'could' make the session store the login stuff on the server rather than by using cookies. That would mean that only the session ID would be stored on the users machine with the rest being stored on your server.

check this link for an example of a good login. (http://www.codingforums.com/showthread.php?t=121397&highlight=login)

FishMonger
03-13-2010, 03:50 PM
I agree with Bazz.

Due to the way you've posted the code, some of which is missing, it's hard for us to see the "big picture" of how your script is designed and how the counter code I showed you broke it.

I'm not sure how much of that posted code is original and how much is your additions, but here are 2 examples of questionable code.

This is a very sloppy way of getting a date string.

my @months = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
my @days = qw/Sun Mon Tue Wed Thu Fri Sat/;
my($sec,$min,$hour,$mday,$month,$year,$wday) = gmtime(time+86400*$expires);
$year += 1900;
$expires = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",$days[$wday],$mday,$months[$month],$year,$hour,$min,$sec

Better written as:

my $datestamp = strftime("%a, %d-%b-%Y %H:%M:%S GMT", gmtime(time+86400*$expires));

None of these items in the character class need to be escaped and that line is pointless.

$loginalias =~ s/[\*\#\"\'\}\{\)\(\%\&\@\+]//g;
because 2 lines later you have this which does the same and more.

$loginalias =~ s/\W//g;



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum