line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl -s |
2
|
|
|
|
|
|
|
## |
3
|
|
|
|
|
|
|
## CGI::Persistent |
4
|
|
|
|
|
|
|
## |
5
|
|
|
|
|
|
|
## Copyright (c) 1998, Vipul Ved Prakash. All Rites Reversed. |
6
|
|
|
|
|
|
|
## This code is free software; you can redistribute it and/or modify |
7
|
|
|
|
|
|
|
## it under the same terms as Perl itself. |
8
|
|
|
|
|
|
|
## |
9
|
|
|
|
|
|
|
## $Id: Persistent.pm,v 0.21 1999/12/07 04:18:30 root Exp root $ |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
package CGI::Persistent; |
12
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
24142
|
use CGI '-no_xhtml'; |
|
1
|
|
|
|
|
40926
|
|
|
1
|
|
|
|
|
7
|
|
14
|
1
|
|
|
1
|
|
2402
|
use Persistence::Object::Simple; |
|
1
|
|
|
|
|
14729
|
|
|
1
|
|
|
|
|
36
|
|
15
|
1
|
|
|
1
|
|
8
|
use vars qw(@ISA $VERSION); |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
50
|
|
16
|
1
|
|
|
1
|
|
6
|
use Data::Dumper; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
49
|
|
17
|
1
|
|
|
1
|
|
6
|
use File::Basename; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
880
|
|
18
|
|
|
|
|
|
|
@ISA = qw( CGI ); |
19
|
|
|
|
|
|
|
$VERSION = '1.11'; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub new { |
22
|
|
|
|
|
|
|
|
23
|
0
|
|
|
0
|
1
|
|
my ( $class, $dope, $id ) = @_ ; |
24
|
0
|
0
|
|
|
|
|
$dope = "." unless $dope; |
25
|
0
|
|
|
|
|
|
my $cgi = new CGI; # print $cgi->header (); |
26
|
0
|
|
0
|
|
|
|
my $fn = fileparse($cgi->param( '.id' ) || $id || ''); |
27
|
|
|
|
|
|
|
|
28
|
0
|
0
|
|
|
|
|
unless ( $fn ) { |
29
|
0
|
|
|
|
|
|
my $po = new Persistence::Object::Simple ( __Dope => $dope ); |
30
|
0
|
|
|
|
|
|
$fn = fileparse $po->{ __Fn }; |
31
|
0
|
|
|
|
|
|
$cgi->append( -name => '.id', -values => $fn ); |
32
|
0
|
|
|
|
|
|
undef $po; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
0
|
|
|
|
|
|
my $po = new Persistence::Object::Simple __Fn => "$dope/$fn"; |
36
|
0
|
|
|
|
|
|
$po->{ __DOPE } = undef; |
37
|
0
|
|
|
|
|
|
$po->{sessiondir} = $dope; |
38
|
0
|
|
|
|
|
|
my @names = $cgi->param (); |
39
|
|
|
|
|
|
|
|
40
|
0
|
|
|
|
|
|
my $st = $cgi->param('.sailthru'); |
41
|
0
|
0
|
|
|
|
|
unless ( $st ) { |
42
|
0
|
0
|
|
|
|
|
for ( @names ) { $po->{$_} = $cgi->param( $_ ) unless $_ eq ".id" } |
|
0
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
0
|
|
|
|
|
|
foreach $key ( keys %$po ) { |
46
|
0
|
0
|
0
|
|
|
|
$cgi->param( -name => $key, -values => $po->{$key} ) |
47
|
|
|
|
|
|
|
unless ( grep /$key/, @names ) || $key eq "__Fn"; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
$cgi->{sessiondir} = $po->{sessiondir}; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# Stringify the params. This is black magic to work around an interpreter |
53
|
|
|
|
|
|
|
# crash in Data::Dumper. |
54
|
0
|
|
|
|
|
|
foreach my $param ($cgi->param) |
55
|
|
|
|
|
|
|
{ |
56
|
0
|
|
|
|
|
|
my $s = "param $param is " . $cgi->param($param) . "\n"; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
$po->commit (); |
60
|
0
|
|
|
|
|
|
return bless $cgi, $class; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub delete { |
65
|
|
|
|
|
|
|
|
66
|
0
|
|
|
0
|
1
|
|
my ( $self, $param ) = @_; |
67
|
0
|
|
|
|
|
|
my $fn = join "/", ($self->{sessiondir},$self->param( '.id' )); |
68
|
0
|
|
|
|
|
|
my $po = new Persistence::Object::Simple __Fn => $fn; |
69
|
0
|
|
|
|
|
|
delete $po->{ $param }; $po->commit (); |
|
0
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
|
$self->SUPER::delete ( $param ); # delete, is like, overloaded. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub delete_all { |
75
|
|
|
|
|
|
|
|
76
|
0
|
|
|
0
|
1
|
|
my ( $self ) = shift; |
77
|
0
|
|
|
|
|
|
$fn = join "/", ($self->{sessiondir},$self->param( '.id' )); |
78
|
0
|
|
|
|
|
|
my $po = new Persistence::Object::Simple __Fn => $fn; |
79
|
0
|
|
|
|
|
|
$po->expire; |
80
|
0
|
|
|
|
|
|
$self->SUPER::delete_all (); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub state_url { |
85
|
|
|
|
|
|
|
|
86
|
0
|
|
|
0
|
1
|
|
my ( $self ) = @_; |
87
|
0
|
|
|
|
|
|
return $self->url ."?.id=".$self->param('.id'); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub state_url_thru { |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
0
|
0
|
|
my ( $self ) = @_; |
94
|
0
|
|
|
|
|
|
return $self->url ."?.id=".$self->param('.id')."&.sailthru=1"; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub state_field { |
99
|
|
|
|
|
|
|
|
100
|
0
|
|
|
0
|
1
|
|
my ( $self ) = @_; |
101
|
0
|
|
0
|
|
|
|
my $id = $self->param ( '.id' ) || ""; |
102
|
0
|
|
|
|
|
|
return ""; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub state_field_thru { |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
0
|
0
|
|
my ( $self ) = @_; |
109
|
0
|
|
|
|
|
|
my $id = $self->param ( '.id' ); |
110
|
0
|
|
|
|
|
|
return "" . "\n" . |
111
|
|
|
|
|
|
|
""; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
1; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head1 NAME |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
CGI::Persistent -- Transparent state persistence for CGI applications. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head1 SYNOPSIS |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
use CGI::Persistent; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
my $cgi = new CGI::Persistent "/directory"; |
126
|
|
|
|
|
|
|
print $cgi->header (); |
127
|
|
|
|
|
|
|
my $url = $cgi->state_url (); |
128
|
|
|
|
|
|
|
print "I am a persistent CGI session."; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=head1 SOLUTION TO THE STATELESS PROBLEM |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
HTTP is a stateless protocol; a HTTP server closes connection after |
133
|
|
|
|
|
|
|
serving an object. It retains no memory of the request details and doesn't |
134
|
|
|
|
|
|
|
relate subsequent requests with what it has already served. While this |
135
|
|
|
|
|
|
|
works well for static resources like HTML pages and image elements, |
136
|
|
|
|
|
|
|
complex user interactions often require state preservation across multiple |
137
|
|
|
|
|
|
|
requests and different parts of the web resource. Statefulness on a |
138
|
|
|
|
|
|
|
stateless server is achieved either through client-side mechanisms like |
139
|
|
|
|
|
|
|
Netscape cookies or with hidden fields in forms and value-attribute pairs |
140
|
|
|
|
|
|
|
in the URLs. State preserving URLs are more desirable, because they are |
141
|
|
|
|
|
|
|
independent of the client configuration, but tend to get unwieldy with |
142
|
|
|
|
|
|
|
increase in space complexity of the application. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
CGI::Persistent solves this problem by introducing persistent CGI sessions |
145
|
|
|
|
|
|
|
that store their state data on the server side. When a new session starts, |
146
|
|
|
|
|
|
|
CGI::Persistent automatically generates a unique state identification string |
147
|
|
|
|
|
|
|
and associates it with a persistent object on the server. The identification |
148
|
|
|
|
|
|
|
string is used in URLs or forms to refer to the particular session. Request |
149
|
|
|
|
|
|
|
attributes are transparently committed to the associated object and the |
150
|
|
|
|
|
|
|
object data is bound to the query. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
CGI::Persistent is derived from CGI.pm. CGI.pm methods have been overridden |
153
|
|
|
|
|
|
|
as appropriate. Very few new methods have been added. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head1 METHODS |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=over 4 |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item B |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Creates a new CGI object and binds it to its associated persistent state. |
162
|
|
|
|
|
|
|
A new state image is created if no associated state exists. new() takes |
163
|
|
|
|
|
|
|
two optional arguments. The first argument is the directory of |
164
|
|
|
|
|
|
|
persistence, the place where state information is stored. Ideally, this |
165
|
|
|
|
|
|
|
should be a separate directory dedicated to state files. When a directory |
166
|
|
|
|
|
|
|
is not specified, the current working directory is assumed. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
new() can also take a state id on the argument list instead of getting it |
169
|
|
|
|
|
|
|
from the query. This might be useful if you are using this module to store |
170
|
|
|
|
|
|
|
configuration data that you wish to retain across different sessions. |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Examples: |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
$q = new CGI::Persistent; |
175
|
|
|
|
|
|
|
$q = new CGI::Persistent "/sessions"; |
176
|
|
|
|
|
|
|
$q = new CGI::Persistent undef, "/sessions/924910985.134"; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=item B |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Returns a URL with the state identification string. This URL should be used |
181
|
|
|
|
|
|
|
for referring to the persistent session associated with the query. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item B |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
Returns a hidden INPUT type for inclusion in HTML forms. Like state_url(), |
186
|
|
|
|
|
|
|
this element is used in forms to refer to the associated persistent session. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=item B |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
delete() is an overridden method that deletes a named attribute from the |
192
|
|
|
|
|
|
|
query. The persistent object field associated with the attribute is |
193
|
|
|
|
|
|
|
also deleted. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Important note: Attributes that are NOT explicitly delete()ed will lurk |
196
|
|
|
|
|
|
|
about and come back to haunt you. Remember to clear control attributes and |
197
|
|
|
|
|
|
|
other context dependent fields that need clearing. See L. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=item B |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Another overridden method. Deletes all attributes as well as the persistent |
202
|
|
|
|
|
|
|
disk image of the session. This method should be used when you want to |
203
|
|
|
|
|
|
|
irrevocably destroy a session. See L. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=back |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head1 EXAMPLES |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
The accompanying CGI example, roach.cgi, illustrates the features of the |
210
|
|
|
|
|
|
|
module by implementing a multi-page input form. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=head1 SEE ALSO |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
CGI(3), |
215
|
|
|
|
|
|
|
Persistence::Object::Simple(3) |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 LICENSE |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
CGI::Persistent is distributed under the same license as Perl itself. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 REVISION HISTORY |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=over 4 |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item 1.00 Released 1998 |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item 1.10 Applies patches from folks at Mitel/SME server. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=back |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head1 AUTHOR |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
Vipul Ved Prakash, mail@vipul.net |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=cut |