generalize reading post input
[perl/plp/.git] / PLP.pm
1 package PLP;
2
3 use 5.006;
4
5 use PLP::Functions ();
6 use PLP::Fields;
7 use PLP::Tie::Headers;
8 use PLP::Tie::Delay;
9 use PLP::Tie::Print;
10
11 use File::Basename ();
12 use File::Spec;
13
14 use strict;
15
16 our $VERSION = '3.19';
17
18 # Subs in this package:
19 #  _default_error($plain, $html)    Default error handler
20 #  clean                            Reset variables
21 #  error($error, $type)             Handle errors
22 #  everything                       Do everything: CGI
23 #  handler($r)                      Do everything: mod_perl
24 #  sendheaders                      Send headers
25 #  source($path, $level, $linespec) Read and parse .plp files
26 #  start                            Start the initialized PLP script
27
28 # The _init subs do the following:
29 #  Set $PLP::code to the initial code
30 #  Set $ENV{PLP_*} and make PATH_INFO if needed
31 #  Change the CWD
32
33 # This gets referenced as the initial $PLP::ERROR
34 sub _default_error {
35         my ($plain, $html) = @_; 
36         print qq{<table border=1 class="PLPerror"><tr><td>},
37               qq{<b>Debug information:</b><br>$html</td></tr></table>};
38 }
39
40 # This cleans up from previous requests, and sets the default $PLP::DEBUG
41 sub clean {
42         @PLP::END = ();
43         $PLP::code = '';
44         $PLP::sentheaders = 0;
45         $PLP::DEBUG = 1;
46         $PLP::print = '';
47         $PLP::r = undef;
48         delete @ENV{ grep /^PLP_/, keys %ENV };
49 }
50
51 # Handles errors, uses subref $PLP::ERROR (default: \&_default_error)
52 sub error {
53         my ($error, $type) = @_;
54         if (not defined $type or $type < 100) {
55                 return undef unless $PLP::DEBUG & 1;
56                 my $plain = $error;
57                 (my $html = $plain) =~ s/([<&>])/'&#' . ord($1) . ';'/ge;
58                 PLP::sendheaders() unless $PLP::sentheaders;
59                 $PLP::ERROR->($plain, $html);
60         } else {
61                 select STDOUT;
62                 my ($short, $long) = @{
63                         +{
64                                 404 => [
65                                         'Not Found',
66                                         "The requested URL $ENV{REQUEST_URI} was not found " .
67                                         "on this server."
68                                 ],
69                                 403 => [
70                                         'Forbidden',
71                                         "You don't have permission to access $ENV{REQUEST_URI} " .
72                                         "on this server."
73                                 ],
74                         }->{$type}
75                 };
76                 print "Status: $type\nContent-Type: text/html\n\n",
77                         qq{<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html>},
78                         "<head>\n<title>$type $short</title>\n</head></body>\n<h1>$short",
79                         "</h1>\n$long<p>\n<hr>\n$ENV{SERVER_SIGNATURE}</body></html>";
80         }
81 }
82
83 # Wrap old request handlers.
84 sub everything {
85         require PLP::CGI;
86         PLP::CGI::everything();
87 }
88 sub handler {
89         require PLP::Apache;
90         PLP::Apache::handler(@_);
91 }
92
93 # Sends the headers waiting in %PLP::Script::header
94 sub sendheaders () {
95         $PLP::sentheaders ||= [ caller 1 ? (caller 1)[1, 2] : (caller)[1, 2] ];
96         print STDOUT "Content-Type: text/plain\n\n" if $PLP::DEBUG & 2;
97         print STDOUT map("$_: $PLP::Script::header{$_}\n", keys %PLP::Script::header), "\n";
98 }
99
100 {
101         my %cached; # Conceal cached sources: ( path => [ [ deps ], source, -M ] )
102         
103         # Given a filename and optional level (level should be 0 if the caller isn't
104         # source() itself), and optional linespec (used by PLP::Functions::Include),
105         # this function parses a PLP file and returns Perl code, ready to be eval'ed
106         sub source {
107                 my ($file, $level, $linespec, $path) = @_;
108                 our $use_cache;
109
110                 # $file is displayed, $path is used. $path is constructed from $file if
111                 # not given.
112
113                 $level = 0      unless defined $level;
114                 $linespec = '1' unless defined $linespec;
115                 
116                 if ($level > 128) {
117                         %cached = ();
118                         return $level
119                                 ? qq{\cQ; die qq[Include recursion detected]; print q\cQ}
120                                 : qq{\n#line $linespec\ndie qq[Include recursion detected];};
121                 }
122
123                 my $in_block = 0;   # 1 => "<:", 2 => "<:="
124                 
125                 $path ||= File::Spec->rel2abs($file);
126                 
127                 my $source_start = $level
128                         ? qq/\cQ;\n#line 1 "$file"\n$PLP::print q\cQ/
129                         : qq/\n#line 1 "$file"\n$PLP::print q\cQ/;
130                 
131                 if ($use_cache and exists $cached{$path}) {
132                         BREAKOUT: {
133                                 my @checkstack = ($path);
134                                 my $item;
135                                 my %checked;
136                                 while (defined(my $item = shift @checkstack)) {
137                                         next if $checked{$item};
138                                         last BREAKOUT if $cached{$item}[2] > -M $item;
139                                         $checked{$item} = 1;
140                                         push @checkstack, @{ $cached{$item}[0] }
141                                                 if @{ $cached{$item}[0] };
142                                 }
143                                 return $level
144                                         ? $source_start . $cached{$path}[1]
145                                         : $source_start . $cached{$path}[1] . "\cQ";
146                         }
147                 }
148
149                 $cached{$path} = [ [ ], undef, undef ] if $use_cache;
150                 
151                 my $linenr = 0;
152                 my $source = '';
153
154                 local *SOURCE;
155                 open SOURCE, '<', $path or return $level
156                         ? qq{\cQ; die qq[Can't open "\Q$path\E" (\Q$!\E)]; print q\cQ}
157                         : qq{\n#line $linespec\ndie qq[Can't open "\Q$path\E" (\Q$!\E)];};
158                 
159                 LINE:
160                 while (defined (my $line = <SOURCE>)) {
161                         $linenr++;
162                         for (;;) {
163                                 $line =~ /
164                                         \G                  # Begin where left off
165                                         ( \z                # End
166                                         | <:=? | :>         # PLP tags     <:= ... :> <: ... :>
167                                         | <\([^)]*\)>       # Include tags <(...)>
168                                         | <[^:(][^<:]*      # Normal text
169                                         | :[^>][^<:]*       # Normal text
170                                         | [^<:]*            # Normal text
171                                         )
172                                 /gxs;
173                                 next LINE unless length $1;
174                                 my $part = $1;
175                                 if ($part eq '<:=' and not $in_block) {
176                                         $in_block = 2;
177                                         $source .= "\cQ, (";
178                                 } elsif ($part eq '<:' and not $in_block) {
179                                         $in_block = 1;
180                                         $source .= "\cQ; ";
181                                 } elsif ($part eq ':>' and $in_block) {
182                                         $source .= (
183                                                 $in_block == 2
184                                                         ? "), q\cQ"              # 2
185                                                         : "; $PLP::print q\cQ"   # 1
186                                         );
187                                         $in_block = 0;
188                                 } elsif ($part =~ /^<\((.*?)\)>\z/ and not $in_block) {
189                                         my $ipath = File::Spec->rel2abs(
190                                                 $1, File::Basename::dirname($path)
191                                         );
192                                         $source .= source($1, $level + 1, undef, $ipath) .
193                                                    qq/\cQ, \n#line $linenr "$file"\nq\cQ/;
194                                         push @{ $cached{$path}[0] }, $ipath;
195                                 } else {
196                                         $part =~ s/\\/\\\\/ unless $in_block;
197                                         $source .= $part;
198                                 }
199                         }
200                 }
201                 
202                 if ($in_block) {
203                         $source .= (
204                                 $in_block == 2
205                                         ? "), q\cQ"              # 2
206                                         : "; $PLP::print q\cQ"   # 1
207                         );
208                 }
209
210                 if ($use_cache) {
211                         $cached{$path}[1] = $source;
212                         $cached{$path}[2] = -M $path;
213                 }
214
215                 return $level
216                         ? $source_start . $source
217                         : $source_start . $source . "\cQ";
218         }
219 }
220
221
222 # Let the games begin! No lexicals may exist at this point.
223 sub start {
224         no strict;
225         tie *PLPOUT, 'PLP::Tie::Print';
226         select PLPOUT;
227         $PLP::ERROR = \&_default_error;
228
229         PLP::Fields::doit();
230         {
231                 package PLP::Script;
232                 use vars qw(%headers %header %cookies %cookie %get %post %fields);
233                 *headers = \%header;
234                 *cookies = \%cookie;
235                 PLP::Functions->import();
236
237                 # No lexicals may exist at this point.
238                 
239                 eval qq{ package PLP::Script; $PLP::code; };
240                 PLP::error($@, 1) if $@ and $@ !~ /\cS\cT\cO\cP/;
241
242                 eval   { package PLP::Script; $_->() for reverse @PLP::END };
243                 PLP::error($@, 1) if $@ and $@ !~ /\cS\cT\cO\cP/;
244         }
245         PLP::sendheaders() unless $PLP::sentheaders;
246         select STDOUT;
247         undef *{"PLP::Script::$_"} for keys %PLP::Script::;
248         # Symbol::delete_package('PLP::Script');
249         # The above does not work. TODO - find out why not.
250 }
251
252 1;
253
254 =head1 NAME
255
256 PLP - Perl in HTML pages
257
258 =head1 SYNOPSIS
259
260 =head2 mod_perl installation
261
262 =over 10
263
264 =item * httpd.conf (for mod_perl setup)
265
266     <Files *.plp>
267         SetHandler perl-script
268         PerlHandler PLP::Apache
269         PerlSendHeader On
270         PerlSetVar PLPcache On
271     </Files>
272
273     # Who said CGI was easier to set up? :)
274
275 =back
276
277 =head2 CGI installation
278
279 =over 10
280
281 =item * /foo/bar/plp.cgi (local filesystem address)
282
283     #!/usr/bin/perl
284     use PLP::CGI;
285     PLP::CGI::everything();
286
287 =item * httpd.conf (for CGI setup)
288
289     ScriptAlias /foo/bar/ /PLP_COMMON/
290     <Directory /foo/bar/>
291         AllowOverride None
292         Options +ExecCGI
293         Order allow,deny
294         Allow from all
295     </Directory>
296     AddHandler plp-document plp
297     Action plp-document /PLP_COMMON/plp.cgi
298
299 =back
300
301 =head2 Test script (test.plp)
302
303     <html><body>
304     <:
305         print "Hurrah, it works!<br>" for 1..10;
306     :>
307     </body></html>
308
309 =head1 DESCRIPTION
310
311 PLP is yet another Perl embedder, primarily for HTML documents. Unlike with
312 other Perl embedders, there is no need to learn a meta-syntax or object
313 model: one can just use the normal Perl constructs. PLP runs under mod_perl
314 for speeds comparable to those of PHP, but can also be run as a CGI script.
315
316 =head2 PLP Syntax
317
318 =over 22
319
320 =item C<< <: perl_code(); :> >>
321
322 With C<< <: >> and C<< :> >>, you can add Perl code to your document. This is
323 what PLP is all about. All code outside of these tags is printed. It is
324 possible to mix perl language constructs with normal HTML parts of the document:
325
326     <: unless ($ENV{REMOTE_USER}) { :>
327         You are not logged in.
328     <: } :>
329
330 C<< :> >> always stops a code block, even when it is found in a string literal.
331
332 =item C<< <:= $expression :> >>
333
334 Includes a dynamic expression in your document. The expression is evaluated in
335 list context. Please note that the expression should not end a statement: avoid
336 semi-colons. No whitespace may be between C<< <: >> and the equal sign.
337
338 C<< foo <:= $bar :> $baz >> is like C<< <: print 'foo ', $bar, ' $baz'; :> >>.
339
340 =item C<< <(filename)> >>
341
342 Includes another file before the PLP code is executed. The file is included
343 literally, so it shares lexical variables. Because this is a compile-time tag,
344 it's fast, but you can't use a variable as the filename. You can create
345 recursive includes, so beware! (PLP will catch simple recursion: the maximum
346 depth is 128.) Whitespace in the filename is not ignored so C<< <( foo.txt)> >>
347 includes the file named C< foo.txt>, including the space in its name. A
348 compile-time alternative is include(), which is described in L<PLP::Functions>.
349
350 =back
351
352 =head2 PLP Functions
353
354 These are described in L<PLP::Functions>.
355
356 =head2 PLP Variables
357
358 =over 22
359
360 =item $ENV{PLP_NAME}
361
362 The URI of the PLP document, without the query string. (Example: C</foo.plp>)
363
364 =item $ENV{PLP_FILENAME}
365
366 The filename of the PLP document. (Example: C</var/www/index.plp>)
367
368 =item $PLP::VERSION
369
370 The version of PLP.
371
372 =item $PLP::DEBUG
373
374 Controls debugging output, and should be treated as a bitmask. The least
375 significant bit (1) controls if run-time error messages are reported to the
376 browser, the second bit (2) controls if headers are sent twice, so they get
377 displayed in the browser. A value of 3 means both features are enabled. The
378 default value is 1.
379
380 =item $PLP::ERROR
381
382 Contains a reference to the code that is used to report run-time errors. You
383 can override this to have it in your own design, and you could even make it
384 report errors by e-mail. The sub reference gets two arguments: the error message
385 as plain text and the error message with special characters encoded with HTML 
386 entities.
387
388 =item %header, %cookie, %get, %post, %fields
389
390 These are described in L<PLP::Fields>.
391
392 =back
393
394 =head2 (mod_perl only) PerlSetVar configuration directives
395
396 =over 22
397
398 =item PLPcache
399
400 Sets caching B<On>/B<Off>. When caching, PLP saves your script in memory and
401 doesn't re-read and re-parse it if it hasn't changed. PLP will use more memory,
402 but will also run 50% faster.
403
404 B<On> is default, anything that isn't =~ /^off$/i is considered On.
405
406 =back
407
408 =head2 Things that you should know about
409
410 Not only syntax is important, you should also be aware of some other important
411 features. Your script runs inside the package C<PLP::Script> and shouldn't
412 leave it. This is because when your script ends, all global variables in the
413 C<PLP::Script> package are destroyed, which is very important if you run under
414 mod_perl (they would retain their values if they weren't explicitly destroyed).
415
416 Until your first output, you are printing to a tied filehandle C<PLPOUT>. On
417 first output, headers are sent to the browser and C<STDOUT> is selected for
418 efficiency. To set headers, you must assign to C<$header{ $header_name}> before
419 any output. This means the opening C<< <: >> have to be the first characters in
420 your document, without any whitespace in front of them. If you start output and
421 try to set headers later, an error message will appear telling you on which
422 line your output started. An alternative way of setting headers is using Perl's
423 BEGIN blocks. BEGIN blocks are executed as soon as possible, before anything
424 else.
425
426 Because the interpreter that mod_perl uses never ends, C<END { }> blocks won't
427 work properly. You should use C<PLP_END { };> instead. Note that this is a not
428 a built-in construct, so it needs proper termination with a semi-colon (as do
429 C<eval> and C<do>).
430
431 Under mod_perl, modules are loaded only once. A good modular design can improve
432 performance because of this, but you will have to B<reload> the modules
433 yourself when there are newer versions. 
434
435 The special hashes are tied hashes and do not always behave the way you expect,
436 especially when mixed with modules that expect normal CGI environments, like
437 CGI.pm. Read L<PLP::Fields> for information more about this.
438
439 =head1 FAQ and HowTo
440
441 A lot of questions are asked often, so before asking yours, please read the 
442 FAQ at L<PLP::FAQ>. Some examples can be found at L<PLP::HowTo>.
443
444 =head1 NO WARRANTY
445
446 No warranty, no guarantees. Use PLP at your own risk, as I disclaim all
447 responsibility.
448
449 =head1 AUTHORS
450
451 Currently maintained by Mischa POSLAWSKY <perl@shiar.org>
452
453 Originally by Juerd Waalboer <juerd@cpan.org>
454
455 =head1 SEE ALSO
456
457 L<PLP::Functions>, L<PLP::Fields>, L<PLP::FAQ>, L<PLP::HowTo>
458
459 =cut
460
461 ### Garbage bin
462
463 # About the #S lines:
464 # I wanted to implement Safe.pm so that scripts were run inside a
465 # configurable compartment. This needed for XS modules to be pre-loaded,
466 # hence the PLPsafe_* Apache directives. However, $safe->reval() lets
467 # Apache segfault. End of fun. The lines are still here so that I can
468 # s/^#S //g to re-implement them whenever this has been fixed.
469
470 #S # For PLPsafe scripts
471 #S sub safe_eval {
472 #S     my ($r, $code) = @_;
473 #S     $r->send_http_header('text/plain');
474 #S     require Safe;
475 #S     unless ($PLP::safe) {
476 #S      $PLP::safe = Safe->new('PLP::Script');
477 #S      for ( map split, $r->dir_config->get('PLPsafe_module') ) {
478 #S          $PLP::safe->share('*' . $_ . '::');
479 #S          s!::!/!g;
480 #S          require $_ . '.pm';
481 #S      }
482 #S      $PLP::safe->permit(Opcode::full_opset());
483 #S      $PLP::safe->deny(Opcode::opset(':dangerous'));
484 #S     }
485 #S     $PLP::safe->reval($code);
486 #S }
487 #S  my ($r) = @_;
488
489 # start()
490 #S      if ($PLP::use_safe) {
491 #S          PLP::safe_eval($r, $PLP::code);
492 #S      } else {
493 #           eval qq{ package PLP::Script; $PLP::code; };
494 #S      }
495 #       PLP::error($@, 1) if $@ and $@ !~ /\cS\cT\cO\cP/;
496 #S      if ($PLP::use_safe) {
497 #S          PLP::safe_eval($r, '$_->() for reverse @PLP::END');
498 #S      } else {
499 #           eval   { package PLP::Script; $_->() for reverse @PLP::END };
500 #S      }
501 #       PLP::error($@, 1) if $@ and $@ !~ /\cS\cT\cO\cP/;
502
503 ###