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

hi all,

hoping that this perlmonks group will resolve mod_perl problem too....

im facing a problem with mod_perl2 on apache 2 as,

in my application, in the multiuser environment, everyone logs into the main page and their respective profile gets displayed. after every click, other user's data also gets appended to this current view for the user, which is not the expected one in mod_perl.

the same piece of code cgi/perl works very well on apache 2.(without mod_perl). only the respective user's profile can be viewed.

i tested with another piece of simple code,
#!/usr/cisco/bin/perl -w use strict; use CGI; my $q = CGI->new; my $name = $q->param('name'); print_response( ); sub print_response { print "Content-type: text/plain\n\n"; print "Thank you, $name!"; }
in one browser, when i pass a name it is printed properly. and opening another browser to run the same cgi with another name, prints the name entered in the previous browser.

so the problem arises only with mod_perl for sure.

how can this be resolved???

thanks
rsennat
  • Comment on mod_perl and multi user environment - clashes with other users's data
  • Download Code

Replies are listed 'Best First'.
Re: mod_perl and multi user environment - clashes with other users's data
by ikegami (Patriarch) on Dec 02, 2005 at 18:22 UTC

    Because print_response closed over the my $name that existed when the script was compiled. That my $name is different from the one in the second pass.

    Solution 1: Use package (our) variables instead of lexical (my) variables for globals.

    #!/usr/cisco/bin/perl -w use strict; use CGI; our $q; our $name; sub print_response { print "Content-type: text/plain\n\n"; print "Thank you, $name!"; } { local $q = CGI->new; local $name = $q->param('name'); print_response( ); }

    Solution 2: Use arguments instead of global variables.

    #!/usr/cisco/bin/perl -w use strict; use CGI; sub print_response { my ($name) = @_; print "Content-type: text/plain\n\n"; print "Thank you, $name!"; } { my $q = CGI->new; my $name = $q->param('name'); print_response($name); }

    Update:

    Solution 3: Use objects instead of global variables.

    #!/usr/cisco/bin/perl -w use strict; use CGI; sub new { my ($class) = @_; my $q = CGI->new; my $name = $q->param('name'); return bless({ q => $q, name => $name, }, $class); } sub print_response { my ($self) = @_; my $name = $self->{name}; print "Content-type: text/plain\n\n"; print "Thank you, $name!"; } { my $self = __PACKAGE__->new(); $self->print_response(); }
      hi,
      Even after using "our" keyword, im facing problem with my code. with that sample your solution works fine. but please check whats wrong in my code,
      #! /usr/cisco/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
Re: mod_perl and multi user environment - clashes with other users's data
by rsennat (Beadle) on Dec 02, 2005 at 18:33 UTC
    hi ikegami,

    that works fine. thanks a lot.

    but i found in some sites like to use lot of modules in the httpd.conf to make this work...

    is there any way to use some module like PerlRun to resolve this problem???

    thanks
    rsennat
      You can use PerlRun to solve this. It will run more slowly, but should work and will still be faster than CGI. Fixing the code is the best way to solve it.

        Specifically,

        This module's handler emulates the CGI environment, allowing programmers to write scripts that run under CGI or mod_perl without change. Unlike Apache::Registry, the Apache::PerlRun handler does not cache the script inside of a subroutine. Scripts will be "compiled" every request. After the script has run, it's namespace is flushed of all variables and subroutines.

        The Apache::Registry handler is much faster than Apache::PerlRun. However, Apache::PerlRun is much faster than CGI as the fork is still avoided and scripts can use modules which have been pre-loaded at server startup time. This module is meant for "Dirty" CGI Perl scripts which relied on the single request lifetime of CGI and cannot run under Apache::Registry without cleanup.

        It works because scripts are compiled at every request. I don't recommend using PerlRun unless you're trying to run an existing CGI script in mod_perl. If you're writting a script for mod_perl, you shouldn't use PerlRun.