rsennat has asked for the wisdom of the Perl Monks concerning the following question:

hi,
Earlier i posted mod_perl and multi user environment - clashes with other users's data, and got the solution for the problem. But the same is not working here.
After using "our" keyword, im still facing problem with my code. On every click to the cgi, i see that different user's info is displayed. Please check whats wrong in my code,
#! /usr/local/bin/perl -w #use strict; use CGI qw(:standard); use CGI::Carp qw(warningsToBrowser fatalsToBrowser); use HTML::Template; use Data::Dumper; use hiGuiStatus; # my own module # send the obligatory Content-Type print "Content-Type: text/html\n\n"; #$q = new CGI; #print $q->Dump(); our $status = hiGuiStatus->new(); our $userid = $status->get_ldap_user_name(); print $userid; my $err_msg; ($err_msg, %hoh) = $status->read_file($userid); #print Dumper \%hoh; if(param('sort')) { my $sort_sel = param('sort_option'); ($err_msg, @sort_keys) = $status->jobs_sort($sort_sel); #print $err_msg; } if(param('terminate')) { my @del_ids = param('check_del'); ($err_msg) = $status->jobs_terminate(\@del_ids, $userid, \%hoh); ($err_msg, %hoh) = $status->read_file($userid); } if(param('publish')) { my $ddts = param('ddts_no'); my @del_ids = param('check_del'); $status->jobs_publish($ddts, \@del_ids); } if(param('delete')) { my @del_ids = param('check_del'); ($err_msg) = $status->jobs_delete(\@del_ids, $userid, \%hoh); ($err_msg, %hoh) = $status->read_file($userid); } @loop = $status->jobs_loop(); #print Dumper \@loop; my $template = HTML::Template->new(filename => 'hiGuiStatus.tmpl'); # call param to fill in the loop with the loop data by reference. $template->param(err_msg => $err_msg, job_loop => \@loop); # print the template print $template->output;

Basically this code does retrieve data from a text file for a particular user who has logged in and display it using HTML::Template.
I used the keyword "our" and still face the problem of other user's data being displayed in my browser, ONLY IN mod_perl

thanks
rsennat

Replies are listed 'Best First'.
Re: mod_perl and multiuser global variables
by gam3 (Curate) on Dec 05, 2005 at 14:29 UTC
    The problem is that
    our $status = hiGuiStatus->new();
    our $userid = $status->get_ldap_user_name();
    
    get set by one user (the user that first generates the page), and then when the next user looks at the page they will see the info for the first user. Then since there are several servers (instanses of httpd) running it seems to switch from user to user as you reload the page.

    To fix this set $userid in the handler.

    -- gam3
    A picture is worth a thousand words, but takes 200K.
      I would imagine this is a Apache child problem. I'll try to expalin:

      Apache is inheritedly and relitively multi-threaded. And, depending on your configuration and such, you will expect to have many threads open at any given time. The threads are usually called 'Children' or 'Apache Children'. Each of these children are used to load pages and send the data back to the requestor.

      Given this quick tutorial, it sounds to me like you are loading the LDAP user name globally to each child. Then when the user goes to the next page, the page is loaded through another child that is no longer aware of the $userid. However, in the same sense, the $userid is still defined, however in another child. Therefore, when another user comes along and loads the page, if they grab the same child as the user before them did, they would already have the $userid from the last user.

      Generally speaking, this is not the best way to hold persistant session data. Mainly because Apache, and all web servers for that matter, do not have the ability to uphold any type of persistance via the net. Perhaps the best way to hold this type of information in a semi-secure and easily retrievable way is through the assignement of a cookie or other persistance mechagnism.

      Answer:
      Don't use Perl variables within a Child to store user session information. It will, almost certainly, be shared to different requestors as the uptime of the server continues to grow.

      These might give you some more answers, too. Take a look at them in the order I've listed them:
      Good Luck

      ---hA||ta----
      print map{$_.' '}grep{/\w+/}@{[reverse(qw{Perl Code})]} or die while ( 'trying' );

      hum... If it wasn't in the handler, than none of the code would execute (since it's all at the same level), and he'd see nothing at all (or rather a 500 HTTP error). I suspect he's using Apache::Registry, in which case the code *is* in the handler.

      With Apache::Registry, the script gets converted to a function which is called every time the page is requested.

      I bet the problem is in his hiGuiStatus module.

      By the way rsennat, our isn't needed here. my will suffice and it would be a better choice here. The problem in the previous thread is that you were using a my variable as a global, which is a no-no in mod_perl. Here, they're not used as globals.

        hi,
        i need this to be resolved. because there is no persistency in getting the logged in user's info.

        this code is in a separate .cgi file and not in a handler to execute from the browser, which will display the user's info.

        im using PerlResponseHandler ModPerl::RegistryPrefork in httpd.conf.

        Only in mod_perl i see this problem. Even in perl/cgi environment im using the module hiGuiStatus.pm, where there is no problem.

        thanks
        rsennat
      Sorry if im asking the very basic. I have just started using mod_perl.
      So, where to set $userid??

      thanks
Re: mod_perl and multiuser global variables
by maverick (Curate) on Dec 05, 2005 at 15:31 UTC
    Try looking at Apache::Session in tandem with Apache::Cookie. The former sets up a hash that can be used to store any user specific data and retrive it in subsequent requests by referencing a unique key. The later helps you manage cookies that can be used to store your unique session key on the browser side.

    The problem that you're running into isn't really one of keeping a value shared, it's one of making sure you have the same value for the same browser session. Since HTTP is stateless, you have to have the browser pass back to the server on each request (either via cookie or URL parameter) the unique identifier of the session.

    It's Monday AM...let's see if I can whip out a working example.

    use Apache::Cookie; use Apache::Session::File; # Inside your mod_perl handler my $cookie = Apache::Cookie->new($r, -name => 'session_id', -expires => '+1D', -domain => 'mysite.com', -path => '/' ); my %session; my $session_id = $cookie->value; # The tie will fail if the session_id isn't valid or is missing. Thus + the need for eval. eval { tie(%session,'Apache::Session::File',$session_id, { Directory => ' +/tmp', LockDirectory => '/tmp' }); }; if ($@) { # bogus session_id. Setting it to undef will cause Apache::Sessio +n to create a new one undef $session_id; tie(%session,'Apache::Session::File',$session_id, { Directory => ' +/tmp', LockDirectory => '/tmp') || die "say something useful"; } if ($session_id != $cookie->value) { # session id has changed or is a new one; update the cookie $cookie->value($session_id); $cookie->bake; } # use %session at will to store user data. $session{'name'} = 'John Doe'; $session{'user_id'} = 123; my $value = $session{'some_data'}; # untie the session after you're done with it untie %session;
    Hope this helps

    Edit: Typos, add links to cpan

    /\/\averick

      hi wazzuteke, maverick, already im maintaining a session, using CGI::Session. So i will try storing the user info in the session and retrieve it from there.

      but whats the solution in using global variables with mod_perl

      because i have one more problem too. like in the HTML::Template im passing some data. Only in mod_perl, i see that after every reload of the page, the data displayed gets repeatedly displayed. this happens for every reload.

      thanks
      rsennat
        This is somewhat of a tricky question. Assuming you're running Apache on *nix, each child will be forked off into it's own process. Therefore, if you make a variable global, it will only be global to that child. However, if you make the same variable name global in each child to the same value (via a database, or something similar), then you will have some sort of psudo-global variable. Nonetheless, to have a variable that is global to the Parent and each child is not possible; at least from my knowledge of mod_perl and Apache (someone correct me if I'm wrong here).


        ---hA||ta----
        print map{$_.' '}grep{/\w+/}@{[reverse(qw{Perl Code})]} or die while ( 'trying' );
Re: mod_perl and multiuser global variables
by perrin (Chancellor) on Dec 05, 2005 at 16:32 UTC
    Uncomment "use strict", add "use warnings", and change those "our" variables to "my" variables. The values of $userid and $status will persist if you use our.