File Coverage

blib/lib/Data/Session/Driver/File.pm
Criterion Covered Total %
statement 94 99 94.9
branch 27 78 34.6
condition 14 28 50.0
subroutine 16 16 100.0
pod 1 7 14.2
total 152 228 66.6


line stmt bran cond sub pod time code
1             package Data::Session::Driver::File;
2              
3 2     2   1789 use parent 'Data::Session::Base';
  2         3  
  2         19  
4 2     2   145 no autovivification;
  2         3  
  2         17  
5 2     2   98 use strict;
  2         3  
  2         79  
6 2     2   10 use warnings;
  2         4  
  2         85  
7              
8 2     2   41 use Fcntl qw/:DEFAULT :flock :mode/;
  2         4  
  2         1832  
9              
10 2     2   14 use File::Path;
  2         4  
  2         136  
11 2     2   11 use File::Spec;
  2         3  
  2         65  
12              
13 2     2   11 use Hash::FieldHash ':all';
  2         2  
  2         243  
14              
15 2     2   68 use Try::Tiny;
  2         3  
  2         5604  
16              
17             our $VERSION = '1.16';
18              
19             # -----------------------------------------------
20              
21             sub get_file_path
22             {
23 471     471 0 724 my($self, $sid) = @_;
24 471         989 (my $id = $sid) =~ s|\\|/|g;
25              
26 471 50       1272 ($id =~ m|/|) && die __PACKAGE__ . ". Session ids cannot contain \\ or /: '$sid'";
27              
28 471         8215 return File::Spec -> catfile($self -> directory, sprintf($self -> file_name, $sid) );
29              
30             } # End of get_file_path.
31              
32             # -----------------------------------------------
33              
34             sub init
35             {
36 251     251 0 433 my($self, $arg) = @_;
37 251   50     1129 $$arg{debug} ||= 0;
38 251   33     1931 $$arg{directory} ||= File::Spec -> tmpdir;
39 251   50     2974 $$arg{file_name} ||= 'cgisess_%s';
40 251   100     837 $$arg{id} ||= 0;
41 251   50     1090 $$arg{no_flock} ||= 0;
42 251   50     883 $$arg{no_follow} ||= eval { O_NOFOLLOW } || 0;
      33        
43 251   50     947 $$arg{umask} ||= 0660;
44 251   50     692 $$arg{verbose} ||= 0;
45              
46             } # End of init.
47              
48             # -----------------------------------------------
49              
50             sub new
51             {
52 251     251 1 2581 my($class, %arg) = @_;
53              
54 251         876 $class -> init(\%arg);
55              
56 251         15743 my($self) = from_hash(bless({}, $class), \%arg);
57              
58 251 50       1953 ($self -> file_name !~ /%s/) && die __PACKAGE__ . ". file_name must contain %s";
59              
60 251 50       1531 if (! -d $self -> directory)
61             {
62 0 0       0 if (! File::Path::mkpath($self -> directory) )
63             {
64 0         0 die __PACKAGE__ . ". Can't create directory '" . $self -> directory . "'";
65             }
66             }
67              
68 251         9579 return $self;
69              
70             } # End of new.
71              
72             # -----------------------------------------------
73              
74             sub remove
75             {
76 242     242 0 395 my($self, $id) = @_;
77 242         631 my($file_path) = $self -> get_file_path($id);
78              
79 242   50     14879 unlink $file_path || die __PACKAGE__ . ". Can't unlink file '$file_path'. " . ($self -> debug ? $! : '');
80              
81 242         806 return 1;
82              
83             } # End of remove.
84              
85             # -----------------------------------------------
86              
87             sub retrieve
88             {
89 137     137 0 315 my($self, $id) = @_;
90 137         404 my($file_path) = $self -> get_file_path($id);
91 137         2140 my($message) = __PACKAGE__ . ". Can't %s file '$file_path'. %s";
92              
93 137 100       10649 (! -e $file_path) && return '';
94              
95             # Remove symlinks if possible.
96              
97 132 50       2440 if (-l $file_path)
98             {
99 0 0       0 unlink($file_path) || die sprintf($message, 'unlink', $self -> debug ? $! : '');
    0          
100             }
101              
102 132         2314 my($mode) = (O_RDWR | $self -> no_follow);
103              
104 132         175 my($fh);
105              
106 132 0       5937 sysopen($fh, $file_path, $mode, $self -> umask) || die sprintf($message, 'open', $self -> debug ? $! : '');
    50          
107              
108             # Sanity check.
109              
110 132 50       3547 (-l $file_path) && die sprintf($message, "open it. It's a link, not a", '');
111              
112 132 50       825 if (! $self -> no_flock)
113             {
114 132 0       1085 flock($fh, LOCK_EX) || die sprintf($message, 'lock', $self -> debug ? $! : '');
    50          
115             }
116              
117 132         247 my($data) = '';
118              
119 132         2471 while (<$fh>)
120             {
121 415         1655 $data .= $_;
122             }
123              
124 132 0       1712 close($fh) || die sprintf($message, 'close', $self -> debug ? $! : '');
    50          
125              
126 132         938 return $data;
127              
128             } # End of retrieve.
129              
130             # -----------------------------------------------
131              
132             sub store
133             {
134 92     92 0 233 my($self, $id, $data) = @_;
135 92         337 my($file_path) = $self -> get_file_path($id);
136 92         1845 my($message) = __PACKAGE__ . ". Can't %s file '$file_path'. %s";
137              
138             # Remove symlinks if possible.
139              
140 92 50       3276 if (-l $file_path)
141             {
142 0 0       0 unlink($file_path) || die sprintf($message, 'unlink', $self -> debug ? $! : '');
    0          
143             }
144              
145 92 100       1650 my($mode) = -e $file_path ? (O_WRONLY | $self -> no_follow) : (O_RDWR | O_CREAT | O_EXCL);
146              
147 92         131 my($fh);
148              
149 92 0       9903 sysopen($fh, $file_path, $mode, $self -> umask) || die sprintf($message, 'open', $self -> debug ? $! : '');
    50          
150              
151             # Sanity check.
152              
153 92 50       1904 (-l $file_path) && die sprintf($message, "create it. It's a link, not a", '');
154              
155 92 50       457 if (! $self -> no_flock)
156             {
157 92 0       1127 flock($fh, LOCK_EX) || die sprintf($message, 'lock', $self -> debug ? $! : '');
    50          
158             }
159              
160 92 0       607 seek($fh, 0, 0) || die sprintf($message, 'seek', $self -> debug ? $! : '');
    50          
161 92 0       3049 truncate($fh, 0) || die sprintf($message, 'truncate', $self -> debug ? $! : '');
    50          
162 92         846 print $fh $data;
163 92 0       11692 close($fh) || die sprintf($message, 'close', $self -> debug ? $! : '');
    50          
164              
165 92         555 return 1;
166              
167             } # End of store.
168              
169             # -----------------------------------------------
170              
171             sub traverse
172             {
173 1     1 0 2 my($self, $sub) = @_;
174              
175 1 50 33     8 if (! $sub || ref($sub) ne 'CODE')
176             {
177 0         0 die __PACKAGE__ . '. traverse() called without subref';
178             }
179              
180 1         4 my($pattern) = $self -> file_name;
181 1         2 $pattern =~ s/\./\\./g; # Or /\Q.../.
182 1         4 $pattern =~ s/%s/(\.\+)/;
183 1         7 my($message) = __PACKAGE__ . ". Can't %s dir '" . $self -> directory . "' in traverse. %s";
184              
185 1 0       10 opendir(INX, $self -> directory) || die sprintf($message, 'open', $self -> debug ? $! : '');
    50          
186              
187 1         35 my($entry);
188              
189             # I do not use readdir(INX) || die .. here because I could not get it to work,
190             # even with: while ($entry = (readdir(INX) || die sprintf($message, 'read', $!) ) ).
191             # Every attempt triggered the call to die.
192              
193 1         34 while ($entry = readdir(INX) )
194             {
195 6 100 66     432 next if ($entry =~ /^\.\.?/ || -d $entry);
196              
197 4 50       54 ($entry =~ /$pattern/) && $sub -> ($1);
198             }
199              
200 1 0       14 closedir(INX) || die sprintf($message, 'close', $self -> debug ? $! : '');
    50          
201              
202 1         12 return 1;
203              
204             } # End of traverse.
205              
206             # -----------------------------------------------
207              
208             1;
209              
210             =pod
211              
212             =head1 NAME
213              
214             L - A persistent session manager
215              
216             =head1 Synopsis
217              
218             See L for details.
219              
220             =head1 Description
221              
222             L allows L to manipulate sessions via files.
223              
224             To use this module do this:
225              
226             =over 4
227              
228             =item o Specify a driver of type File, as Data::Session -> new(type => 'driver:File ...')
229              
230             =back
231              
232             =head1 Case-sensitive Options
233              
234             See L for important information.
235              
236             =head1 Method: new()
237              
238             Creates a new object of type L.
239              
240             C takes a hash of key/value pairs, some of which might mandatory. Further, some combinations
241             might be mandatory.
242              
243             The keys are listed here in alphabetical order.
244              
245             They are lower-case because they are (also) method names, meaning they can be called to set or get the value
246             at any time.
247              
248             =over 4
249              
250             =item o debug => $Boolean
251              
252             Specifies that debugging should be turned on (1) or off (0) in L and
253             L.
254              
255             When debug is 1, $! is included in error messages, but because this reveals directory names, it is 0 by default.
256              
257             This key is optional.
258              
259             Default: 0.
260              
261             =item o directory => $string
262              
263             Specifies the path to the directory which will contain the session files.
264              
265             This key is normally passed in as Data::Session -> new(directory => $string).
266              
267             Default: File::Spec -> tmpdir.
268              
269             This key is optional.
270              
271             =item o file_name => $string_containing_%s
272              
273             Specifies the pattern to use for session file names. It must contain 1 '%s', which will be replaced by the
274             session id before the pattern is used as a file name.
275              
276             This key is normally passed in as Data::Session -> new(file_name => $string_containing_%s).
277              
278             Default: 'cgisess_%s'.
279              
280             This key is optional.
281              
282             =item o no_flock => $boolean
283              
284             Specifies (no_flock => 1) to not use flock() to obtain a lock on a session file before processing it,
285             or (no_flock => 0) to use flock().
286              
287             This key is normally passed in as Data::Session -> new(no_flock => $boolean).
288              
289             Default: 0.
290              
291             This key is optional.
292              
293             =item o no_follow => $value
294              
295             Influences the mode to use when calling sysopen() on session files.
296              
297             'Influences' means the value is bit-wise ored with O_RDWR for reading and with O_WRONLY for writing.
298              
299             This key is normally passed in as Data::Session -> new(no_follow => $boolean).
300              
301             Default: eval{O_NOFOLLOW} || 0.
302              
303             This key is optional.
304              
305             =item o umask => $octal_value
306              
307             Specifies the mode to use when calling sysopen() on session files.
308              
309             This key is normally passed in as Data::Session -> new(umask => $octal_value).
310              
311             Default: 0660.
312              
313             This key is optional.
314              
315             =item o verbose => $integer
316              
317             Print to STDERR more or less information.
318              
319             Typical values are 0, 1 and 2.
320              
321             This key is normally passed in as Data::Session -> new(verbose => $integer).
322              
323             This key is optional.
324              
325             =back
326              
327             =head1 Method: remove($id)
328              
329             Deletes from storage the session identified by $id.
330              
331             Returns 1 if it succeeds, and dies if it can't.
332              
333             =head1 Method: retrieve($id)
334              
335             Retrieves from storage the session identified by $id, or dies if it can't.
336              
337             Returns the result of reading the session from the file identified by $id.
338              
339             This result is a frozen session. This value must be thawed by calling the appropriate serialization
340             driver's thaw() method.
341              
342             L calls the right thaw() automatically.
343              
344             =head1 Method: store($id => $data)
345              
346             Writes to storage the session identified by $id, together with its data $data.
347              
348             Storage is a file identified by $id.
349              
350             Returns 1 if it succeeds, and dies if it can't.
351              
352             =head1 Method: traverse($sub)
353              
354             Retrieves all ids via their file names, and for each id calls the supplied subroutine with the id as the only
355             parameter.
356              
357             Returns 1.
358              
359             =head1 Support
360              
361             Log a bug on RT: L.
362              
363             =head1 Author
364              
365             L was written by Ron Savage Iron@savage.net.auE> in 2010.
366              
367             Home page: L.
368              
369             =head1 Copyright
370              
371             Australian copyright (c) 2010, Ron Savage.
372              
373             All Programs of mine are 'OSI Certified Open Source Software';
374             you can redistribute them and/or modify them under the terms of
375             The Artistic License, a copy of which is available at:
376             http://www.opensource.org/licenses/index.html
377              
378             =cut