File Coverage

blib/lib/CGI/Easy.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 100.0


line stmt bran cond sub pod time code
1             package CGI::Easy;
2              
3 2     2   54249 use warnings;
  2         5  
  2         80  
4 2     2   13 use strict;
  2         5  
  2         66  
5 2     2   13 use Carp;
  2         8  
  2         175  
6              
7 2     2   2193 use version; our $VERSION = qv('1.0.1'); # REMINDER: update Changes
  2         6396  
  2         14  
8              
9             # REMINDER: update dependencies in Makefile.PL
10 2     2   202 use 5.008;
  2         13  
  2         96  
11              
12              
13             1; # Magic true value required at end of module
14             __END__
15              
16             =encoding utf8
17              
18             =head1 NAME
19              
20             CGI::Easy - simple and straightforward helpers to make CGI easy
21              
22              
23             =head1 SYNOPSIS
24              
25             use CGI::Easy::Request;
26             use CGI::Easy::Headers;
27             use CGI::Easy::Session;
28              
29             my $r = CGI::Easy::Request->new();
30             my $h = CGI::Easy::Headers->new();
31             my $sess = CGI::Easy::Session->new($r, $h);
32              
33             # -- access basic GET request details
34             my $url = "$r->{scheme}://$r->{host}:$r->{port}$r->{path}";
35             my $param_name = $r->{GET}{name};
36             my @param_color = @{ $r->{GET}{'color[]'} };
37             my $cookie_some = $r->{cookie}{some};
38              
39             # -- file upload
40             my $avatar_image = $r->{POST}{avatar};
41             my $avatar_filename = $r->{filename}{avatar};
42             my $avatar_mimetype = $r->{mimetype}{avatar};
43              
44             # -- easy way to identify visitors and get data stored in cookies
45             my $session_id = $sess->{id};
46             my $tempcookie_x= $sess->{temp}{x};
47             my $permcookie_y= $sess->{perm}{y};
48              
49             # -- set custom HTTP headers and cookies
50             $h->{Expires} = 'Sat, 01 Jan 2000 00:00:00 GMT';
51             $h->add_cookie({
52             name => 'some',
53             value => 'custom cookie',
54             domain => '.example.com',
55             expires => time+86400,
56             });
57              
58             # -- easy way to store data in cookies
59             $sess->{temp}{x} = 'available until browser closes';
60             $sess->{perm}{y} = 'available for 1 year';
61             $sess->save();
62              
63             # -- output all HTTP headers and html page
64             print $h->compose();
65             print "<html>...</html>";
66              
67             # -- output redirect
68             $h->redirect('http://example.com/');
69             print $h->compose();
70              
71             # -- output custom reply
72             $h->{Status} = '500 Internal Server Error';
73             $h->{'Content-Type'} = 'text/plain; charset=utf-8';
74             print $h->compose(), "Please try again later\n";
75              
76              
77             =head1 DESCRIPTION
78              
79             This documentation is an overview of CGI::Easy::* modules. For detailed
80             information about corner cases and available features you should consult
81             corresponding module documentation: L<CGI::Easy::Request>,
82             L<CGI::Easy::Headers>, L<CGI::Easy::Session>. If you wanna work with
83             CGI/HTTP on lower level, you can look at L<CGI::Easy::Util>. There also
84             some other useful modules available separately: L<CGI::Easy::URLconf>,
85             L<CGI::Easy::SendFile>.
86              
87             CGI::Easy designed to help you do what you want with CGI/HTTP without
88             forcing you to learn I<one more> huge and complex API specific to some
89             module, or limiting you to do your tasks I<only in way> provided by this
90             module. With CGI::Easy you got all you need in B<simple hashes>, and
91             you're free to B<do anything you like> with this data, because it's
92             B<your data>.
93              
94             CGI::Easy consist of three main parts:
95              
96             =over
97              
98             =item CGI::Easy::Request object
99              
100             This object actually is simple hash populated with all data related to
101             current CGI request - GET/POST parameters, cookies, url path, … When you
102             create this object with new(), current request will be parsed (from C< %ENV >
103             and C< STDIN >), all useful things will be stored in that object/hash, and
104             now you're free to do anything you want with this object/hash - modify it
105             contents in any way, etc. You don't need special methods to access trivial
106             data like some GET parameter or cookie anymore.
107              
108             Here is list of keys in that hash prepared for you:
109              
110             # -- URL info
111             scheme 'http' OR 'https'
112             host 'example.com'
113             port 80
114             path '/' OR '/index.php' OR '/articles/2008/'
115             # -- CGI parameters
116             GET { name => 'powerman', 'color[]' => ['red','green'], … }
117             POST { name => 'powerman', avatar => '…binary image data…', … }
118             filename { name => undef, avatar => 'C:\\Documents\\avatar.png', … }
119             mimetype { name => undef, avatar => 'image/png', … }
120             cookie { somevar => 'someval', … }
121             # -- USER details
122             REMOTE_ADDR 192.168.2.1
123             REMOTE_PORT 12345
124             AUTH_TYPE Basic
125             REMOTE_USER 'powerman'
126             REMOTE_PASS 'secret'
127             # -- original request data
128             ENV { REQUEST_METHOD => 'POST', … }
129             STDIN 'name=powerman&color[]=red&color[]=green'
130             # -- request parsing status
131             error '' OR 'POST body too large' etc.
132              
133             =item CGI::Easy::Headers object
134              
135             This object is also very simple hash - keys are HTTP header names and
136             values are HTTP header values. When you call new() this hash populated
137             with few headers (notably C<< 'Status'=>'200 OK' >> and
138             C<< 'Content-Type'=>'text/html; charset=utf-8' >>), but you're free to
139             change these keys/headers and add your own headers. When you ready to
140             output all headers from this object/hash you should call compose() method,
141             and it will return string with all HTTP headers suitable for sending to
142             browser.
143              
144             There one exception: value for key 'Set-Cookie' is ARRAYREF with HASHREFs,
145             where each HASHREF keep cookie details:
146              
147             $h->{'Set-Cookie'} = [
148             { name=>'mycookie1', value=>'myvalue1' },
149             { name=>'x', value=>5,
150             domain=>'.example.com', expires=>time+86400 }
151             ];
152              
153             To make it ease for you to work with this key there helper add_cookie()
154             method available, but you're free to modify this key manually if you like.
155              
156             There also some helper methods in this object (like redirect()), but they
157             all just modify some keys/headers in this hash.
158              
159             =item CGI::Easy::Session object
160              
161             This object make working with cookies even more ease than already provided
162             by CGI::Easy::Request and CGI::Easy::Headers way:
163              
164             my $somevalue = $r->{cookie}{somename};
165             $h->add_cookie({ name => 'somename', value => $somename });
166              
167             If you will use CGI::Easy::Session, then it will read/write values for
168             three cookies: C<sid>, C<perm> and C<temp>. Cookie C<sid> will contain
169             automatically generated ID unique to this visitor, cookies C<perm> and
170             C<temp> will contain simple perl hashes (automatically serialized to
171             strings for storing in cookies) with different lifetime: C<perm> will
172             expire in 1 year, C<temp> will expire when browser closes.
173              
174             CGI::Easy::Session object will provide you with three keys:
175              
176             id undef OR '…unique string…'
177             perm { x=>5, somename=>'somevalue', … }
178             temp { y=>7, … }
179              
180             Field C<id> will contain undef() in case user has no cookie support.
181             To serialize hashes in fields C<perm> and C<temp> to cookies you'll have
182             to call save() method before C<< $h->compose() >>. Example:
183              
184             if (!defined $sess->{id}) {
185             warn "user has no cookie support";
186             }
187             $sess->{perm}{x} = 5;
188             $sess->{perm}{somename} = 'somevalue';
189             $sess->{temp}{y}++;
190             $sess->save();
191             print $h->compose();
192              
193             =back
194              
195             You don't have to use all these three parts - for example, you can use
196             only CGI::Easy::Request and output HTTP headers manually, or use only
197             CGI::Easy::Headers and parse CGI parameters using standard L<CGI> module,
198             etc.
199              
200              
201             =head2 Unicode
202              
203             These modules by default support Unicode with UTF8 encoding. If you need
204             another encoding or wanna disable Unicode look at C< raw > option for
205             CGI::Easy::Request->new() and modify default C< 'Content-Type' > header
206             provided by CGI::Easy::Headers->new().
207              
208              
209             =head1 EXAMPLES
210              
211             =head2 CGI with Session
212              
213             use CGI::Easy::Request;
214             use CGI::Easy::Headers;
215             use CGI::Easy::Session;
216              
217             my $r = CGI::Easy::Request->new();
218             my $h = CGI::Easy::Headers->new();
219             my $sess = CGI::Easy::Session->new($r, $h);
220              
221             $sess->{perm}{create_time} ||= time;
222             $sess->{temp}{counter} ||= 0;
223             $sess->{temp}{counter}++;
224             $sess->save();
225              
226             print $h->compose();
227              
228             if ($sess->{id}) {
229             printf "<p>Your ID is: %s</p>\n", $sess->{id};
230             printf "<p>Your session was created at: %s</p>\n",
231             scalar gmtime $sess->{perm}{create_time};
232             printf "<p>This is your %d page view</p>\n",
233             $sess->{temp}{counter};
234             } else {
235             printf "<p>You browser doesn't support cookies</p>\n";
236             }
237              
238              
239             =head2 FCGI with cookies
240              
241             use FCGI;
242             use CGI::Easy::Request;
243             use CGI::Easy::Headers;
244              
245             my $count = 0;
246              
247             my $request = FCGI::Request();
248             while($request->Accept() >= 0) {
249             my $r = CGI::Easy::Request->new();
250             my $h = CGI::Easy::Headers->new();
251              
252             $h->{Expires} = 'Sat, 01 Jan 2000 00:00:00 GMT';
253             $h->add_cookie({
254             name => 'counter',
255             value => ($r->{cookie}{counter} || 0) + 1,
256             expires => time+10,
257             });
258              
259             print $h->compose();
260              
261             printf "<p>This is request number: %d</p>\n", ++$count;
262             printf "<p>This is your %d page view</p>\n", $r->{cookie}{counter};
263             }
264              
265             =head2 FCGI::EV with manual Basic HTTP auth
266              
267             # -- you'll need something like this in .htaccess
268             # to catch any url with your FastCGI script
269             # and handle Basic HTTP auth manually in script
270             RewriteEngine On
271             RewriteBase /
272             RewriteCond %{REQUEST_URI} !(fcgi_std)
273             RewriteRule ^(.*)$ /fcgi_std/$1 [L]
274             RewriteCond %{REQUEST_URI} (fcgi_std)
275             RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
276              
277             # -- mod_fastcgi should be configured like this
278             FastCGIExternalServer /var/www/example.com/fcgi_std -socket /tmp/fcgi_std.sock
279              
280             # -- standard code from FCGI::EV documentation
281             use Socket;
282             use Fcntl;
283             use EV;
284             use FCGI::EV;
285             use FCGI::EV::Std;
286             use CGI::Easy::Request;
287             use CGI::Easy::Headers;
288             my $path = '/tmp/fcgi_std.sock';
289             socket my $srvsock, AF_UNIX, SOCK_STREAM, 0;
290             unlink $path;
291             my $umask = umask 0; # ensure 0777 perms for unix socket
292             bind $srvsock, sockaddr_un($path);
293             umask $umask;
294             listen $srvsock, SOMAXCONN;
295             fcntl $srvsock, F_SETFL, O_NONBLOCK;
296             my $w = EV::io $srvsock, EV::READ, sub {
297             accept my($sock), $srvsock;
298             fcntl $sock, F_SETFL, O_NONBLOCK;
299             FCGI::EV->new($sock, 'FCGI::EV::Std');
300             };
301             EV::loop;
302              
303             # -- most interesting part: handle FastCGI requests
304             sub main {
305             my $r = CGI::Easy::Request->new();
306             my $h = CGI::Easy::Headers->new();
307              
308             my $reply = q{};
309             if ($r->{path} =~ m{\A/private/}xms) {
310             if ($r->{REMOTE_USER} ne 'powerman' || $r->{REMOTE_PASS} ne 'secret') {
311             $h->require_basic_auth('Private Area');
312             }
313             else {
314             $reply = sprintf "<p>Welcome to private area, %s</p>\n",
315             $r->{REMOTE_USER};
316             }
317             }
318             else {
319             $reply = "<p>Welcome to public area, guest</p>\n";
320             }
321              
322             print $h->compose(), $reply;
323             }
324              
325              
326             =head1 SEE ALSO
327              
328             L<CGI::Easy::Request>,
329             L<CGI::Easy::Headers>,
330             L<CGI::Easy::Session>,
331             L<CGI::Easy::Util>,
332             L<CGI::Easy::URLconf>,
333             L<CGI::Easy::SendFile>.
334              
335              
336             =head1 BUGS AND LIMITATIONS
337              
338             No bugs have been reported.
339              
340              
341             =head1 SUPPORT
342              
343             Please report any bugs or feature requests through the web interface at
344             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=CGI-Easy>.
345             I will be notified, and then you'll automatically be notified of progress
346             on your bug as I make changes.
347              
348             You can also look for information at:
349              
350             =over
351              
352             =item * RT: CPAN's request tracker
353              
354             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=CGI-Easy>
355              
356             =item * AnnoCPAN: Annotated CPAN documentation
357              
358             L<http://annocpan.org/dist/CGI-Easy>
359              
360             =item * CPAN Ratings
361              
362             L<http://cpanratings.perl.org/d/CGI-Easy>
363              
364             =item * Search CPAN
365              
366             L<http://search.cpan.org/dist/CGI-Easy/>
367              
368             =back
369              
370              
371             =head1 AUTHOR
372              
373             Alex Efros C<< <powerman-asdf@ya.ru> >>
374              
375              
376             =head1 LICENSE AND COPYRIGHT
377              
378             Copyright 2009-2010 Alex Efros <powerman-asdf@ya.ru>.
379              
380             This program is distributed under the MIT (X11) License:
381             L<http://www.opensource.org/licenses/mit-license.php>
382              
383             Permission is hereby granted, free of charge, to any person
384             obtaining a copy of this software and associated documentation
385             files (the "Software"), to deal in the Software without
386             restriction, including without limitation the rights to use,
387             copy, modify, merge, publish, distribute, sublicense, and/or sell
388             copies of the Software, and to permit persons to whom the
389             Software is furnished to do so, subject to the following
390             conditions:
391              
392             The above copyright notice and this permission notice shall be
393             included in all copies or substantial portions of the Software.
394              
395             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
396             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
397             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
398             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
399             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
400             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
401             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
402             OTHER DEALINGS IN THE SOFTWARE.
403