File Coverage

blib/lib/CGI/Plus.pm
Criterion Covered Total %
statement 171 194 88.1
branch 44 72 61.1
condition 11 17 64.7
subroutine 24 25 96.0
pod 8 19 42.1
total 258 327 78.9


line stmt bran cond sub pod time code
1             package CGI::Plus;
2 1     1   444 use strict;
  1         1  
  1         31  
3 1     1   3 use Carp;
  1         1  
  1         49  
4 1     1   468 use CGI::Safe 'taint';
  1         15628  
  1         5  
5 1     1   67 use base 'CGI::Safe';
  1         1  
  1         85  
6 1     1   518 use String::Util ':all';
  1         2421  
  1         219  
7 1     1   490 use CGI::Cookie;
  1         1610  
  1         1520  
8              
9             # version
10             our $VERSION = '0.15';
11              
12             # Debug::ShowStuff
13             # use Debug::ShowStuff ':all';
14             # use Debug::ShowStuff::ShowVar;
15              
16             # enable file uploads
17             $CGI::DISABLE_UPLOADS = 0;
18              
19             # maximum upload: 5 mb
20             $CGI::POST_MAX = 5 * 1024 * 1024;
21              
22             # set path to empty string
23             $ENV{'PATH'} = '';
24              
25             =head1 NAME
26              
27             CGI::Plus -- Extra utilities for CGI
28              
29             =head1 Description
30              
31             This module adds a few enhancements to
32             L,
33             which itself adds a few security-based enancements to
34             L. The enhancement are almost
35             entirely additions - the only method that is overridden is new(), and
36             the changes there are only addition. The enhancements in this module entirely
37             use the object-oriented interface.
38              
39             =head1 SYNOPSIS
40              
41             use CGI::Plus;
42             my ($cgi, $cookie, $url, $param);
43              
44             # new CGI::Plus object
45             $cgi = CGI::Plus->new();
46              
47             # turn on checks for cross-site request forgeries (CSRF)
48             $cgi->csrf(1);
49              
50             # get a cookie and look at its values
51             $cookie = $cgi->incoming_cookies->{'mycookie'};
52             print $cookie->{'values'}->{'x'}, "\n";
53             print $cookie->{'values'}->{'y'}, "\n";
54              
55             # more concise way to get an incoming cookie
56             $cookie = $cgi->ic->{'mycookie'};
57              
58             # resend a cookie, but change one of its values
59             $cookie = $cgi->resend_cookie('mycookie');
60             $cookie->{'values'}->{'x'} = 2;
61              
62             # add an outgoing cookie, set some values
63             $cookie = $cgi->new_send_cookie('newcookie');
64             $cookie->{'values'}->{'val1'} = '1';
65             $cookie->{'values'}->{'val2'} = '2';
66              
67             # output HTTP header with outgoing cookies, including CSRF
68             # check cookie, automatically added
69             print $cgi->header_plus;
70            
71             # output header again if it hasn't already been sent, but if it
72             # has then output an empty string
73             print $cgi->header_plus;
74              
75             # output the URL of the current page but set a new value
76             # for the "t" param and remove the "j" param
77             $url = $cgi->self_link(params=>{t=>2, j=>undef});
78              
79             # check if the submitted form includes the value of the CSRF
80             # cookie that was sent
81             if (! $cgi->csrf_check)
82             { die 'security error' }
83              
84             # output the randomly generated value of the CSRF cookie,
85             # output: KTFnGgpkZ4
86             print $cgi->csrf_value, "\n";
87              
88             # output the hidden input form field that uses the same
89             # value as the CSRF cookie
90             # output:
91             print $cgi->csrf_field, "\n";
92              
93             # get the CSRF check param for use in a URL
94             # output: csrf=KTFnGgpkZ4
95             print $cgi->csrf_param;
96              
97             # set a custom header
98             $cgi->set_header('myheader', 'whatever');
99              
100             # change content type
101             $cgi->set_content_type('text/json');
102              
103             # output HTTP headers, including added cookies, the CSRF cookie,
104             # and the new header
105             print $cgi->header_plus;
106              
107             # outputs something like this:
108             # Set-Cookie: newcookie=val2&2&val1&1; path=/
109             # Set-Cookie: mycookie=y&2&x&2; path=/
110             # Set-Cookie: csrf=v&KTFnGgpkZ4; path=/
111             # Date: Sun, 29 Jul 2012 04:08:06 GMT
112             # Myheader: whatever
113             # Content-Type: text/json; charset=ISO-8859-1
114              
115             =head1 INSTALLATION
116              
117             CGI::Plus can be installed with the usual routine:
118              
119             perl Makefile.PL
120             make
121             make test
122             make install
123              
124             =head1 METHODS
125              
126             =cut
127              
128              
129             #------------------------------------------------------------------------------
130             ## new
131             #
132              
133             =head2 CGI::Plus->new()
134              
135             Creates and returns a CGI::Plus object. New calls the super-class' new()
136             method, so all params sent to this method will be passed through to CGI
137             and CGI::Safe.
138              
139             =cut
140              
141             sub new {
142 9     9 1 5905 my $class = shift;
143 9         45 my $cgi = $class->SUPER::new(@_);
144            
145             # set cookies
146 9         5882 $cgi->initialize_cookies();
147            
148             # call super method
149 9         19 return $cgi;
150             }
151             #
152             # new
153             #------------------------------------------------------------------------------
154              
155              
156             #------------------------------------------------------------------------------
157             # ic, oc
158             # quick accesors to incoming and outgoing cookies
159             #
160              
161             =head2 $cgi->ic, $cgi->oc
162              
163              
164             =cut
165              
166 6     6 0 28 sub incoming_cookies { return $_[0]->{'cookies'}->{'incoming'} }
167 6     6 1 16 sub ic { return shift->incoming_cookies(@_) }
168              
169 11     11 0 35 sub outgoing_cookies { return $_[0]->{'cookies'}->{'outgoing'} }
170 11     11 1 24 sub oc { return shift->outgoing_cookies(@_) }
171              
172             #
173             # ic, oc
174             #------------------------------------------------------------------------------
175              
176              
177             #------------------------------------------------------------------------------
178             # initialize_cookies
179             # private method
180             #
181             sub initialize_cookies {
182 9     9 0 13 my ($cgi) = @_;
183 9         10 my ($got, %cookies);
184            
185             # cookie hashes
186 9         23 $cgi->{'cookies'} = {};
187 9         15 $got = $cgi->{'cookies'}->{'incoming'} = {};
188 9         13 $cgi->{'cookies'}->{'outgoing'} = {};
189            
190             # get hash of cookies that were sent
191 9         37 %cookies = CGI::Cookie->fetch();
192             # showhash \%cookies, title=>'%cookies';
193            
194             # populate cookie values
195 9         2409 foreach my $name (keys %cookies) {
196 18         20 my ($cookie, $element, @value);
197 18         61 $cookie = $cookies{$name};
198 18         19 $element = {};
199            
200             # name of cookie
201 18         23 $element->{'name'} = $name;
202            
203             # original cookie object
204 18         23 $element->{'org'} = $cookie;
205            
206             # expires
207 18 50       36 if (defined $cookie->expires())
208 0         0 { $element->{'expires'} = $cookie->expires() }
209            
210             # get parsed values
211 18         92 @value = $cookie->value();
212            
213             # if more than one element in @value, assume it's a hash
214 18 100       101 if (@value > 1)
215 9         23 { $element->{'values'} = {@value} }
216            
217             # else it's a single string value
218             else
219 9         16 { $element->{'value'} = $cookie->value() }
220            
221             # hold on to cookie element
222 18         63 $got->{$name} = $element;
223             }
224             }
225             #
226             # initialize_cookies
227             #------------------------------------------------------------------------------
228              
229              
230             #------------------------------------------------------------------------------
231             # cookie_resend
232             #
233             sub resend_cookie {
234 1     1 0 211 my $cgi = shift;
235 1         4 return $cgi->cookie_resend(@_);
236             }
237              
238             sub cookie_resend {
239 2     2 0 4 my ($cgi, $name, %opts) = @_;
240 2         3 my ($got, $send);
241            
242             # default %opts
243 2         7 %opts = (ensure=>1, %opts);
244            
245             # if not ensuring existence of cookie, and cookie doesn't
246             # exist, return undef
247 2 50 66     4 unless ( $cgi->ic->{$name} || $opts{'ensure'}) {
248 0         0 return undef;
249             }
250            
251             # get sent cookie
252 2   100     6 $got = $cgi->ic->{$name} || {'name'=>$name};
253            
254             # create cookie that gets sent back out
255 2         3 $send = {};
256            
257             # clone $got cookie
258 2         6 foreach my $key (keys %$got) {
259 4         6 my $value = $got->{$key};
260            
261             # original cookie
262 4 100       24 if (UNIVERSAL::isa $value, 'CGI::Cookie') {
    100          
263 1         3 $send->{$key} = $value;
264             }
265            
266             # hashref
267             elsif (UNIVERSAL::isa $value, 'HASH') {
268 1         4 $send->{$key} = {%$value};
269             }
270            
271             # else just copy
272             else {
273 2         6 $send->{$key} = $value;
274             }
275             }
276            
277             # set cookie
278 2         6 $cgi->oc->{$name} = $send;
279            
280             # return new cookie
281 2         6 return $send;
282             }
283             #
284             # cookie_resend
285             #------------------------------------------------------------------------------
286              
287              
288             #------------------------------------------------------------------------------
289             # new_send_cookie
290             #
291             sub new_send_cookie {
292 1     1 0 5 my ($cgi, $name) = @_;
293 1         1 my ($cookie);
294            
295             # create oject
296 1         5 $cookie = {};
297 1         2 $cookie->{'name'} = $name;
298 1         2 $cookie->{'values'} = {};
299            
300             # add to hash of outgoing cookies
301 1         2 $cgi->oc->{$name} = $cookie;
302            
303             # return new cookie
304 1         2 return $cookie;
305             }
306             #
307             # new_send_cookie
308             #------------------------------------------------------------------------------
309              
310              
311             #------------------------------------------------------------------------------
312             # self_link
313             #
314              
315             =head2 $cgi->self_link(%options)
316              
317             Returns a url that is a relative link to the current page. The local path of
318             the URL is sent, but not the protocol or host. So, for example, if the URL
319             of the current page is
320              
321             http://www.example.com/cgi-plus/?y=1&x=2&t=2&y=2
322              
323             then $cgi->self_link() would return something like as follows. Note that the
324             order of the URL params mght be changed.
325              
326             /cgi-plus/?y=1&y=2&x=2&t=2
327              
328             NOTE: If all you want is to do is get the URL of the current page, then
329             L<$cgi-Eurl()|http://perldoc.perl.org/CGI.html#OBTAINING-THE-SCRIPT%27S-URL>
330             is a better choice because it preserves the order of URL params.
331              
332             B params
333              
334             The C option allows you to change the values of some of the URL params
335             while leaving others as-is. C is a hashref of URL params and
336             their new values. For example, consider this URL:
337              
338             http://www.example.com/cgi-plus/?y=1&x=2&t=2&y=2
339              
340             Suppose you want to change just that C param from 2 to 3. You would do that
341             like this:
342              
343             $cgi->self_link(params=>{t=>3})
344              
345             which gives us this relative URL with the C and C values as they were before, but
346             with the new C value:
347              
348             /cgi-plus/?y=1&y=2&x=2&t=3
349              
350             If the value of the param is an array ref, then the param is output once
351             for each value in the array ref. So, for example, you could set that C
352             to have the values 4 and 5 like this:
353              
354             $cgi->self_link(params=>{t=>[4,5]})
355              
356             which gives us
357              
358             /cgi-plus/?y=1&y=2&x=2&t=4&t=5
359              
360             You can remove params by setting their values to undef:
361              
362             $cgi->self_link(params=>{t=>undef})
363              
364             which gives us
365              
366             /cgi-plus/?y=1&y=2&x=2
367              
368             B clear_params
369              
370             C removes all params from the URL. For example, using our
371             example URL from above:
372              
373             http://www.example.com/cgi-plus/?y=1&x=2&t=2&y=2
374              
375             this:
376              
377             $cgi->self_link(clear_params=>1)
378              
379             returns this URL;
380              
381             /cgi-plus/
382              
383             You can use C in conjunction with C to wipe the slate clean
384             and send only specific params. So, for example, this call
385              
386             $cgi->self_link(clear_params=>1, params=>{j=>10})
387              
388             gives us this URL:
389              
390             /cgi-plus/?j=10
391              
392             B html
393              
394             The C option returns the URL HTML-escaped. So, for example, this
395             call:
396              
397             $cgi->self_link(params=>{t=>[4,5]}, html=>1)
398              
399             returns this:
400              
401             /cgi-plus/?y=1&y=2&x=2&t=4&t=5
402              
403             =cut
404              
405             sub self_link {
406 6     6 1 2565 my ($cgi, %opts) = @_;
407 6         7 my (%params, $rv, $query, $changes, %added);
408            
409             # get params for adding to url
410 6   100     24 $changes = $opts{'params'} || $opts{'param'} || {};
411            
412             # start with uri path
413 6 50       14 unless ($rv = $ENV{'PATH_INFO'}) {
414 6         8 $rv = $ENV{'REQUEST_URI'};
415 6         19 $rv =~ s|\?.*||s;
416             }
417            
418             # get parameter names from cgi
419 6 100       12 unless ($opts{'clear_params'})
420 4         9 { @params{$cgi->param()} = () }
421            
422             # get parameter names from changes
423 6         72 @params{keys %$changes} = ();
424            
425             # loop through params
426 6         11 foreach my $key (keys %params) {
427 9         7 my (@vals);
428            
429             # get values from adds
430 9 100       14 if (exists $changes->{$key}) {
431 4 100       7 if (ref $changes->{$key})
432 1         1 { @vals = @{$changes->{$key}} }
  1         3  
433             else
434 3         6 { @vals = $changes->{$key} }
435             }
436             else {
437 5         9 @vals = $cgi->param($key);
438             }
439            
440             # remove values that are undef
441 9         76 @vals = grep {defined $_} @vals;
  12         17  
442            
443             # output values
444 9         11 foreach my $val (@vals) {
445             # add delimiter or query marker
446 12 100       14 if ($query)
447 7         7 { $query .= '&' }
448             else
449 5         6 { $query = '?' }
450            
451             # url escape
452 12         31 $val = $cgi->escape($val);
453            
454             # add value
455 12         95 $query .= $key . '=' . $val;
456             }
457             }
458            
459             # add query
460 6 100       12 if ($query)
461 5         5 { $rv .= $query }
462            
463             # html escape
464 6 50       11 if ($opts{'html'})
465 0         0 { $rv = htmlesc($rv) }
466            
467             # return
468 6         15 return $rv;
469             }
470             #
471             # self_link
472             #------------------------------------------------------------------------------
473              
474              
475              
476             #------------------------------------------------------------------------------
477             # set_header
478             #
479             sub set_header {
480 1     1 0 6 my ($cgi, $name, $value) = @_;
481            
482             # initialize header hash
483 1   50     9 $cgi->{'headers'} ||= {};
484            
485             # set header
486 1         2 $cgi->{'headers'}->{$name} = $value;
487            
488             # return
489 1         2 return 1;
490             }
491             #
492             # set_header
493             #------------------------------------------------------------------------------
494              
495              
496              
497             #------------------------------------------------------------------------------
498             # set_content_type
499             #
500             sub set_content_type {
501 1     1 0 5 my ($cgi, $type) = @_;
502            
503             # set type
504 1         3 $cgi->{'content_type'} = $type;
505            
506             # return
507 1         2 return 1;
508             }
509             #
510             # set_content_type
511             #------------------------------------------------------------------------------
512              
513              
514             #------------------------------------------------------------------------------
515             # header_plus
516             #
517             sub header_plus {
518 3     3 0 417 my ($cgi, %opts) = @_;
519 3         4 my (@cookies);
520            
521             # if header has already been sent, don't send it again, just
522             # return empty string
523 3 50       10 if ($cgi->{'header_sent'})
524 0         0 { return '' }
525            
526             # set content type
527 3 100 66     23 if ( (! $opts{'-type'}) && $cgi->{'content_type'} ) {
528 1         3 $opts{'-type'} = $cgi->{'content_type'};
529             }
530            
531             # add headers
532 3 100       8 if ($cgi->{'headers'}) {
533 1         1 while ( my($name, $value) = each(%{$cgi->{'headers'}}) ) {
  2         6  
534 1         3 $name =~ s|^\-*|-|s;
535 1   33     6 $opts{$name} ||= $value;
536             }
537             }
538            
539             # add cookies
540 3         4 foreach my $name ( keys %{$cgi->oc} ) {
  3         6  
541 1         2 my (%element, %params, $cookie);
542 1         2 %element = %{$cgi->oc->{$name}};
  1         7  
543            
544             # 'values' takes precedence over 'value'
545 1 50       6 if ($element{'values'})
    0          
546 1         3 { delete $element{'value'} }
547            
548             # else if no 'value' either, set it to empty string
549             elsif (! defined $element{'value'})
550 0         0 { $element{'value'} = '' }
551            
552             # loop through values
553 1         3 foreach my $key (keys %element) {
554             # special case: values
555 2 100       6 if ($key eq 'values') {
556 1         4 $params{'-value'} = $element{$key};
557             }
558            
559             # else just copy value
560             else {
561 1         2 my $send_key = $key;
562 1         6 $send_key =~ s|^\-*|-|;
563            
564 1         4 $params{$send_key} = $element{$key};
565             }
566             }
567            
568             # set domain
569 1 50       4 if ($element{'domain'})
570 0         0 { $params{'-domain'} = $element{'domain'} }
571            
572             # set expires: default to one year
573 1 50       5 if (exists $element{'expires'}) {
574 0 0       0 if (defined $element{'expires'})
575 0         0 { $params{'-expires'} = $element{'expires'} }
576             }
577             else {
578 1         3 $params{'-expires'} = '+1y';
579             }
580            
581             # create cookie object
582 1         6 $cookie = CGI::Cookie->new(%params);
583            
584 1 50       242 if (! defined $cookie) {
585             # showhash \%params, title=>'error generating cookie';
586 0         0 die 'cookie error';
587             }
588            
589             # add to cookie array
590 1         6 push @cookies, $cookie;
591             }
592            
593             # add cookies to header options
594 3 100       8 if (@cookies)
595 1         3 { $opts{'-cookie'} = \@cookies }
596            
597             # note that header has been sent
598 3         6 $cgi->{'header_sent'} = 1;
599            
600             # call super method
601 3         67 return $cgi->SUPER::header(%opts);
602             }
603             #
604             # header_plus
605             #------------------------------------------------------------------------------
606              
607              
608              
609              
610             #------------------------------------------------------------------------------
611             # CSRF info
612             #
613              
614             =head1 Cross-site request forgery (CSRF) defenses
615              
616             A L
617             (CSRF) is a technique for breaching a web site's security. CSRF is one of the
618             most common web-site vulnerabilities. CGI::Plus provides a technique for
619             protecting
620              
621             =cut
622              
623             #
624             # CSRF info
625             #------------------------------------------------------------------------------
626              
627              
628              
629              
630             #------------------------------------------------------------------------------
631             # csrf
632             #
633             sub csrf {
634 6     6 0 11 my $cgi = shift;
635            
636             # set csrf value if sent
637 6 100       15 if (@_) {
638 1         3 $cgi->{'csrf'} = $_[0];
639            
640             # set csrf cookie
641 1 50       3 if ($cgi->{'csrf'}) {
642 1         2 my ($cookie);
643 1         4 $cookie = $cgi->cookie_resend($cgi->csrf_name);
644 1   50     24 $cookie->{'values'} ||= {v=>randword(10)};
645             }
646             }
647            
648             # return
649 6         165 return $cgi->{'csrf'};
650             }
651             #
652             # csrf
653             #------------------------------------------------------------------------------
654              
655              
656             #------------------------------------------------------------------------------
657             # csrf_name
658             #
659             sub csrf_name {
660 5     5 0 213 return 'csrf';
661             }
662             #
663             # csrf_name
664             #------------------------------------------------------------------------------
665              
666              
667             #------------------------------------------------------------------------------
668             # csrf_value
669             #
670              
671             =head2 $cgi->csrf_value()
672              
673             Returns the string used in CSRF checks. This value must be included in an HTML
674             form (see Lcsrf_value()>)
675              
676             =cut
677              
678             sub csrf_value {
679 0     0 1 0 my ($cgi) = @_;
680 0         0 my ($name, $cookie, $rv);
681            
682             # must be in csrf mode
683 0 0       0 if (! $cgi->csrf)
684 0         0 { croak 'cannot set CSRF field when not in CSRF mode' }
685            
686             # get name of csrf cookie
687 0         0 $name = $cgi->csrf_name;
688            
689             # get csrf cookie
690 0         0 $cookie = $cgi->oc->{$name};
691 0 0       0 $cookie or die 'do not have csrf cookie';
692            
693             # return
694 0         0 return $cookie->{'values'}->{'v'};
695             }
696             #
697             # csrf_value
698             #------------------------------------------------------------------------------
699              
700              
701             #------------------------------------------------------------------------------
702             # csrf_field
703             #
704              
705             =head2 $cgi->csrf_field()
706              
707             Returns a hidden HTML field with the CSRF check value in it. This field must
708             be included in HTML forms if you do a CSRF check. The string will look
709             something like this:
710              
711            
712              
713             =cut
714              
715             sub csrf_field {
716 1     1 1 2 my ($cgi) = @_;
717 1         1 my ($name, $cookie, $rv);
718            
719             # must be in csrf mode
720 1 50       3 if (! $cgi->csrf)
721 0         0 { croak 'cannot set CSRF field when not in CSRF mode' }
722            
723             # get name of csrf cookie
724 1         3 $name = $cgi->csrf_name;
725            
726             # get csrf cookie
727 1         2 $cookie = $cgi->oc->{$name};
728 1 50       2 $cookie or die 'do not have csrf cookie';
729            
730             # showhash $cookie;
731             # showhash $cookie->{'values'}->{'v'};
732            
733             # build return value
734 1         4 $rv =
735             '
736             'name="' . htmlesc($name) . '" ' .
737             'value="' . htmlesc($cookie->{'values'}->{'v'}) . '">';
738            
739             # return
740 1         17 return $rv;
741             }
742             #
743             # csrf_field
744             #------------------------------------------------------------------------------
745              
746              
747             #------------------------------------------------------------------------------
748             # csrf_param
749             #
750              
751             =head2 $cgi->csrf_param()
752              
753             Returns the URL parameter to use in a URL. The return value will look
754             something like this:
755              
756             csrf=8hFnVjSr25
757              
758             The string will never contain HTML or URL meta characters, so it does not need
759             to be HTML or URL escaped.
760              
761             =cut
762              
763             sub csrf_param {
764 1     1 1 2 my ($cgi) = @_;
765 1         1 my ($name, $cookie, $rv);
766            
767             # must be in csrf mode
768 1 50       2 if (! $cgi->csrf)
769 0         0 { croak 'cannot set CSRF field when not in CSRF mode' }
770            
771             # get name of csrf cookie
772 1         2 $name = $cgi->csrf_name;
773            
774             # get csrf cookie
775 1         2 $cookie = $cgi->oc->{$name};
776 1 50       5 $cookie or die 'do not have csrf cookie';
777            
778             # build return value
779 1         3 $rv = $name . '=' . $cookie->{'values'}->{'v'};
780            
781             # return
782 1         5 return $rv;
783             }
784             #
785             # csrf_param
786             #------------------------------------------------------------------------------
787              
788              
789             #------------------------------------------------------------------------------
790             # csrf_check
791             #
792              
793             =head2 $cgi->csrf_check()
794              
795             Checks if a CSRF check value was sent and that it matches the CSRF check
796             cookie. CSRF checks must be turned on or this method will croak. The
797             following code is a typical usage of csrf checking:
798              
799             $cgi->csrf(1);
800              
801             if (! $cgi->csrf_check) {
802             die 'security error';
803             }
804              
805             =cut
806              
807             sub csrf_check {
808 1     1 1 2 my ($cgi) = @_;
809 1         2 my ($name, $cookie, $cookie_value, $form_value);
810            
811             # must be in csrf mode
812 1 50       2 if (! $cgi->csrf)
813 0         0 { croak 'cannot check CSRF when not in CSRF mode' }
814            
815             # get name of csrf cookie
816 1         2 $name = $cgi->csrf_name;
817            
818             # get csrf cookie
819 1         2 $cookie = $cgi->oc->{$name};
820 1 50       2 $cookie or return 0;
821            
822             # get cookie value
823 1         2 $cookie_value = $cookie->{'values'}->{'v'};
824 1 50       2 $cookie_value or return 0;
825            
826             # get form value
827 1         5 $form_value = $cgi->param($name);
828 1 50       20 $form_value or return 0;
829            
830             # return true if same
831 0 0         if ($cookie_value eq $form_value)
832 0           { return 1 }
833            
834             # else return false
835 0           return 0;
836             }
837             #
838             # csrf_check
839             #------------------------------------------------------------------------------
840              
841              
842              
843              
844             # return true
845             1;
846              
847             __END__