1package CGI::Session;
2use strict;
3use Carp;
4use CGI::Session::ErrorHandler;
5
6@CGI::Session::ISA      = qw( CGI::Session::ErrorHandler );
7$CGI::Session::VERSION  = '4.48';
8$CGI::Session::NAME     = 'CGISESSID';
9$CGI::Session::IP_MATCH = 0;
10
11sub STATUS_UNSET    () { 1 << 0 } # denotes session that's resetted
12sub STATUS_NEW      () { 1 << 1 } # denotes session that's just created
13sub STATUS_MODIFIED () { 1 << 2 } # denotes session that needs synchronization
14sub STATUS_DELETED  () { 1 << 3 } # denotes session that needs deletion
15sub STATUS_EXPIRED  () { 1 << 4 } # denotes session that was expired.
16
17sub import {
18    my ($class, @args) = @_;
19
20    return unless @args;
21
22  ARG:
23    for my $arg (@args) {
24        if ($arg eq '-ip_match') {
25            $CGI::Session::IP_MATCH = 1;
26            last ARG;
27        }
28    }
29}
30
31sub new {
32    my ($class, @args) = @_;
33
34    my $self;
35    if (ref $class) {
36        #
37        # Called as an object method as in $session->new()...
38        #
39        $self  = bless { %$class }, ref( $class );
40        $class = ref $class;
41        $self->_reset_status();
42        #
43        # Object may still have public data associated with it, but we
44        # don't care about that, since we want to leave that to the
45        # client's disposal. However, if new() was requested on an
46        # expired session, we already know that '_DATA' table is
47        # empty, since it was the job of flush() to empty '_DATA'
48        # after deleting. How do we know flush() was already called on
49        # an expired session? Because load() - constructor always
50        # calls flush() on all to-be expired sessions
51        #
52    }
53    else {
54        #
55        # Called as a class method as in CGI::Session->new()
56        #
57
58        # Start fresh with error reporting. Errors in past objects shouldn't affect this one.
59        $class->set_error('');
60
61        $self = $class->load( @args );
62        if (not defined $self) {
63            return $class->set_error( "new(): failed: " . $class->errstr );
64        }
65    }
66
67    my $dataref = $self->{_DATA};
68    unless ($dataref->{_SESSION_ID}) {
69        #
70        # Absence of '_SESSION_ID' can only signal:
71        # * Expired session: Because load() - constructor is required to
72        #                    empty contents of _DATA - table
73        # * Unavailable session: Such sessions are the ones that don't
74        #                    exist on datastore, but are requested by client
75        # * New session: When no specific session is requested to be loaded
76        #
77        my $id = $self->_id_generator()->generate_id(
78                                                     $self->{_DRIVER_ARGS},
79                                                     $self->{_CLAIMED_ID}
80                                                     );
81        unless (defined $id) {
82            return $self->set_error( "Couldn't generate new SESSION-ID" );
83        }
84        $dataref->{_SESSION_ID} = $id;
85        $dataref->{_SESSION_CTIME} = $dataref->{_SESSION_ATIME} = time();
86        $dataref->{_SESSION_REMOTE_ADDR} = $ENV{REMOTE_ADDR} || "";
87        $self->_set_status( STATUS_NEW );
88    }
89    return $self;
90}
91
92sub DESTROY         {   $_[0]->flush()      }
93sub close           {   $_[0]->flush()      }
94
95*param_hashref      = \&dataref;
96my $avoid_single_use_warning = *param_hashref;
97sub dataref         { $_[0]->{_DATA}        }
98
99sub is_empty        { !defined($_[0]->id)   }
100
101sub is_expired      { $_[0]->_test_status( STATUS_EXPIRED ) }
102
103sub is_new          { $_[0]->_test_status( STATUS_NEW ) }
104
105sub id              { return defined($_[0]->dataref) ? $_[0]->dataref->{_SESSION_ID}    : undef }
106
107# Last Access Time
108sub atime           { return defined($_[0]->dataref) ? $_[0]->dataref->{_SESSION_ATIME} : undef }
109
110# Creation Time
111sub ctime           { return defined($_[0]->dataref) ? $_[0]->dataref->{_SESSION_CTIME} : undef }
112
113sub _driver {
114    my $self = shift;
115    defined($self->{_OBJECTS}->{driver}) and return $self->{_OBJECTS}->{driver};
116    my $pm = "CGI::Session::Driver::" . $self->{_DSN}->{driver};
117    defined($self->{_OBJECTS}->{driver} = $pm->new( $self->{_DRIVER_ARGS} ))
118        or die $pm->errstr();
119    return $self->{_OBJECTS}->{driver};
120}
121
122sub _serializer     {
123    my $self = shift;
124    defined($self->{_OBJECTS}->{serializer}) and return $self->{_OBJECTS}->{serializer};
125    return $self->{_OBJECTS}->{serializer} = "CGI::Session::Serialize::" . $self->{_DSN}->{serializer};
126}
127
128
129sub _id_generator   {
130    my $self = shift;
131    defined($self->{_OBJECTS}->{id}) and return $self->{_OBJECTS}->{id};
132    return $self->{_OBJECTS}->{id} = "CGI::Session::ID::" . $self->{_DSN}->{id};
133}
134
135sub ip_matches {
136  return ( $_[0]->{_DATA}->{_SESSION_REMOTE_ADDR} eq $ENV{REMOTE_ADDR} );
137}
138
139
140# parses the DSN string and returns it as a hash.
141# Notably: Allows unique abbreviations of the keys: driver, serializer and 'id'.
142# Also, keys and values of the returned hash are lower-cased.
143sub parse_dsn {
144    my $self = shift;
145    my $dsn_str = shift;
146    croak "parse_dsn(): usage error" unless $dsn_str;
147
148    require Text::Abbrev;
149    my $abbrev = Text::Abbrev::abbrev( "driver", "serializer", "id" );
150    my %dsn_map = map { split /:/ } (split /;/, $dsn_str);
151    my %dsn  = map { $abbrev->{lc $_}, lc $dsn_map{$_} } keys %dsn_map;
152    return \%dsn;
153}
154
155sub query {
156    my $self = shift;
157
158    if ( $self->{_QUERY} ) {
159        return $self->{_QUERY};
160    }
161#   require CGI::Session::Query;
162#   return $self->{_QUERY} = CGI::Session::Query->new();
163    require CGI;
164    return $self->{_QUERY} = CGI->new();
165}
166
167
168sub name {
169    my $self = shift;
170    my $name = shift;
171
172    if (ref $self) {
173        unless ( defined $name ) {
174            return $self->{_NAME} || $CGI::Session::NAME;
175        }
176        return $self->{_NAME} = $name;
177    }
178
179    $CGI::Session::NAME = $name if defined $name;
180    return $CGI::Session::NAME;
181}
182
183
184sub dump {
185    my $self = shift;
186
187    require Data::Dumper;
188    my $d = Data::Dumper->new([$self], [ref $self]);
189    $d->Deepcopy(1);
190    return $d->Dump();
191}
192
193
194sub _set_status {
195    my $self    = shift;
196    croak "_set_status(): usage error" unless @_;
197    $self->{_STATUS} |= $_[0];
198}
199
200
201sub _unset_status {
202    my $self = shift;
203    croak "_unset_status(): usage error" unless @_;
204    $self->{_STATUS} &= ~$_[0];
205}
206
207
208sub _reset_status {
209    $_[0]->{_STATUS} = STATUS_UNSET;
210}
211
212sub _test_status {
213    return $_[0]->{_STATUS} & $_[1];
214}
215
216
217sub flush {
218    my $self = shift;
219
220    # Would it be better to die or err if something very basic is wrong here?
221    # I'm trying to address the DESTROY related warning
222    # from: http://rt.cpan.org/Ticket/Display.html?id=17541
223    # return unless defined $self;
224
225    return unless $self->id;            # <-- empty session
226
227    # neither new, nor deleted nor modified
228    return if !defined($self->{_STATUS}) or $self->{_STATUS} == STATUS_UNSET;
229
230    if ( $self->_test_status(STATUS_NEW) && $self->_test_status(STATUS_DELETED) ) {
231        $self->{_DATA} = {};
232        return $self->_unset_status(STATUS_NEW | STATUS_DELETED);
233    }
234
235    my $driver      = $self->_driver();
236    my $serializer  = $self->_serializer();
237
238    if ( $self->_test_status(STATUS_DELETED) ) {
239        defined($driver->remove($self->id)) or
240            return $self->set_error( "flush(): couldn't remove session data: " . $driver->errstr );
241        $self->{_DATA} = {};                        # <-- removing all the data, making sure
242                                                    # it won't be accessible after flush()
243        return $self->_unset_status(STATUS_DELETED);
244    }
245
246    if ( $self->_test_status(STATUS_NEW | STATUS_MODIFIED) ) {
247        my $datastr = $serializer->freeze( $self->dataref );
248        unless ( defined $datastr ) {
249            return $self->set_error( "flush(): couldn't freeze data: " . $serializer->errstr );
250        }
251        defined( $driver->store($self->id, $datastr) ) or
252            return $self->set_error( "flush(): couldn't store datastr: " . $driver->errstr);
253        $self->_unset_status(STATUS_NEW | STATUS_MODIFIED);
254    }
255    return 1;
256}
257
258sub trace {}
259sub tracemsg {}
260
261sub param {
262    my ($self, @args) = @_;
263
264    if ($self->_test_status( STATUS_DELETED )) {
265        carp "param(): attempt to read/write deleted session";
266    }
267
268    # USAGE: $s->param();
269    # DESC:  Returns all the /public/ parameters
270    if (@args == 0) {
271        return grep { !/^_SESSION_/ } keys %{ $self->{_DATA} };
272    }
273    # USAGE: $s->param( $p );
274    # DESC: returns a specific session parameter
275    elsif (@args == 1) {
276        return $self->{_DATA}->{ $args[0] }
277    }
278
279
280    # USAGE: $s->param( -name => $n, -value => $v );
281    # DESC:  Updates session data using CGI.pm's 'named param' syntax.
282    #        Only public records can be set!
283    my %args = @args;
284    my ($name, $value) = @args{ qw(-name -value) };
285    if (defined $name && defined $value) {
286        if ($name =~ m/^_SESSION_/) {
287
288            carp "param(): attempt to write to private parameter";
289            return undef;
290        }
291        $self->_set_status( STATUS_MODIFIED );
292        return $self->{_DATA}->{ $name } = $value;
293    }
294
295    # USAGE: $s->param(-name=>$n);
296    # DESC:  access to session data (public & private) using CGI.pm's 'named parameter' syntax.
297    return $self->{_DATA}->{ $args{'-name'} } if defined $args{'-name'};
298
299    # USAGE: $s->param($name, $value);
300    # USAGE: $s->param($name1 => $value1, $name2 => $value2 [,...]);
301    # DESC:  updates one or more **public** records using simple syntax
302    if ((@args % 2) == 0) {
303        my $modified_cnt = 0;
304	ARG_PAIR:
305        while (my ($name, $val) = each %args) {
306            if ( $name =~ m/^_SESSION_/) {
307                carp "param(): attempt to write to private parameter";
308                next ARG_PAIR;
309            }
310            $self->{_DATA}->{ $name } = $val;
311            ++$modified_cnt;
312        }
313        $self->_set_status(STATUS_MODIFIED);
314        return $modified_cnt;
315    }
316
317    # If we reached this far none of the expected syntax were
318    # detected. Syntax error
319    croak "param(): usage error. Invalid syntax";
320}
321
322
323
324sub delete {    $_[0]->_set_status( STATUS_DELETED )    }
325
326
327*header = \&http_header;
328my $avoid_single_use_warning_again = *header;
329sub http_header {
330    my $self = shift;
331    return $self->query->header(-cookie=>$self->cookie, -type=>'text/html', @_);
332}
333
334sub cookie {
335    my $self = shift;
336
337    my $query = $self->query();
338    my $cookie= undef;
339
340    if ( $self->is_expired ) {
341        $cookie = $query->cookie( -name=>$self->name, -value=>$self->id, -expires=> '-1d', @_ );
342    }
343    elsif ( my $t = $self->expire ) {
344        $cookie = $query->cookie( -name=>$self->name, -value=>$self->id, -expires=> '+' . $t . 's', @_ );
345    }
346    else {
347        $cookie = $query->cookie( -name=>$self->name, -value=>$self->id, @_ );
348    }
349    return $cookie;
350}
351
352
353
354
355
356sub save_param {
357    my $self = shift;
358    my ($query, $params) = @_;
359
360    $query  ||= $self->query();
361    $params ||= [ $query->param ];
362
363    for my $p ( @$params ) {
364        my @values = $query->param($p) or next;
365        if ( @values > 1 ) {
366            $self->param($p, \@values);
367        } else {
368            $self->param($p, $values[0]);
369        }
370    }
371    $self->_set_status( STATUS_MODIFIED );
372}
373
374
375
376sub load_param {
377    my $self = shift;
378    my ($query, $params) = @_;
379
380    $query  ||= $self->query();
381    $params ||= [ $self->param ];
382
383    for ( @$params ) {
384        $query->param(-name=>$_, -value=>$self->param($_));
385    }
386}
387
388
389sub clear {
390    my $self    = shift;
391    my $params  = shift;
392    #warn ref($params);
393    if (defined $params) {
394        $params =  [ $params ] unless ref $params;
395    }
396    else {
397        $params = [ $self->param ];
398    }
399
400    for ( grep { ! /^_SESSION_/ } @$params ) {
401        delete $self->{_DATA}->{$_};
402    }
403    $self->_set_status( STATUS_MODIFIED );
404}
405
406
407sub find {
408    my $class       = shift;
409    my ($dsn, $coderef, $dsn_args);
410
411    # find( \%code )
412    if ( @_ == 1 ) {
413        $coderef = $_[0];
414    }
415    # find( $dsn, \&code, \%dsn_args )
416    else {
417        ($dsn, $coderef, $dsn_args) = @_;
418    }
419
420    unless ( $coderef && ref($coderef) && (ref $coderef eq 'CODE') ) {
421        croak "find(): usage error.";
422    }
423
424    my $driver;
425    if ( $dsn ) {
426        my $hashref = $class->parse_dsn( $dsn );
427        $driver     = $hashref->{driver};
428    }
429    $driver ||= "file";
430    my $pm = "CGI::Session::Driver::" . ($driver =~ /(.*)/)[0];
431    eval "require $pm";
432    if (my $errmsg = $@ ) {
433        return $class->set_error( "find(): couldn't load driver." . $errmsg );
434    }
435
436    my $driver_obj = $pm->new( $dsn_args );
437    unless ( $driver_obj ) {
438        return $class->set_error( "find(): couldn't create driver object. " . $pm->errstr );
439    }
440
441    # Read-only isn't the perfect name here. In read-only mode, we skip the ip_match check,
442    # and don't update the atime. We *do* still delete expired sessions and session params.
443    my $read_only = 1;
444    my $driver_coderef = sub {
445        my ($sid) = @_;
446        my $session = $class->load( $dsn, $sid, $dsn_args, $read_only );
447        unless ( $session ) {
448            return $class->set_error( "find(): couldn't load session '$sid'. " . $class->errstr );
449        }
450        $coderef->( $session );
451    };
452
453    defined($driver_obj->traverse( $driver_coderef ))
454        or return $class->set_error( "find(): traverse seems to have failed. " . $driver_obj->errstr );
455    return 1;
456}
457
458# $Id$
459
460=pod
461
462=head1 NAME
463
464CGI::Session - persistent session data in CGI applications
465
466=head1 SYNOPSIS
467
468    # Object initialization:
469    use CGI::Session;
470    $session = CGI::Session->new();
471
472    $CGISESSID = $session->id();
473
474    # Send proper HTTP header with cookies:
475    print $session->header();
476
477    # Storing data in the session:
478    $session->param('f_name', 'Sherzod');
479    # or
480    $session->param(-name=>'l_name', -value=>'Ruzmetov');
481
482    # Flush the data from memory to the storage driver at least before your
483    # program finishes since auto-flushing can be unreliable.
484    $session->flush();
485
486    # Retrieving data:
487    my $f_name = $session->param('f_name');
488    # or
489    my $l_name = $session->param(-name=>'l_name');
490
491    # Clearing a certain session parameter:
492    $session->clear(["l_name", "f_name"]);
493
494    # Expire '_is_logged_in' flag after 10 idle minutes:
495    $session->expire('is_logged_in', '+10m')
496
497    # Expire the session itself after 1 idle hour:
498    $session->expire('+1h');
499
500    # Delete the session for good:
501    $session->delete();
502    $session->flush(); # Recommended practice says use flush() after delete().
503
504=head1 DESCRIPTION
505
506CGI::Session provides an easy, reliable and modular session management system across HTTP requests.
507
508=head1 METHODS
509
510Following is the overview of all the available methods accessible via CGI::Session object.
511
512=head2 new()
513
514=head2 new( $sid )
515
516=head2 new( $query )
517
518=head2 new( $dsn, $query||$sid )
519
520=head2 new( $dsn, $query||$sid, \%dsn_args )
521
522=head2 new( $dsn, $query||$sid, \%dsn_args, \%session_params )
523
524Constructor. Returns new session object, or undef on failure. Error message is accessible through L<errstr() - class method|CGI::Session::ErrorHandler/"errstr()">. If called on an already initialized session will re-initialize the session based on already configured object. This is only useful after a call to L<load()|/"load()">.
525
526Can accept up to three arguments, $dsn - Data Source Name, $query||$sid - query object OR a string representing session id, and finally, \%dsn_args, arguments used by $dsn components.
527
528If called without any arguments, $dsn defaults to I<driver:file;serializer:default;id:md5>, $query||$sid defaults to C<< CGI->new() >>, and C<\%dsn_args> defaults to I<undef>.
529
530If called with a single argument, it will be treated either as C<$query> object, or C<$sid>, depending on its type. If argument is a string , C<new()> will treat it as session id and will attempt to retrieve the session from data store. If it fails, will create a new session id, which will be accessible through L<id() method|/"id">. If argument is an object, L<cookie()|CGI/cookie> and L<param()|CGI/param> methods will be called on that object to recover a potential C<$sid> and retrieve it from data store. If it fails, C<new()> will create a new session id, which will be accessible through L<id() method|/"id">. C<name()> will define the name of the query parameter and/or cookie name to be requested, defaults to I<CGISESSID>.
531
532If called with two arguments first will be treated as $dsn, and second will be treated as $query or $sid or undef, depending on its type. Some examples of this syntax are:
533
534    $s = CGI::Session->new("driver:mysql", undef);
535    $s = CGI::Session->new("driver:sqlite", $sid);
536    $s = CGI::Session->new("driver:db_file", $query);
537    $s = CGI::Session->new("serializer:storable;id:incr", $sid);
538    # etc...
539
540Briefly, C<new()> will return an initialized session object with a valid id, whereas C<load()> may return
541an empty session object with an undefined id.
542
543Tests are provided (t/new_with_undef.t and t/load_with_undef.t) to clarify the result of calling C<new()> and C<load()>
544with undef, or with an initialized CGI object with an undefined or fake CGISESSID.
545
546You are strongly advised to run the old-fashioned 'make test TEST_FILES=t/new_with_undef.t TEST_VERBOSE=1'
547or the new-fangled 'prove -v t/new_with_undef.t', for both new*.t and load*.t, and examine the output.
548
549Following data source components are supported:
550
551=over 4
552
553=item *
554
555B<driver> - CGI::Session driver. Available drivers are L<file|CGI::Session::Driver::file>, L<db_file|CGI::Session::Driver::db_file>, L<mysql|CGI::Session::Driver::mysql> and L<sqlite|CGI::Session::Driver::sqlite>. Third party drivers are welcome. For driver specs consider L<CGI::Session::Driver|CGI::Session::Driver>
556
557=item *
558
559B<serializer> - serializer to be used to encode the data structure before saving
560in the disk. Available serializers are L<storable|CGI::Session::Serialize::storable>, L<freezethaw|CGI::Session::Serialize::freezethaw> and L<default|CGI::Session::Serialize::default>. Default serializer will use L<Data::Dumper|Data::Dumper>.
561
562=item *
563
564B<id> - ID generator to use when new session is to be created. Available ID generator is L<md5|CGI::Session::ID::md5>
565
566=back
567
568For example, to get CGI::Session store its data using DB_File and serialize data using FreezeThaw:
569
570    $s = CGI::Session->new("driver:DB_File;serializer:FreezeThaw", undef);
571
572If called with three arguments, first two will be treated as in the previous example, and third argument will be C<\%dsn_args>, which will be passed to C<$dsn> components (namely, driver, serializer and id generators) for initialization purposes. Since all the $dsn components must initialize to some default value, this third argument should not be required for most drivers to operate properly.
573
574If called with four arguments, the first three match previous examples. The fourth argument must be a hash reference with parameters to be used by the CGI::Session object. (see \%session_params above )
575
576The following is a list of the current keys:
577
578=over
579
580=item *
581
582B<name> - Name to use for the cookie/query parameter name. This defaults to CGISESSID. This can be altered or accessed by the C<name> accessor.
583
584=back
585
586undef is acceptable as a valid placeholder to any of the above arguments, which will force default behavior.
587
588=head2 load()
589
590=head2 load( $query||$sid )
591
592=head2 load( $dsn, $query||$sid )
593
594=head2 load( $dsn, $query, \%dsn_args )
595
596=head2 load( $dsn, $query, \%dsn_args, \%session_params )
597
598Accepts the same arguments as new(), and also returns a new session object, or
599undef on failure.  The difference is, L<new()|/"new()"> can create a new session if
600it detects expired and non-existing sessions, but C<load()> does not.
601
602C<load()> is useful to detect expired or non-existing sessions without forcing the library to create new sessions. So now you can do something like this:
603
604    $s = CGI::Session->load() or die CGI::Session->errstr();
605    if ( $s->is_expired ) {
606        print $s->header(),
607            $cgi->start_html(),
608            $cgi->p("Your session timed out! Refresh the screen to start new session!")
609            $cgi->end_html();
610        exit(0);
611    }
612
613    if ( $s->is_empty ) {
614        $s = $s->new() or die $s->errstr;
615    }
616
617Notice: All I<expired> sessions are empty, but not all I<empty> sessions are expired!
618
619Briefly, C<new()> will return an initialized session object with a valid id, whereas C<load()> may return
620an empty session object with an undefined id.
621
622Tests are provided (t/new_with_undef.t and t/load_with_undef.t) to clarify the result of calling C<new()> and C<load()>
623with undef, or with an initialized CGI object with an undefined or fake CGISESSID.
624
625You are strongly advised to run the old-fashioned 'make test TEST_FILES=t/new_with_undef.t TEST_VERBOSE=1'
626or the new-fangled 'prove -v t/new_with_undef.t', for both new*.t and load*.t, and examine the output.
627
628=cut
629
630# pass a true value as the fourth parameter if you want to skip the changing of
631# access time This isn't documented more formally, because it only called by
632# find().
633sub load {
634    my $class = shift;
635    return $class->set_error( "called as instance method")    if ref $class;
636    return $class->set_error( "Too many arguments provided to load()")  if @_ > 5;
637
638    my $self = bless {
639        _DATA       => {
640            _SESSION_ID     => undef,
641            _SESSION_CTIME  => undef,
642            _SESSION_ATIME  => undef,
643            _SESSION_REMOTE_ADDR => $ENV{REMOTE_ADDR} || "",
644            #
645            # Following two attributes may not exist in every single session, and declaring
646            # them now will force these to get serialized into database, wasting space. But they
647            # are here to remind the coder of their purpose
648            #
649#            _SESSION_ETIME  => undef,
650#            _SESSION_EXPIRE_LIST => {}
651        },          # session data
652        _DSN        => {},          # parsed DSN params
653        _OBJECTS    => {},          # keeps necessary objects
654        _DRIVER_ARGS=> {},          # arguments to be passed to driver
655        _CLAIMED_ID => undef,       # id **claimed** by client
656        _STATUS     => STATUS_UNSET,# status of the session object
657        _QUERY      => undef        # query object
658    }, $class;
659
660    my ($dsn,$query_or_sid,$dsn_args,$read_only,$params);
661    # load($query||$sid)
662    if ( @_ == 1 ) {
663        $self->_set_query_or_sid($_[0]);
664    }
665    # Two or more args passed:
666    # load($dsn, $query||$sid)
667    elsif ( @_ > 1 ) {
668        ($dsn, $query_or_sid, $dsn_args,$read_only) = @_;
669
670        # Make it backwards-compatible (update_atime is an undocumented key in %$params).
671        # In fact, update_atime as a key is not used anywhere in the code as yet.
672        # This patch is part of the patch for RT#33437.
673        if ( ref $read_only and ref $read_only eq 'HASH' ) {
674            $params = {%$read_only};
675            $read_only = $params->{'read_only'};
676
677            if ($params->{'name'}) {
678                $self->{_NAME} = $params->{'name'};
679            }
680        }
681
682        # Since $read_only is not part of the public API
683        # we ignore any value but the one we use internally: 1.
684        if (defined $read_only and $read_only != '1') {
685            return $class->set_error( "Too many arguments to load(). First extra argument was: $read_only");
686         }
687
688        if ( defined $dsn ) {      # <-- to avoid 'Uninitialized value...' warnings
689            $self->{_DSN} = $self->parse_dsn($dsn);
690        }
691        $self->_set_query_or_sid($query_or_sid);
692
693        # load($dsn, $query, \%dsn_args);
694
695        $self->{_DRIVER_ARGS} = $dsn_args if defined $dsn_args;
696
697    }
698
699    $self->_load_pluggables();
700
701    # Did load_pluggable fail? If so, return undef, just like $class->set_error() would
702    return undef if $class->errstr;
703
704    if (not defined $self->{_CLAIMED_ID}) {
705        my $query = $self->query();
706        eval {
707            $self->{_CLAIMED_ID} = $query->cookie( $self->name ) || $query->param( $self->name );
708        };
709        if ( my $errmsg = $@ ) {
710            return $class->set_error( "query object $query does not support cookie() and param() methods: " .  $errmsg );
711        }
712    }
713
714    # No session is being requested. Just return an empty session
715    return $self unless $self->{_CLAIMED_ID};
716
717    # Attempting to load the session
718    my $driver = $self->_driver();
719    my $raw_data = $driver->retrieve( $self->{_CLAIMED_ID} );
720    unless ( defined $raw_data ) {
721        return $self->set_error( "load(): couldn't retrieve data: " . $driver->errstr );
722    }
723
724    # Requested session couldn't be retrieved
725    return $self unless $raw_data;
726
727    my $serializer = $self->_serializer();
728    $self->{_DATA} = $serializer->thaw($raw_data);
729    unless ( defined $self->{_DATA} ) {
730        #die $raw_data . "\n";
731        return $self->set_error( "load(): couldn't thaw() data using $serializer:" .
732                                $serializer->errstr );
733    }
734    unless (defined($self->{_DATA}) && ref ($self->{_DATA}) && (ref $self->{_DATA} eq 'HASH') &&
735            defined($self->{_DATA}->{_SESSION_ID}) ) {
736        return $self->set_error( "Invalid data structure returned from thaw()" );
737    }
738
739
740    # checking for expiration ticker
741    if ( $self->{_DATA}->{_SESSION_ETIME} ) {
742        if ( ($self->{_DATA}->{_SESSION_ATIME} + $self->{_DATA}->{_SESSION_ETIME}) <= time() ) {
743            $self->_set_status( STATUS_EXPIRED |    # <-- so client can detect expired sessions
744                STATUS_DELETED );                   # <-- session should be removed from database
745            $self->flush();                         # <-- flush() will do the actual removal!
746            return $self;
747        }
748    }
749
750    # checking expiration tickers of individuals parameters, if any:
751    my @expired_params = ();
752    if ( $self->{_DATA}->{_SESSION_EXPIRE_LIST} ) {
753        while (my ($param, $max_exp_interval) = each %{ $self->{_DATA}->{_SESSION_EXPIRE_LIST} } ) {
754            if ( ($self->{_DATA}->{_SESSION_ATIME} + $max_exp_interval) <= time() ) {
755                push @expired_params, $param;
756            }
757        }
758    }
759    $self->clear(\@expired_params) if @expired_params;
760
761
762
763    if (not defined $read_only) {
764        # checking if previous session ip matches current ip
765        if($CGI::Session::IP_MATCH) {
766            unless($self->ip_matches) {
767                $self->_set_status( STATUS_DELETED );
768                $self->flush;
769                return $self;
770            }
771        }
772
773        $self->{_DATA}->{_SESSION_ATIME} = time();      # <-- updating access time
774        $self->_set_status( STATUS_MODIFIED );          # <-- access time modified above
775    }
776
777    return $self;
778}
779
780
781# set the input as a query object or session ID, depending on what it looks like.
782sub _set_query_or_sid {
783    my $self = shift;
784    my $query_or_sid = shift;
785    if ( ref $query_or_sid){ $self->{_QUERY}       = $query_or_sid  }
786    else                   { $self->{_CLAIMED_ID}  = $query_or_sid  }
787}
788
789
790sub _load_pluggables {
791    my ($self) = @_;
792
793    my %DEFAULT_FOR = (
794                       driver     => "file",
795                       serializer => "default",
796                       id         => "md5",
797                       );
798    my %SUBDIR_FOR  = (
799                       driver     => "Driver",
800                       serializer => "Serialize",
801                       id         => "ID",
802                       );
803    my $dsn = $self->{_DSN};
804    for my $plug (qw(driver serializer id)) {
805        my $mod_name = $dsn->{ $plug };
806        if (not defined $mod_name) {
807            $mod_name = $DEFAULT_FOR{ $plug };
808        }
809        if ($mod_name =~ /^(\w+)$/) {
810
811            # Looks good.  Put it into the dsn hash
812            $dsn->{ $plug } = $mod_name = $1;
813
814            # Put together the actual module name to load
815            my $prefix = join '::', (__PACKAGE__, $SUBDIR_FOR{ $plug }, q{});
816            $mod_name = $prefix . $mod_name;
817
818            ## See if we can load load it
819            eval "require $mod_name";
820            if ($@) {
821                my $msg = $@;
822                return $self->set_error("couldn't load $mod_name: " . $msg);
823            }
824        }
825        else {
826            # do something here about bad name for a pluggable
827        }
828    }
829    return;
830}
831
832=pod
833
834=head2 id()
835
836Returns effective ID for a session. Since effective ID and claimed ID can differ, valid session id should always
837be retrieved using this method.
838
839=head2 param($name)
840
841=head2 param(-name=E<gt>$name)
842
843Used in either of the above syntax returns a session parameter set to $name or undef if it doesn't exist. If it's called on a deleted method param() will issue a warning but return value is not defined.
844
845=head2 param($name, $value)
846
847=head2 param(-name=E<gt>$name, -value=E<gt>$value)
848
849Used in either of the above syntax assigns a new value to $name parameter,
850which can later be retrieved with previously introduced param() syntax. C<$value>
851may be a scalar, arrayref or hashref.
852
853Attempts to set parameter names that start with I<_SESSION_> will trigger
854a warning and undef will be returned.
855
856=head2 param_hashref()
857
858B<Deprecated>. Use L<dataref()|/"dataref()"> instead.
859
860=head2 dataref()
861
862Returns reference to session's data table:
863
864    $params = $s->dataref();
865    $sid = $params->{_SESSION_ID};
866    $name= $params->{name};
867    # etc...
868
869Useful for having all session data in a hashref, but too risky to update.
870
871=head2 save_param()
872
873=head2 save_param($query)
874
875=head2 save_param($query, \@list)
876
877Saves query parameters to session object. In other words, it's the same as calling L<param($name, $value)|/"param($name)"> for every single query parameter returned by C<< $query->param() >>. The first argument, if present, should be either CGI object or any object which can provide param() method. If it's undef, defaults to the return value of L<query()|/"query()">, which returns C<< CGI->new >>. If second argument is present and is a reference to an array, only those query parameters found in the array will be stored in the session. undef is a valid placeholder for any argument to force default behavior.
878
879=head2 load_param()
880
881=head2 load_param($query)
882
883=head2 load_param($query, \@list)
884
885Loads session parameters into a query object. The first argument, if present, should be query object, or any other object which can provide param() method. If second argument is present and is a reference to an array, only parameters found in that array will be loaded to the query object.
886
887=head2 clear()
888
889=head2 clear('field')
890
891=head2 clear(\@list)
892
893Clears parameters from the session object.
894
895With no parameters, all fields are cleared. If passed a single parameter or a
896reference to an array, only the named parameters are cleared.
897
898=head2 flush()
899
900Synchronizes data in memory with the copy serialized by the driver. Call flush()
901if you need to access the session from outside the current session object. You should
902call flush() sometime before your program exits.
903
904As a last resort, CGI::Session will automatically call flush for you just
905before the program terminates or session object goes out of scope. Automatic
906flushing has proven to be unreliable, and in some cases is now required
907in places that worked with CGI::Session 3.x.
908
909Always explicitly calling C<flush()> on the session before the
910program exits is recommended. For extra safety, call it immediately after
911every important session update.
912
913Also see L<A Warning about Auto-flushing>
914
915=head2 atime()
916
917Read-only method. Returns the last access time of the session in seconds from epoch. This time is used internally while
918auto-expiring sessions and/or session parameters.
919
920=head2 ctime()
921
922Read-only method. Returns the time when the session was first created in seconds from epoch.
923
924=head2 expire()
925
926=head2 expire($time)
927
928=head2 expire($param, $time)
929
930Sets expiration interval relative to L<atime()|/"atime()">.
931
932If used with no arguments, returns the expiration interval if it was ever set. If no expiration was ever set, returns undef. For backwards compatibility, a method named C<etime()> does the same thing.
933
934Second form sets an expiration time. This value is checked when previously stored session is asked to be retrieved, and if its expiration interval has passed, it will be expunged from the disk immediately. Passing 0 cancels expiration.
935
936By using the third syntax you can set the expiration interval for a particular
937session parameter, say I<~logged-in>. This would cause the library call clear()
938on the parameter when its time is up. Note it only makes sense to set this value to
939something I<earlier> than when the whole session expires.  Passing 0 cancels expiration.
940
941All the time values should be given in the form of seconds. Following keywords are also supported for your convenience:
942
943    +-----------+---------------+
944    |   alias   |   meaning     |
945    +-----------+---------------+
946    |     s     |   Second      |
947    |     m     |   Minute      |
948    |     h     |   Hour        |
949    |     d     |   Day         |
950    |     w     |   Week        |
951    |     M     |   Month       |
952    |     y     |   Year        |
953    +-----------+---------------+
954
955Examples:
956
957    $session->expire("2h");                # expires in two hours
958    $session->expire(0);                   # cancel expiration
959    $session->expire("~logged-in", "10m"); # expires '~logged-in' parameter after 10 idle minutes
960
961Note: all the expiration times are relative to session's last access time, not to its creation time. To expire a session immediately, call L<delete()|/"delete">. To expire a specific session parameter immediately, call L<clear([$name])|/"clear">.
962
963=cut
964
965*expires = \&expire;
966my $prevent_warning = \&expires;
967sub etime           { $_[0]->expire()  }
968sub expire {
969    my $self = shift;
970
971    # no params, just return the expiration time.
972    if (not @_) {
973        return $self->{_DATA}->{_SESSION_ETIME};
974    }
975    # We have just a time
976    elsif ( @_ == 1 ) {
977        my $time = $_[0];
978        # If 0 is passed, cancel expiration
979        if ( defined $time && ($time =~ m/^\d$/) && ($time == 0) ) {
980            $self->{_DATA}->{_SESSION_ETIME} = undef;
981            $self->_set_status( STATUS_MODIFIED );
982        }
983        # set the expiration to this time
984        else {
985            $self->{_DATA}->{_SESSION_ETIME} = $self->_str2seconds( $time );
986            $self->_set_status( STATUS_MODIFIED );
987        }
988    }
989    # If we get this far, we expect expire($param,$time)
990    # ( This would be a great use of a Perl6 multi sub! )
991    else {
992        my ($param, $time) = @_;
993        if ( ($time =~ m/^\d$/) && ($time == 0) ) {
994            delete $self->{_DATA}->{_SESSION_EXPIRE_LIST}->{ $param };
995            $self->_set_status( STATUS_MODIFIED );
996        } else {
997            $self->{_DATA}->{_SESSION_EXPIRE_LIST}->{ $param } = $self->_str2seconds( $time );
998            $self->_set_status( STATUS_MODIFIED );
999        }
1000    }
1001    return 1;
1002}
1003
1004# =head2 _str2seconds()
1005#
1006# my $secs = $self->_str2seconds('1d')
1007#
1008# Takes a CGI.pm-style time representation and returns an equivalent number
1009# of seconds.
1010#
1011# See the docs of expire() for more detail.
1012#
1013# =cut
1014
1015sub _str2seconds {
1016    my $self = shift;
1017    my ($str) = @_;
1018
1019    return unless defined $str;
1020    return $str if $str =~ m/^[-+]?\d+$/;
1021
1022    my %_map = (
1023        s       => 1,
1024        m       => 60,
1025        h       => 3600,
1026        d       => 86400,
1027        w       => 604800,
1028        M       => 2592000,
1029        y       => 31536000
1030    );
1031
1032    my ($koef, $d) = $str =~ m/^([+-]?\d+)([smhdwMy])$/;
1033    unless ( defined($koef) && defined($d) ) {
1034        die "_str2seconds(): couldn't parse '$str' into \$koef and \$d parts. Possible invalid syntax";
1035    }
1036    return $koef * $_map{ $d };
1037}
1038
1039
1040=pod
1041
1042=head2 is_new()
1043
1044Returns true only for a brand new session.
1045
1046=head2 is_expired()
1047
1048Tests whether session initialized using L<load()|/"load"> is to be expired. This method works only on sessions initialized with load():
1049
1050    $s = CGI::Session->load() or die CGI::Session->errstr;
1051    if ( $s->is_expired ) {
1052        die "Your session expired. Please refresh";
1053    }
1054    if ( $s->is_empty ) {
1055        $s = $s->new() or die $s->errstr;
1056    }
1057
1058
1059=head2 is_empty()
1060
1061Returns true for sessions that are empty. It's preferred way of testing whether requested session was loaded successfully or not:
1062
1063    $s = CGI::Session->load($sid);
1064    if ( $s->is_empty ) {
1065        $s = $s->new();
1066    }
1067
1068Actually, the above code is nothing but waste. The same effect could've been achieved by saying:
1069
1070    $s = CGI::Session->new( $sid );
1071
1072L<is_empty()|/"is_empty"> is useful only if you wanted to catch requests for expired sessions, and create new session afterwards. See L<is_expired()|/"is_expired"> for an example.
1073
1074=head2 ip_match()
1075
1076Returns true if $ENV{REMOTE_ADDR} matches the remote address stored in the session.
1077
1078If you have an application where you are sure your users' IPs are constant
1079during a session, you can consider enabling an option to make this check:
1080
1081    use CGI::Session '-ip_match';
1082
1083Usually you don't call ip_match() directly, but by using the above method. It is useful
1084only if you want to call it inside of coderef passed to the L<find()|/"find( \&code )"> method.
1085
1086=head2 delete()
1087
1088Sets the objects status to be "deleted".  Subsequent read/write requests on the
1089same object will fail.  To physically delete it from the data store you need to call L<flush()|/"flush()">.
1090CGI::Session attempts to do this automatically when the object is being destroyed (usually as
1091the script exits), but see L<A Warning about Auto-flushing>.
1092
1093=head2 find( \&code )
1094
1095=head2 find( $dsn, \&code )
1096
1097=head2 find( $dsn, \&code, \%dsn_args )
1098
1099Experimental feature. Executes \&code for every session object stored in disk, passing initialized CGI::Session object as the first argument of \&code. Useful for housekeeping purposes, such as for removing expired sessions. Following line, for instance, will remove sessions already expired, but are still in disk:
1100
1101The following line, for instance, will remove sessions already expired, but which are still on disk:
1102
1103    CGI::Session->find( sub {} );
1104
1105Notice, above \&code didn't have to do anything, because load(), which is called to initialize sessions inside L<find()|/"find( \&code )">, will automatically remove expired sessions. Following example will remove all the objects that are 10+ days old:
1106
1107    CGI::Session->find( \&purge );
1108    sub purge {
1109        my ($session) = @_;
1110        next if $session->is_empty;    # <-- already expired?!
1111        if ( ($session->ctime + 3600*240) <= time() ) {
1112            $session->delete();
1113            $session->flush(); # Recommended practice says use flush() after delete().
1114        }
1115    }
1116
1117B<Note>: find will not change the modification or access times on the sessions it returns.
1118
1119Explanation of the 3 parameters to C<find()>:
1120
1121=over 4
1122
1123=item $dsn
1124
1125This is the DSN (Data Source Name) used by CGI::Session to control what type of
1126sessions you previously created and what type of sessions you now wish method
1127C<find()> to pass to your callback.
1128
1129The default value is defined above, in the docs for method C<new()>, and is
1130'driver:file;serializer:default;id:md5'.
1131
1132Do not confuse this DSN with the DSN arguments mentioned just below, under \%dsn_args.
1133
1134=item \&code
1135
1136This is the callback provided by you (i.e. the caller of method C<find()>)
1137which is called by CGI::Session once for each session found by method C<find()>
1138which matches the given $dsn.
1139
1140There is no default value for this coderef.
1141
1142When your callback is actually called, the only parameter is a session. If you
1143want to call a subroutine you already have with more parameters, you can
1144achieve this by creating an anonymous subroutine that calls your subroutine
1145with the parameters you want. For example:
1146
1147    CGI::Session->find($dsn, sub { my_subroutine( @_, 'param 1', 'param 2' ) } );
1148    CGI::Session->find($dsn, sub { $coderef->( @_, $extra_arg ) } );
1149
1150Or if you wish, you can define a sub generator as such:
1151
1152    sub coderef_with_args {
1153        my ( $coderef, @params ) = @_;
1154        return sub { $coderef->( @_, @params ) };
1155    }
1156
1157    CGI::Session->find($dsn, coderef_with_args( $coderef, 'param 1', 'param 2' ) );
1158
1159=item \%dsn_args
1160
1161If your $dsn uses file-based storage, then this hashref might contain keys such as:
1162
1163    {
1164        Directory => Value 1,
1165        NoFlock   => Value 2,
1166        UMask     => Value 3
1167    }
1168
1169If your $dsn uses db-based storage, then this hashref contains (up to) 3 keys, and looks like:
1170
1171    {
1172        DataSource => Value 1,
1173        User       => Value 2,
1174        Password   => Value 3
1175    }
1176
1177These 3 form the DSN, username and password used by DBI to control access to your database server,
1178and hence are only relevant when using db-based sessions.
1179
1180The default value of this hashref is undef.
1181
1182=back
1183
1184B<Note:> find() is meant to be convenient, not necessarily efficient. It's best suited in cron scripts.
1185
1186=head2 name($new_name)
1187
1188The $new_name parameter is optional. If supplied it sets the query or cookie parameter name to be used.
1189
1190It defaults to I<$CGI::Session::NAME>, which defaults to I<CGISESSID>.
1191
1192You are strongly discouraged from using the global variable I<$CGI::Session::NAME>, since it is
1193deprecated (as are all global variables) and will be removed in a future version of this module.
1194
1195Return value: The current query or cookie parameter name.
1196
1197=head1 MISCELLANEOUS METHODS
1198
1199=head2 remote_addr()
1200
1201Returns the remote address of the user who created the session for the first time. Returns undef if variable REMOTE_ADDR wasn't present in the environment when the session was created.
1202
1203=cut
1204
1205sub remote_addr {   return $_[0]->{_DATA}->{_SESSION_REMOTE_ADDR}   }
1206
1207=pod
1208
1209=head2 errstr()
1210
1211Class method. Returns last error message from the library.
1212
1213=head2 dump()
1214
1215Returns a dump of the session object. Useful for debugging purposes only.
1216
1217=head2 header()
1218
1219A wrapper for C<CGI>'s header() method. Calling this method
1220is equivalent to something like this:
1221
1222    $cookie = CGI::Cookie->new(-name=>$session->name, -value=>$session->id);
1223    print $cgi->header(-cookie=>$cookie, @_);
1224
1225You can minimize the above into:
1226
1227    print $session->header();
1228
1229It will retrieve the name of the session cookie from C<$session->name()> which defaults to C<$CGI::Session::NAME>. If you want to use a different name for your session cookie, do something like this before creating session object:
1230
1231    CGI::Session->name("MY_SID");
1232    $session = CGI::Session->new(undef, $cgi, \%attrs);
1233
1234Now, $session->header() uses "MY_SID" as the name for the session cookie. For all additional options that can
1235be passed, see the C<header()> docs in C<CGI>.
1236
1237=head2 query()
1238
1239Returns query object associated with current session object. Default query object class is C<CGI>.
1240
1241=head2 DEPRECATED METHODS
1242
1243These methods exist solely for for compatibility with CGI::Session 3.x.
1244
1245=head3 close()
1246
1247Closes the session. Using flush() is recommended instead, since that's exactly what a call
1248to close() does now.
1249
1250=head1 DISTRIBUTION
1251
1252CGI::Session consists of several components such as L<drivers|"DRIVERS">, L<serializers|"SERIALIZERS"> and L<id generators|"ID GENERATORS">. This section lists what is available.
1253
1254=head2 DRIVERS
1255
1256The following drivers are included in the standard distribution:
1257
1258=over 4
1259
1260=item *
1261
1262L<file|CGI::Session::Driver::file> - default driver for storing session data in plain files. Full name: B<CGI::Session::Driver::file>
1263
1264=item *
1265
1266L<db_file|CGI::Session::Driver::db_file> - for storing session data in BerkelyDB. Requires: L<DB_File>.
1267Full name: B<CGI::Session::Driver::db_file>
1268
1269=item *
1270
1271L<mysql|CGI::Session::Driver::mysql> - for storing session data in MySQL tables. Requires L<DBI|DBI> and L<DBD::mysql|DBD::mysql>.
1272Full name: B<CGI::Session::Driver::mysql>
1273
1274=item *
1275
1276L<sqlite|CGI::Session::Driver::sqlite> - for storing session data in SQLite. Requires L<DBI|DBI> and L<DBD::SQLite|DBD::SQLite>.
1277Full name: B<CGI::Session::Driver::sqlite>
1278
1279=back
1280
1281Other drivers are available from CPAN.
1282
1283=head2 SERIALIZERS
1284
1285=over 4
1286
1287=item *
1288
1289L<default|CGI::Session::Serialize::default> - default data serializer. Uses standard L<Data::Dumper|Data::Dumper>.
1290Full name: B<CGI::Session::Serialize::default>.
1291
1292=item *
1293
1294L<storable|CGI::Session::Serialize::storable> - serializes data using L<Storable>. Requires L<Storable>.
1295Full name: B<CGI::Session::Serialize::storable>.
1296
1297=item *
1298
1299L<freezethaw|CGI::Session::Serialize::freezethaw> - serializes data using L<FreezeThaw>. Requires L<FreezeThaw>.
1300Full name: B<CGI::Session::Serialize::freezethaw>
1301
1302=item *
1303
1304L<yaml|CGI::Session::Serialize::yaml> - serializes data using YAML. Requires L<YAML> or L<YAML::Syck>.
1305Full name: B<CGI::Session::Serialize::yaml>
1306
1307=back
1308
1309=head2 ID GENERATORS
1310
1311The following ID generators are included in the standard distribution.
1312
1313=over 4
1314
1315=item *
1316
1317L<md5|CGI::Session::ID::md5> - generates 32 character long hexadecimal string. Requires L<Digest::MD5|Digest::MD5>.
1318Full name: B<CGI::Session::ID::md5>.
1319
1320=item *
1321
1322L<incr|CGI::Session::ID::incr> - generates incremental session ids.
1323
1324=item *
1325
1326L<static|CGI::Session::ID::static> - generates static session ids. B<CGI::Session::ID::static>
1327
1328=back
1329
1330=head1 A Warning about Auto-flushing
1331
1332Auto-flushing can be unreliable for the following reasons. Explicit flushing
1333after key session updates is recommended.
1334
1335=over 4
1336
1337=item If the C<DBI> handle goes out of scope before the session variable
1338
1339For database-stored sessions, if the C<DBI> handle has gone out of scope before
1340the auto-flushing happens, auto-flushing will fail.
1341
1342=item Circular references
1343
1344If the calling code contains a circular reference, it's possible that your
1345C<CGI::Session> object will not be destroyed until it is too late for
1346auto-flushing to work. You can find circular references with a tool like
1347L<Devel::Cycle>.
1348
1349In particular, these modules are known to contain circular references which
1350lead to this problem:
1351
1352=over 4
1353
1354=item CGI::Application::Plugin::DebugScreen V 0.06
1355
1356=item CGI::Application::Plugin::ErrorPage before version 1.20
1357
1358=back
1359
1360=item Signal handlers
1361
1362If your application may receive signals, there is an increased chance that the
1363signal will arrive after the session was updated but before it is auto-flushed
1364at object destruction time.
1365
1366=back
1367
1368=head1 A Warning about UTF8
1369
1370You are strongly encouraged to refer to, at least, the first of these articles, for help with UTF8.
1371
1372L<http://en.wikibooks.org/wiki/Perl_Programming/Unicode_UTF-8>
1373
1374L<http://perl.bristolbath.org/blog/lyle/2008/12/giving-cgiapplication-internationalization-i18n.html>
1375
1376L<http://metsankulma.homelinux.net/cgi-bin/l10n_example_4/main.cgi>
1377
1378L<http://rassie.org/archives/247>
1379
1380L<http://www.di-mgt.com.au/cryptoInternational2.html>
1381
1382Briefly, these are the issues:
1383
1384=over 4
1385
1386=item The file containing the source code of your program
1387
1388Consider "use utf8;" or "use encoding 'utf8';".
1389
1390=item Influencing the encoding of the program's input
1391
1392Use:
1393
1394    binmode STDIN, ":encoding(utf8)";.
1395
1396    Of course, the program can get input from other sources, e.g. HTML template files, not just STDIN.
1397
1398=item Influencing the encoding of the program's output
1399
1400Use:
1401
1402    binmode STDOUT, ":encoding(utf8)";
1403
1404    When using CGI.pm, you can use $q->charset('UTF-8'). This is the same as passing 'UTF-8' to CGI's C<header()> method.
1405
1406    Alternately, when using CGI::Session, you can use $session->header(charset => 'utf-8'), which will be
1407    passed to the query object's C<header()> method. Clearly this is preferable when the query object might not be
1408    of type CGI.
1409
1410    See L</header()> for a fuller discussion of the use of the C<header()> method in conjunction with cookies.
1411
1412=back
1413
1414=head1 TRANSLATIONS
1415
1416This document is also available in Japanese.
1417
1418=over 4
1419
1420=item o
1421
1422Translation based on 4.14: http://digit.que.ne.jp/work/index.cgi?Perldoc/ja
1423
1424=item o
1425
1426Translation based on 3.11, including Cookbook and Tutorial: http://perldoc.jp/docs/modules/CGI-Session-3.11/
1427
1428=back
1429
1430=head1 CREDITS
1431
1432CGI::Session evolved to what it is today with the help of following developers. The list doesn't follow any strict order, but somewhat chronological. Specifics can be found in F<Changes> file
1433
1434=over 4
1435
1436=item Andy Lester
1437
1438=item Brian King E<lt>mrbbking@mac.comE<gt>
1439
1440=item Olivier Dragon E<lt>dragon@shadnet.shad.caE<gt>
1441
1442=item Adam Jacob E<lt>adam@sysadminsith.orgE<gt>
1443
1444=item Igor Plisco E<lt>igor@plisco.ruE<gt>
1445
1446=item Mark Stosberg
1447
1448=item Matt LeBlanc E<lt>mleblanc@cpan.orgE<gt>
1449
1450=item Shawn Sorichetti
1451
1452=item Ron Savage
1453
1454=item Rhesa Rozendaal
1455
1456He suggested Devel::Cycle to help debugging.
1457
1458=back
1459
1460Also, many people on the CGI::Application and CGI::Session mailing lists have contributed ideas and
1461suggestions, and battled publicly with bugs, all of which has helped.
1462
1463=head1 COPYRIGHT
1464
1465Copyright (C) 2001-2005 Sherzod Ruzmetov E<lt>sherzodr@cpan.orgE<gt>. All rights reserved.
1466This library is free software. You can modify and or distribute it under the same terms as Perl itself.
1467
1468=head1 PUBLIC CODE REPOSITORY
1469
1470You can see what the developers have been up to since the last release by
1471checking out the code repository. You can browse the git repository from here:
1472
1473 http://github.com/cromedome/cgi-session/tree/master
1474
1475Or check out the code with:
1476
1477 git clone git://github.com/cromedome/cgi-session.git
1478
1479=head1 SUPPORT
1480
1481If you need help using CGI::Session, ask on the mailing list. You can ask the
1482list by sending your questions to cgi-session-user@lists.sourceforge.net .
1483
1484You can subscribe to the mailing list at https://lists.sourceforge.net/lists/listinfo/cgi-session-user .
1485
1486Bug reports can be submitted at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=CGI-Session
1487
1488=head1 AUTHOR
1489
1490Sherzod Ruzmetov C<sherzodr@cpan.org>
1491
1492Mark Stosberg became a co-maintainer during the development of 4.0. C<markstos@cpan.org>.
1493
1494Ron Savage became a co-maintainer during the development of 4.30. C<rsavage@cpan.org>.
1495
1496If you would like support, ask on the mailing list as describe above. The
1497maintainers and other users are subscribed to it.
1498
1499=head1 SEE ALSO
1500
1501To learn more both about the philosophy and CGI::Session programming style,
1502consider the following:
1503
1504=over 4
1505
1506=item *
1507
1508L<CGI::Session::Tutorial|CGI::Session::Tutorial> - extended CGI::Session manual. Also includes library architecture and driver specifications.
1509
1510=item *
1511
1512We also provide mailing lists for CGI::Session users. To subscribe to the list
1513or browse the archives visit
1514https://lists.sourceforge.net/lists/listinfo/cgi-session-user
1515
1516=item * B<RFC 2109> - The primary spec for cookie handing in use, defining the  "Cookie:" and "Set-Cookie:" HTTP headers.
1517Available at L<http://www.ietf.org/rfc/rfc2109.txt>. A newer spec, RFC 2965 is meant to obsolete it with "Set-Cookie2"
1518and "Cookie2" headers, but even of 2008, the newer spec is not widely supported. See L<http://www.ietf.org/rfc/rfc2965.txt>
1519
1520=item *
1521
1522L<Apache::Session|Apache::Session> - an alternative to CGI::Session.
1523
1524=back
1525
1526=cut
1527
15281;
1529
1530