File Coverage

blib/lib/HTML/EP.pm
Criterion Covered Total %
statement 349 605 57.6
branch 166 344 48.2
condition 32 148 21.6
subroutine 33 54 61.1
pod 0 26 0.0
total 580 1177 49.2


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # HTML::EP - A Perl based HTML extension.
4             #
5             #
6             # Copyright (C) 1998 Jochen Wiedmann
7             # Am Eisteich 9
8             # 72555 Metzingen
9             # Germany
10             #
11             # Email: joe@ispsoft.de
12             #
13             #
14             # Portions Copyright (C) 1999 OnTV Pittsburgh, L.P.
15             # 123 University St.
16             # Pittsburgh, PA 15213
17             # USA
18             #
19             # Phone: 1 412 681 5230
20             # Developer: Jason McMullan
21             # Developer: Erin Glendenning
22             #
23             #
24             # All rights reserved.
25             #
26             # You may distribute this module under the terms of either
27             # the GNU General Public License or the Artistic License, as
28             # specified in the Perl README file.
29             #
30             ############################################################################
31              
32             require 5.005;
33 8     8   22314 use strict;
  8         17  
  8         347  
34              
35 8     8   159909 use CGI ();
  8         20731030  
  8         234  
36 8     8   16621 use Symbol ();
  8         7467  
  8         173  
37 8     8   4780 use HTML::EP::Config ();
  8         32  
  8         163  
38 8     8   3837 use HTML::EP::Parser ();
  8         26  
  8         31091  
39              
40              
41             package HTML::EP;
42              
43             $HTML::EP::VERSION = '0.2011';
44              
45              
46             sub new {
47 86     86 0 27078 my $proto = shift;
48 86 100       315 my $self = (@_ == 1) ? {%{shift()}} : { @_ };
  9         34  
49 86         304 $self->{'_ep_output'} = '';
50 86         202 $self->{'_ep_output_stack'} = [];
51 86   33     532 $self->{'_ep_config'} ||= $HTML::EP::Config::CONFIGURATION;
52 86   50     336 $self->{'debug'} ||= 0;
53 86   50     547 $self->{'cgi'} ||= (CGI->new() || die "Failed to create CGI object: $!");
      33        
54 86   33     61229 bless($self, (ref($proto) || $proto));
55             }
56              
57             sub Run {
58 84     84 0 1918 my($self, $template) = @_;
59 84         365 my $parser = HTML::EP::Parser->new();
60 84         161 my $r = $self->{'_ep_r'};
61 84 50 33     524 $self->{'env'} ||= $r ?
62             { $r->cgi_env(), 'PATH_INFO' => $r->uri() } : \%ENV;
63 84 50       164 if ($template) {
64 84         966 $parser->parse($template);
65             } else {
66 0   0     0 my $file = $self->{'env'}->{'PATH_TRANSLATED'}
67             || die "Missing server environment (PATH_TRANSLATED variable)";
68 0         0 my $fh = Symbol::gensym();
69 0 0       0 open($fh, "<$file") || die "Failed to open $file: $!";
70 0         0 $parser->parse_file($fh);
71             }
72 84         359 $parser->eof();
73 84         316 my $tokens = HTML::EP::Tokens->new('tokens' => $parser->{'_ep_tokens'});
74 84         360 $self->{'_ep_output'} = $self->ParseVars($self->TokenMarch($tokens));
75             }
76              
77              
78             sub CgiRun {
79 0     0 0 0 my($self, $path, $r) = @_;
80 0         0 my $cgi = $self->{'cgi'};
81 0         0 my $ok_templates = $self->{'_ep_config'}->{'ok_templates'};
82 0         0 local $| = 1;
83 0         0 my $output = eval {
84 0 0 0     0 die "Access to $path forbidden; check ok_templates in ",
85             $INC{'HTML/EP/Config.pm'}
86             if $ok_templates && $path !~ /$ok_templates/;
87 0 0       0 $self->_ep_debug({}) if $cgi->param('debug');
88 0         0 $self->Run();
89             };
90              
91 0 0       0 if ($@) {
92 0 0       0 if ($@ =~ /_ep_exit, ignore/) {
93 0         0 $output .= $self->ParseVars($self->{'_ep_output'});
94             } else {
95 0         0 my $errmsg;
96 0         0 my $errstr = $@;
97 0 0       0 my $errfile = $self->{_ep_err_type} ?
98             $self->{_ep_err_file_user} : $self->{_ep_err_file_system};
99 0 0       0 if ($errfile) {
100 0 0       0 if ($errfile =~ /^\//) {
101 0 0       0 my $derrfile = $r ?
102             $r->cgi_var('DOCUMENT_ROOT') : $ENV{'DOCUMENT_ROOT'}
103             . $errfile;
104 0 0       0 if ($self->{'debug'}) {
105 0         0 $self->print("Error type = " . $self->{_ep_err_type} .
106             ", error file = $errfile" .
107             ", derror file = $derrfile\n");
108             }
109 0 0       0 if (-f $derrfile) { $errfile = $derrfile }
  0         0  
110             }
111 0         0 my $fh = Symbol::gensym();
112 0 0       0 if (open($fh, "<$errfile")) {
113 0         0 local $/ = undef;
114 0         0 $errmsg = <$fh>;
115 0         0 close($fh);
116             }
117             }
118 0 0       0 if (!$errmsg) {
119 0 0       0 $errmsg = $self->{_ep_err_type} ?
120             $self->{_ep_err_msg_user} : $self->{_ep_err_msg_system};
121             }
122 0         0 return $self->SimpleError($errmsg, $errstr);
123             }
124             }
125              
126 0 0       0 if (!$self->{_ep_stop}) {
127 0         0 $self->print($cgi->header($self->SetCookies(),
128 0         0 %{$self->{'_ep_headers'}}), $output);
129             }
130             }
131              
132             sub FindEndTag {
133 29     29 0 47 my($self, $tokens, $tag) = @_;
134 29         32 my $level = 0;
135 29         77 while (defined(my $token = $tokens->Token())) {
136 77 100       285 if ($token->{'type'} eq 'S') {
    100          
137 9 100       42 ++$level if $token->{'tag'} eq $tag;
138             } elsif ($token->{'type'} eq 'E') {
139 36 100       81 if ($token->{'tag'} eq $tag) {
140 34 100       127 return $tokens->First() unless $level--;
141             }
142             }
143             }
144 0         0 die "$tag without /$tag";
145             }
146              
147             sub AttrVal {
148 12     12 0 29 my($self, $val, $tokens, $token, $parse) = @_;
149 12 100       30 return $val if defined($val);
150 9         26 my $first = $tokens->First();
151 9 50       34 my $last = $self->FindEndTag($tokens,
152             ref($token) ? $token->{'tag'} : $token);
153 9         32 my $output = $self->TokenMarch($tokens->Clone($first, $last-1));
154 9 100       47 $parse ? $self->ParseVars($output) : $output;
155             }
156              
157             sub ParseAttr {
158 152     152 0 192 my $self = shift; my $attr = shift;
  152         242  
159 152         216 my $parsed_attr = {};
160 152         619 while (my($var, $val) = each %$attr) {
161 187 100       575 if ($val =~ /\$\_\W/) {
    100          
162 49         90 $_ = $self;
163 49         1442 $parsed_attr->{$var} = eval $val;
164 49 50       281 die $@ if $@;
165             } elsif ($val =~ /\$/) {
166 34         87 $parsed_attr->{$var} = $self->ParseVars($val);
167             } else {
168 104         497 $parsed_attr->{$var} = $val;
169             }
170             }
171 152         558 $parsed_attr;
172             }
173              
174             sub RepeatedTokenMarch {
175 75     75 0 87 my $self = shift; my $tokens = shift;
  75         85  
176 75         182 my $first = $tokens->First();
177 75         196 my $last = $tokens->Last();
178 75         156 my $res = $self->TokenMarch($tokens);
179 75         188 $tokens->First($first);
180 75         170 $tokens->Last($last);
181 75         267 $res;
182             }
183             sub TokenMarch {
184 227     227 0 309 my($self, $tokens) = @_;
185 227         318 my $debug = $self->{'debug'};
186              
187 227         460 push(@{$self->{'_ep_output_stack'}}, $self->{'_ep_output'});
  227         559  
188 227         425 $self->{'_ep_output'} = '';
189 227 50       478 $self->print("TokenMarch: From ", $tokens->First(), " to ",
190             $tokens->Last(), ".\n") if $debug >= 2;
191 227         622 while (defined(my $token = $tokens->Token())) {
192 337         549 my $type = $token->{'type'};
193 337         341 my $res;
194 337 100       803 if ($type eq 'T') {
    100          
    50          
    0          
195 205         342 $res = $token->{'text'};
196             } elsif ($token->{'type'} eq 'S') {
197 126         237 my $method = "_$token->{'tag'}";
198 126         177 my $attr = $token->{'attr'};
199 126         540 $method =~ s/\-/_/g;
200 126         320 $res = $self->$method($self->ParseAttr($attr), $tokens, $token);
201 120 50       474 if (!defined($res)) {
202             # Upwards compatibility: If the method returned undef, then
203             # it is a multiline tag in the sense of EP1. We've got to
204             # collect all lines until a matching /$tag and evaluate it.
205 0         0 my $def = delete $tokens->{'default'};
206 0         0 my $first = $tokens->First();
207 0         0 my $last = $self->FindEndTag($tokens, $token->{'tag'});
208 0         0 my $t = $tokens->Clone($first, $last-1);
209 0         0 $attr->{$def} = $self->TokenMarch($t);
210 0         0 $res = $self->$method($attr, $tokens);
211             }
212             } elsif ($token->{'type'} eq 'I') {
213 6         14 $res = $self->RepeatedTokenMarch($token->{'tokens'});
214             } elsif ($token->{'type'} eq 'E') {
215 0         0 die "Unexpected end tag: /$token->{'tag'} without $token->{'tag'}";
216             } else {
217 0         0 die "Unknown token type $self->{'type'}";
218             }
219 331         1266 $self->{'_ep_output'} .= $res;
220             }
221 221         380 my $result = $self->{'_ep_output'};
222 221 50       419 $self->print("TokenMarch: Returning $result.\n") if $debug >= 2;
223 221         222 $self->{'_ep_output'} = pop(@{$self->{'_ep_output_stack'}});
  221         458  
224 221         708 $result;
225             }
226              
227              
228              
229              
230             sub WarnHandler {
231 0     0 0 0 my $msg = shift;
232 0 0       0 die $msg unless defined($^S);
233 0         0 print STDERR $msg;
234 0 0       0 print STDERR "\n" unless $msg =~ /\n$/;
235             }
236              
237              
238             sub SimpleError {
239 0     0 0 0 my($self, $template, $errmsg, $admin) = @_;
240 0         0 my $r;
241 0 0 0     0 $r = $self->{'_ep_r'} if $self && ref($self);
242 0 0 0     0 $admin ||= ($r ? $r->cgi_var('SERVER_ADMIN') : $ENV{'SERVER_ADMIN'});
243 0 0       0 $admin = $admin ? "Webmaster" : 'Webmaster';
244 0         0 my $vars = { errmsg => $errmsg, admin => $admin };
245              
246 0 0       0 if (!$template) {
247 0         0 $template = <<'END_OF_HTML';
248             Fatal internal error
249            

Fatal internal error

250            

An internal error occurred. The error message is:

251            
 
252             $errmsg$.
253            
254            

Please contact the $admin$ and tell him URL, time and error message.

255            

We apologize for any inconvenience, please try again later.

256            


257            

Yours sincerely

258            
259             END_OF_HTML
260             }
261              
262 0         0 $template =~ s/\$(\w+)\$/$vars->{$1}/g;
263 0 0       0 if ($r) {
264 0         0 $r->print($self->{'cgi'}->header('-type' => 'text/html'), $template);
265             } else {
266 0         0 print("content-type: text/html\n\n", $template);
267 0         0 exit 0;
268             }
269             }
270              
271             sub print ($;@) {
272 0     0 0 0 my $self = shift;
273 0 0       0 $self->{_ep_r} ? $self->{_ep_r}->print(@_) : print @_;
274             }
275              
276             sub printf {
277 0     0 0 0 my($self, $format, @args) = @_;
278 0         0 $self->print(sprintf($format, @args));
279             }
280              
281             sub escapeHTML {
282 192     192 0 227 my $self = shift; my $str = shift;
  192         215  
283 192         277 $str =~ s/&/&/g;
284 192         225 $str =~ s/\"/"/g;
285 192         200 $str =~ s/>/>/g;
286 192         208 $str =~ s/
287 192         209 $str =~ s/\$/$/g;
288 192         453 $str;
289             }
290              
291             sub FindVar {
292 208     208 0 366 my($self, $var, $subvar) = @_;
293 208 50       530 if ($var eq 'cgi') {
294 0         0 $subvar =~ s/\-\>//;
295 0         0 return $self->{'cgi'}->param($subvar);
296             }
297              
298 208         306 $var = $self->{$var};
299 208   66     575 while ($subvar && $subvar =~ /^\-\>(\w+)(.*)/) {
300 31 50       69 return '' unless ref $var;
301 31         44 my $v = $1;
302 31         45 $subvar = $2;
303 31 100       369 if ($v =~ /^\d+$/) {
304 4         19 $var = $var->[$v];
305             } else {
306 27         126 $var = $var->{$v};
307             }
308             }
309 208 50       537 defined $var ? $var : '';
310             }
311              
312             sub ParseVar {
313 207     207 0 607 my($self, $type, $var, $subvar) = @_;
314 207         233 my $func;
315              
316 207 100 100     505 if ($type && $type eq '&') {
317             # Custom format
318 9 50       38 $func = exists($self->{'_ep_custom_formats'}->{$var}) ?
319             $self->{'_ep_custom_formats'}->{$var} : "_format_$var";
320              
321             # First part of subvar becomes var
322 9 50 33     66 if ($subvar && $subvar =~ /^\-\>(\w+)(.*)/) {
323 9         1105 $var = $1;
324 9         19 $subvar = $2;
325             } else {
326 0         0 $var = '';
327             }
328             }
329              
330 207         437 $var = FindVar($self, $var, $subvar);
331              
332 207 100 100     721 if (!$type || $type eq '%') {
    100          
    50          
    100          
333 191         581 $var = $self->escapeHTML($var);
334             } elsif ($type eq '#') {
335 3         14 $var = CGI->escape($var);
336             } elsif ($type eq '~') {
337 0   0     0 my $dbh = $self->{'dbh'} || die "Not connected";
338 0         0 $var = $dbh->quote($var);
339             } elsif ($func) {
340 9         74 $var = $self->$func($var);
341             }
342              
343 207         857 $var;
344             }
345              
346             sub ParseVars ($$) {
347 206     206 0 345 my($self, $str) = @_;
348 206         1088 $str =~ s/\$([\&\@\#\~\%]?)(\w+)((?:\-\>\w+)*)\$/$self->ParseVar($1,$2,$3)/eg;
  206         456  
349 206         2309 $str;
350             }
351              
352              
353              
354             # For debugging
355             sub Dump {
356 0     0 0 0 my $self = shift;
357 0         0 require Data::Dumper;
358 0         0 Data::Dumper->new([@_])->Indent(1)->Terse(1)->Dump();
359             }
360              
361             sub SetCookies {
362 0     0 0 0 my $self = shift;
363 0         0 my @cookies = values %{$self->{'_ep_cookies'}};
  0         0  
364 0 0       0 return () unless @cookies;
365 0 0       0 print "Setting cookies:\n", $self->Dump(\@cookies), "\n"
366             if $self->{'debug'};
367 0         0 ('-cookie' => \@cookies);
368             }
369              
370              
371              
372             sub EvalIf {
373 83     83 0 118 my($self, $tag, $attr) = @_;
374 83         119 my $debug = $self->{'debug'};
375 83 100       211 if (exists($attr->{'eval'})) {
376 55 50       99 $self->print("$tag: Evaluating $attr->{'eval'}\n") if $debug;
377 55         256 return $attr->{'eval'};
378             }
379 28 100       69 if (exists($attr->{'neval'})) {
380 2 50       6 $self->print("$tag: Evaluating ! $attr->{'neval'}\n") if $debug;
381 2         7 return !$attr->{'neval'};
382             }
383 26 50       65 die "Missing condition" unless(exists($attr->{'cnd'}));
384 26 100       160 if ($attr->{'cnd'} =~ /^(.*?)(==|!=|<=?|>=?)(.*)$/) {
385 22 50       49 $self->print("$tag: Numeric condition $1 $2 $3\n") if $debug;
386 22   50     72 my $left = $1 || 0;
387 22         39 my $cnd = $2;
388 22   50     70 my $right = $3 || 0;
389 22 100       60 return ($left == $right) if $cnd eq '==';
390 19 100       50 return ($left != $right) if $cnd eq '!=';
391 16 100       57 return ($left < $right) if $cnd eq '<';
392 9 100       35 return ($left > $right) if $cnd eq '>';
393 6 100       22 return ($left >= $right) if $cnd eq '>=';
394 3         11 return ($left <= $right);
395             }
396 4 50       27 die "Cannot parse condition cnd=$attr->{'cnd'}"
397             unless $attr->{'cnd'} =~ /^\s*\'(.*?)\'\s*(eq|ne)\s*\'(.*)\'\s*$/;
398 4 50       9 $self->print("$tag: String condition $1 $2 $3\n") if $debug;
399 4 100       17 return $1 eq $3 if $2 eq 'eq';
400 2         7 return $1 ne $3;
401             }
402              
403              
404              
405 16     16 0 34 sub init { 1 }
406              
407 0     0 0 0 sub Stop ($) { my($self) = @_; $self->{_ep_stop} = 1; }
  0         0  
408              
409              
410             sub _ep_comment {
411 2     2   4 my $self = shift; my $attr = shift;
  2         3  
412 2         12 $self->AttrVal($attr->{'comment'}, @_);
413 2         5 '';
414             }
415              
416              
417             sub _ep_package {
418 15     15   24 my $self = shift; my $attr = shift;
  15         38  
419 15         28 my $package = $attr->{name};
420 15 50 33     47 if (!exists($attr->{'require'}) || $attr->{'require'}) {
421 15 50       41 my @inc = ($ENV{'DOCUMENT_ROOT'} . $attr->{'lib'},
422             $attr->{'lib'}, @INC) if $attr->{'lib'};
423 15 50       37 local @INC = @inc if @inc;
424 15         23 my $ppm = $package;
425 15         54 $ppm =~ s/\:\:/\//g;
426 15         2084 require "$ppm.pm";
427             }
428              
429 15   100     83 my $pack = ($self->{'_ep_package'} || 0) + 1;
430 15 100 66     77 if ($attr->{'isa'} || $self->{'_ep_package'}) {
431             # If ep-package is called multiple times, or if $attr->{'isa'}
432             # is set, we create a new package and bless $self into it.
433 1         3 my @isa;
434 1 50       21 @isa = split(',', $attr->{'isa'}) if @isa;
435 1         4 my $p = ref($self);
436 8     8   104 no strict 'refs';
  8         15  
  8         47163  
437 1         3 push(@isa, $p);
438 1         4 my $bpack = "HTML::EP::PACK$pack";
439 1         3 @{"$bpack\::ISA"} = ($package, @isa);
  1         32  
440 1         7 bless($self, $bpack);
441             } else {
442             # Otherwise it's faster to bless $self into the package
443 14         37 bless($self, $package);
444             }
445 15         50 $self->{'_ep_package'} = $pack;
446              
447 15         57 $self->init($attr);
448 15         36 '';
449             }
450              
451             sub _ep_debug {
452 0     0   0 my $self = shift;
453 0         0 my $cgi = $self->{'cgi'};
454              
455 0         0 my $debughosts = $self->{'_ep_config'}->{'debughosts'};
456 0 0       0 if ($debughosts) {
457 0         0 my $remoteip = '';
458 0         0 my $remotehost = '';
459 0 0 0     0 if ($self->{'_ep_r'} && (my $r = $self->{'_ep_r'})) {
460 0   0     0 $remoteip = ($r->connection()->remote_ip() || '');
461 0   0     0 $remotehost = ($r->get_remote_host() || '');
462             } else {
463 0   0     0 $remoteip = ($ENV{'REMOTE_ADDR'} || '');
464             }
465 0 0 0     0 die "Debugging not permitted from $remoteip"
      0        
466             . " ($remotehost), debug hosts = $debughosts"
467             if (($remoteip and $remoteip !~ /$debughosts/) and
468             ($remotehost !~ /$debughosts/));
469             }
470              
471 0         0 $| = 1;
472 0         0 $self->print($cgi->header('-type' => 'text/plain'));
473 0         0 $self->print("Entering debugging mode;",
474             " list of input values:\n");
475 0         0 foreach my $p ($cgi->param()) {
476 0         0 $self->print(" $p = ", $cgi->param($p), "\n");
477             }
478 0   0     0 $self->{'debug'} = $cgi->param('debug') || 1;
479 0         0 '';
480             }
481              
482             sub GetPerlCode {
483 2     2 0 2 my $self = shift; my $attr = shift;
  2         3  
484              
485 2         2 my $code;
486 2 50       4 if (my $file = $attr->{'src'}) {
487 0         0 my $fh = Symbol::gensym();
488 0 0 0     0 if (! -f $file && -f ($self->{env}->{DOCUMENT_ROOT} . $file)) {
489 0         0 $file = ($self->{env}->{DOCUMENT_ROOT} . $file);
490             }
491 0 0       0 open($fh, "<$file") || die "Cannot open $file: $!";
492 0         0 local $/ = undef;
493 0         0 $code = <$fh>;
494 0 0 0     0 die "Error while reading $file: $!" unless defined($fh) and close($fh);
495             } else {
496 2         9 $code = $self->AttrVal($attr->{'code'}, @_);
497             }
498 2         5 $code;
499             }
500              
501             sub EvalPerlCode {
502 2     2 0 2 my($self, $attr, $code) = @_;
503 2         3 my $output;
504 2 50       6 if ($attr->{'safe'}) {
505 0         0 my $compartment = $self->{_ep_compartment};
506 0 0       0 if (!$compartment) {
507 0         0 require Safe;
508 0         0 $compartment = $self->{_ep_compartment} = Safe->new();
509             }
510 0 0       0 if ($self->{debug}) {
511 0         0 $self->print("Evaluating in Safe compartment:\n$code\n");
512             }
513 0         0 local $_ = $self; # The 'local' is required for garbage collection
514 0         0 $output = $compartment->reval($code);
515             } else {
516 2   50     14 $code = "package ".
517             ($attr->{'package'} || "HTML::EP::main").";".$code;
518 2 50       9 $self->print("Evaluating script:\n$code\n") if $self->{'debug'};
519 2         4 local $_ = $self; # The 'local' is required for garbage collection
520 2         149 $output = eval $code;
521             }
522 2 50       10 die $@ if $@;
523 2 50       8 $self->printf("Script returned:\n$output\nEnd of output.\n")
524             if $self->{debug};
525 2         8 $output;
526             }
527              
528             sub EncodeByAttr {
529 2     2 0 4 my($self, $attr, $str) = @_;
530 2         5 my $debug = $self->{'debug'};
531 2 50       4 $self->print("EncodeByAttr: Input $str\n") if $debug;
532 2 50       6 if (my $type = $attr->{'output'}) {
533 0 0       0 if ($type eq 'html') {
    0          
    0          
534 0         0 $str = $self->escapeHTML($str);
535             } elsif ($type eq 'htmlbr') {
536 0         0 $str = $self->escapeHTML($str);
537 0         0 $str =~ s/\n/
/sg;
538             } elsif ($type eq 'url') {
539 0         0 $str = CGI->escape($str);
540             }
541             }
542 2 50       5 $self->print("EncodeByAttr: Output $str\n") if $debug;
543 2         4 $str;
544             }
545              
546             sub _ep_perl {
547 2     2   5 my $self = shift; my $attr = shift;
  2         3  
548 2         8 my $code = $self->GetPerlCode($attr, @_);
549 2 50       7 return undef unless defined $code;
550 2         6 $self->EncodeByAttr($attr, $self->EvalPerlCode($attr, $code));
551             }
552              
553              
554             sub _ep_database ($$;$) {
555 0     0   0 my $self = shift; my $attr = shift;
  0         0  
556 0   0     0 my $dsn = $attr->{'dsn'} || $self->{env}->{DBI_DSN};
557 0   0     0 my $user = $attr->{'user'} || $self->{env}->{DBI_USER};
558 0   0     0 my $pass = $attr->{'password'} || $self->{env}->{DBI_PASS};
559 0   0     0 my $dbhvar = $attr->{'dbh'} || 'dbh';
560 0         0 require DBI;
561 0 0       0 $self->printf("Connecting to database: dsn = %s, user = %s,"
562             . " pass = %s\n", $dsn, $user, $pass) if $self->{'debug'};
563 0         0 $self->{$dbhvar} = DBI->connect($dsn, $user, $pass,
564             { 'RaiseError' => 1, 'Warn' => 0,
565             'PrintError' => 0 });
566 0         0 '';
567             }
568              
569              
570             sub SqlSetupStatement {
571 0     0 0 0 my($self, $attr, $dbh, $statement) = @_;
572              
573 0   0     0 my $start_at = $attr->{'startat'} || 0;
574 0   0     0 my $limit = $attr->{'limit'} || -1;
575 0 0 0     0 if (($start_at || $limit != -1) &&
      0        
576             $dbh->{'ImplementorClass'} eq 'DBD::mysql::db') {
577 0         0 $statement .= " LIMIT $start_at, $limit";
578 0         0 $start_at = 0;
579             }
580 0 0       0 if ($self->{'debug'}) {
581 0         0 $self->print("Executing query, statement = $statement\n");
582 0   0     0 $self->printf("Result starting at row %s\n",
583             $attr->{'startat'} || 0);
584 0         0 $self->printf("Rows limited to %s\n", $attr->{'limit'});
585             }
586 0         0 my $sth = $dbh->prepare($statement);
587 0         0 $sth->execute();
588 0         0 ($sth, $start_at, $limit)
589             }
590              
591             sub SqlSetupResult {
592 0     0 0 0 my($self, $attr, $sth, $start_at, $limit) = @_;
593 0         0 my $result = $attr->{'result'};
594 0         0 my $list = [];
595 0         0 my $ref;
596 0   0     0 while ($limit && $start_at-- > 0) {
597 0 0       0 if (!$sth->fetchrow_arrayref()) {
598 0         0 $limit = 0;
599 0         0 last;
600             }
601             }
602 0 0 0     0 my $resultmethod =
603             (exists($attr->{'resulttype'}) && $attr->{'resulttype'} =~ /array/) ?
604             "fetchrow_arrayref" : "fetchrow_hashref";
605 0   0     0 while ($limit-- && ($ref = $sth->$resultmethod())) {
606 0 0       0 push(@$list, (ref($ref) eq 'ARRAY') ? [@$ref] : {%$ref});
607             }
608 0 0 0     0 if (exists($attr->{'resulttype'}) &&
609             $attr->{'resulttype'} =~ /^single_/) {
610 0         0 $self->{$result} = $list->[0];
611             } else {
612 0         0 $self->{$result} = $list;
613             }
614 0         0 $self->{"$result\_rows"} = scalar(@$list);
615 0 0       0 $self->print("Result: ", scalar(@$list), " rows.\n") if $self->{'debug'};
616             }
617              
618             sub _ep_query {
619 0     0   0 my($self, $attr, $tokens, $token) = @_;
620 0         0 my $debug = $self->{'debug'};
621 0         0 my $statement = $self->AttrVal($attr->{'statement'}, $tokens, $token, 1);
622 0   0     0 my $dbh = $self->{$attr->{'dbh'} || 'dbh'} || die "Not connected";
623 0 0       0 if (!exists($attr->{'result'})) {
624 0 0       0 $self->print("Doing Query: $statement\n") if $debug;
625 0         0 $dbh->do($statement);
626 0         0 return '';
627             }
628              
629 0         0 $self->SqlSetupResult($attr,
630             $self->SqlSetupStatement($attr, $dbh, $statement));
631 0         0 '';
632             }
633              
634              
635             sub _ep_select ($$;$) {
636 1     1   3 my $self = shift; my $attr = shift;
  1         5  
637 1         2 my @tags;
638 1         7 while (my($var, $val) = each %$attr) {
639 4 100       27 if ($var !~ /^template|range|format|items?|selected(?:\-text)?$/i){
640 1         6 push(@tags, sprintf('%s="%s"', $var, $self->escapeHTML($val)));
641             }
642             }
643              
644 1         6 $attr->{'format'} = '';
645 1         5 $self->_ep_list($attr, @_);
646             }
647              
648              
649             sub _ep_list {
650 20     20   33 my($self, $attr, $tokens, $token) = @_;
651 20         37 my $debug = $self->{'debug'};
652 20         23 my $template;
653 20 50       43 if (defined($attr->{'template'})) {
654 0         0 my $parser = HTML::EP::Parser->new();
655 0         0 $parser->text($attr->{'template'});
656 0         0 $template = HTML::EP::Tokens->new('tokens' => $parser->{'_ep_tokens'});
657             } else {
658 20         55 my $first = $tokens->First();
659 20         59 my $last = $self->FindEndTag($tokens, $token->{'tag'});
660 20         62 $template = $tokens->Clone($first, $last-1);
661             }
662 20         31 my $output = '';
663 20         27 my($list, $range);
664 20 100       46 if ($range = $attr->{'range'}) {
665 16 50       43 $list = [ map { $_ =~ /(\d+)\.\.(\d+)/ ? ($1 .. $2) : $_}
  16         155  
666             split(/,/, $range) ];
667             } else {
668 4         8 my $items = $attr->{'items'};
669 4 100       27 $list = ref($items) ? $items :
    50          
670             ($items =~ /^(\w+)((?:\-\>\w+)+)$/) ?
671             $self->FindVar($1, $2) : $self->{$items};
672             }
673 20 50       50 $self->print("_ep_list: Template = $template, Items = ", @$list, "\n")
674             if $debug;
675 20 50       48 my $l = $attr->{'item'} or die "Missing item name";
676 20         22 my $i = 0;
677 20         27 my $selected = $attr->{'selected'};
678 20         33 my $isSelected;
679 20         36 foreach my $ref (@$list) {
680 66         119 $self->{$l} = $ref;
681 66 50       172 $self->{'i'} = $i++ unless $l eq 'i';
682 66 100       123 if ($selected) {
683 5 50       18 if (ref($ref) eq 'HASH') {
    50          
684 0         0 $isSelected = $ref->{'val'} eq $selected;
685             } elsif (ref($ref) eq 'ARRAY') {
686 0         0 $isSelected = $ref->[0] eq $selected;
687             } else {
688 5         10 $isSelected = $ref eq $selected;
689             }
690 5 100 50     20 $self->{'selected'} = $isSelected ?
691             ($attr->{'selected-text'} || 'SELECTED') : '';
692             }
693 66         148 $output .= $self->ParseVars($self->RepeatedTokenMarch($template));
694             }
695 20 100       58 if (my $format = $attr->{'format'}) {
696 1         4 $attr->{'output'} = $output;
697 1         7 $format =~ s/\$([\@\#\~]?)(\w+)((?:\-\>\w+)*)\$/HTML::EP::ParseVar($attr, $1, $2, $3)/eg;
  1         3  
698 1         8 $format;
699             } else {
700 19         81 $output;
701             }
702             }
703              
704              
705             sub _ep_errhandler {
706 0     0   0 my $self = shift; my $attr = shift;
  0         0  
707 0         0 my $type = $attr->{type};
708 0 0 0     0 $type = ($type && (lc $type) eq 'user') ? 'user' : 'system';
709 0 0       0 if ($attr->{src}) {
710 0         0 $self->{"_ep_err_file_$type"} = $attr->{src};
711             } else {
712 0         0 my $template = $self->AttrVal($attr->{'template'}, @_);
713 0         0 $self->{"_ep_err_msg_$type"} = $template;
714             }
715 0         0 '';
716             }
717              
718              
719             sub _ep_error {
720 0     0   0 my($self, $attr, $tokens, $token) = @_;
721 0         0 my $msg = $self->AttrVal($attr->{'msg'}, $tokens, $token, 1);
722 0         0 my $type = $attr->{'type'};
723 0 0 0     0 $self->{_ep_err_type} = ($type && (lc $type) eq 'user') ? 1 : 0;
724 0         0 die $msg;
725 0         0 '';
726             }
727              
728              
729             sub _ep_input_sql_query {
730 0     0   0 my $self = shift; my $attr = shift;
  0         0  
731 0   0     0 my $dbh = $self->{'dbh'} ||
732             die "Missing database-handle (Did you run ep-database?)";
733 0   0     0 my $dest = $attr->{'dest'} ||
734             die "Missing attribute 'dest' (Destination variable)";
735 0         0 my $debug = $self->{'debug'};
736              
737 0         0 my $names = '';
738 0         0 my $values = '';
739 0         0 my $update = '';
740 0         0 my $comma = '';
741 0         0 while (my($var, $val) = each %{$self->{$dest}}) {
  0         0  
742 0         0 $names .= $comma . $var;
743 0         0 my $v = $val->{'val'};
744 0 0 0     0 $v = $dbh->quote($v) if !defined($v) || $val->{'type'} ne 'n';
745 0         0 $values .= $comma . $v;
746 0         0 $update .= $comma . "$var=$v";
747 0 0       0 $comma = ',' unless $comma;
748             }
749 0         0 my $hash = $self->{$dest};
750 0         0 $hash->{'names'} = $names;
751 0 0       0 print "_ep_input_sql_query: Setting $dest\->names to $names\n" if $debug;
752 0         0 $hash->{'values'} = $values;
753 0 0       0 print "_ep_input_sql_query: Setting $dest\->values to $values\n" if $debug;
754 0         0 $hash->{'update'} = $update;
755 0 0       0 print "_ep_input_sql_query: Setting $dest\->update to $update\n" if $debug;
756 0         0 '';
757             }
758              
759             sub _ep_input {
760 2     2   4 my($self, $attr) = @_;
761 2         5 my $prefix = $attr->{'prefix'};
762 2         3 my($var, $val);
763 2         4 my $cgi = $self->{'cgi'};
764 2         7 my @params = $cgi->param();
765 2         46 my $i = 0;
766 2         5 my $list = $attr->{'list'};
767 2         4 my $dest = $attr->{'dest'};
768              
769 2 100       9 $self->{$dest} = [] if $list;
770 2         3 while(1) {
771 4         7 my $p = $prefix;
772 4         7 my $hash = {};
773 4 100       8 if ($list) {
774 3         7 $p .= "$i\_";
775             }
776 4         7 foreach $var (@params) {
777 25 100       230 if ($var =~ /^\Q$p\E\_?(\w+?)_(.*)$/) {
778 17         35 my $col = $2;
779 17         31 my $type = $1;
780 17 100       39 if ($type =~ /^d[dmy]$/) {
781             # A date
782 9 100       26 if ($hash->{$col}) {
783             # Do this only once
784 6         15 next;
785             }
786 3 50       9 if (!$hash->{$col}) {
787 3         15 my $year = $cgi->param("${p}dy_$col");
788 3         74 my $month = $cgi->param("${p}dm_$col");
789 3         89 my $day = $cgi->param("${p}dd_$col");
790 3 50 33     70 if ($year eq '' && $month eq '' && $day eq '') {
      33        
791 0         0 $val = undef;
792             } else {
793 3 100       15 if ($year < 20) {
    100          
794 1         3 $year += 2000;
795             } elsif ($year < 100) {
796 1         2 $year += 1900;
797             }
798 3         19 $val = sprintf("%04d-%02d-%02d",
799             $year, $month, $day);
800             }
801 3         32 $hash->{$col} = { col => $col,
802             val => $val,
803             type => 'd',
804             year => $year,
805             month => $month,
806             day => $day
807             };
808             }
809             } else {
810 8 50       29 $val = ($type eq 's') ?
811             join(",", $cgi->param($var)) : $cgi->param($var);
812 8         195 $hash->{$col} = { col => $col,
813             type => $type,
814             val => $val
815             };
816             }
817             }
818             }
819 4 100       10 if ($list) {
820 3 50       8 die "Cannot create 'names', 'values' and 'update' attributes"
821             . " if 'list' is set." if $attr->{'sqlquery'};
822 3 100       9 last unless %$hash;
823 2         5 $hash->{'i'} = $i++;
824 2         2 push(@{$self->{$dest}}, $hash);
  2         6  
825             } else {
826 1         4 $self->{$dest} = $hash;
827 1 50       8 $self->_ep_input_sql_query($attr) if $attr->{'sqlquery'};
828 1         3 last;
829             }
830             }
831 2 50       7 if ($self->{'debug'}) {
832 0         0 $self->print("_ep_input: Gelesene Daten\n",
833             $self->Dump($self->{$dest}));
834             }
835 2         8 '';
836             }
837              
838             sub _ep_if {
839 59     59   98 my($self, $attr, $tokens, $token) = @_;
840 59         75 my $level = 0;
841 59         93 my $tag = $token->{'tag'};
842 59         138 my $state = $self->EvalIf($tag, $attr);
843 59 100       198 my $start = $tokens->First() if $state;
844 59         76 my $state_done = $state;
845 59         59 my $last;
846 59         168 while (defined(my $token = $tokens->Token())) {
847 371 100       1341 if ($token->{'type'} eq 'S') {
    100          
848 130 100       671 if ($token->{'tag'} eq 'ep-if') {
    100          
849 10         33 ++$level;
850             } elsif ($token->{'tag'} =~ /^ep-els(?:e|e?if)?$/) {
851 114 100       252 next if $level;
852 96 100       270 if ($state) {
    100          
853 31         87 $last = $tokens->First()-1;
854 31         106 $state = 0;
855             } elsif (!$state_done) {
856 42 100 100     173 if ($state = $token->{'tag'} eq 'ep-else' ||
857             $self->EvalIf
858             ($tag, $self->ParseAttr($token->{'attr'}))) {
859 29         35 $state_done = 1;
860 29         121 $start = $tokens->First();
861             }
862             }
863             }
864             } elsif ($token->{'type'} eq 'E') {
865 71 100       160 if ($token->{'tag'} eq 'ep-if') {
866 69 100       167 next if $level--;
867 59 100       123 return '' unless $state_done;
868 55 100       148 $last = $tokens->First()-1 if $state;
869 55         177 return $self->TokenMarch($tokens->Clone($start, $last));
870             }
871             }
872             }
873 0         0 die "ep-if without /ep-if";
874             }
875              
876 0     0   0 sub _ep_elseif { die "ep-elseif without ep-if" }
877 0     0   0 sub _ep_elsif { die "ep-elsif without ep-if" }
878 0     0   0 sub _ep_else { die "ep-else without ep-if" }
879              
880              
881             sub _ep_mail {
882 0     0   0 my($self, $attr, $tokens, $token) = @_;
883              
884 0   0     0 my $host = (delete $attr->{'mailserver'}) ||
885             $self->{'_ep_config'}->{'mailhost'} || '127.0.0.1';
886 0         0 my @options;
887 0         0 my $body = $self->AttrVal($attr->{'body'}, $tokens, $token, 1);
888 0         0 require Mail::Header;
889 0         0 my $msg = Mail::Header->new();
890 0         0 my($header, $val);
891 0   0     0 my $from = $attr->{'from'} || die "Missing header attribute: from";
892 0 0       0 die "Missing header attribute: to" unless $attr->{'to'};
893 0 0       0 die "Missing header attribute: subject" unless $attr->{'subject'};
894 0         0 while (($header, $val) = each %$attr) {
895 0         0 $msg->add($header, $val);
896             }
897 0         0 require Net::SMTP;
898 0         0 require Mail::Internet;
899 0         0 my $debug = $self->{'debug'};
900 0 0       0 local *STDERR if $debug;
901 0 0       0 if ($debug) {
902 0         0 $self->print("Headers: \n");
903 0         0 $self->print($msg->as_string());
904 0         0 $self->print("Making SMTP connection to $host.\n");
905 0         0 open(STDERR, ">&STDOUT");
906             }
907 0 0       0 my $smtp = Net::SMTP->new($host, 'Debug' => $debug)
908             or die "Cannot open SMTP connection to $host: $!";
909 0         0 my $mail = Mail::Internet->new([$body], Header => $msg);
910 0         0 $Mail::Util::mailaddress = $from; # Ugly hack to prevent
911             # DNS lookup for 'mailhost'
912             # in Mail::Util::mailaddress().
913 0         0 $mail->smtpsend('Host' => $smtp, @options);
914 0         0 $smtp->quit();
915 0         0 '';
916             }
917              
918              
919             sub _ep_include {
920 3     3   5 my($self, $attr, $tokens, $token) = @_;
921 3         12 my $parser = HTML::EP::Parser->new();
922 3   50     11 my $f = $attr->{'file'} || die "Missing file name\n";
923 3         9 my $df = $self->{'env'}->{'DOCUMENT_ROOT'} . $f;
924 3 50       64 $f = $df if -f $df;
925 3         16 my $fh = Symbol::gensym();
926 3 50       141 open($fh, "<$f") || die "Failed to open file $f: $!";
927 3         20 $parser->parse_file($fh);
928 3         7 $parser->eof();
929 3         17 my $new_toks = HTML::EP::Tokens->new('tokens' => $parser->{'_ep_tokens'});
930 3 50       14 $tokens->Replace
931             ($tokens->First()-1,
932             { 'type' => 'I',
933             'tokens' => $new_toks
934             }) if $tokens; # Upwards compatibility: Before EP 0.20 users
935             # didn't pass a tokens argument.
936 3         9 $self->RepeatedTokenMarch($new_toks)
937             }
938              
939              
940             sub _ep_exit {
941 3     3   4 my $self = shift;
942             # If we are inside of an ep-if, we need to collect previous output
943 3         4 $self->{'_ep_output'} = join('', @{$self->{'_ep_output_stack'}},
  3         10  
944             $self->{'_ep_output'});
945 3         54 die "_ep_exit, ignore";
946             }
947              
948             sub _ep_redirect {
949 0     0   0 my $self = shift; my $attr = shift;
  0         0  
950 0 0       0 my $to = $attr->{'to'} or die "Missing redirect target";
951 0 0       0 $self->print("Redirecting to $to\n") if $self->{'debug'};
952 0 0       0 $self->print($self->{'cgi'}->redirect('-uri' => $to,
953             '-type' => 'text/plain',
954             '-refresh' => "0; URL=$to",
955             $attr->{'cookies'} ?
956             $self->SetCookies() : ()));
957 0         0 $self->print('Click 958             '">here to go on');
959 0         0 $self->Stop();
960 0         0 '';
961             }
962              
963             sub _ep_set {
964 8     8   11 my($self, $attr, $tokens, $token) = @_;
965 8         33 my $val = $self->AttrVal($attr->{'val'}, $tokens, $token,
966             !$attr->{'noparse'});
967 8         17 my $var = $attr->{'var'};
968 8         11 my $ref = $self;
969 8         28 while ($var =~ /(.*?)\-\>(.*)/) {
970 2         5 my $key = $1;
971 2         5 $var = $2;
972 2 50       8 if ($key =~ /^\d+$/) {
973 0         0 $ref = $ref->[$key];
974             } else {
975 2         7 $ref = $ref->{$key};
976             }
977             }
978 8 50       17 print "Setting $ref -> $var to $val\n" if $self->{'debug'};
979 8 100       21 if ($var =~ /^\d+$/) {
980 1         3 $ref->[$var] = $val;
981             } else {
982 7         14 $ref->{$var} = $val;
983             }
984 8         16 '';
985             }
986              
987             sub _format_NBSP {
988 2     2   4 my $self = shift; my $str = shift;
  2         3  
989 2 100 66     12 if (!defined($str) || $str eq '') {
990 1         2 $str = ' ';
991             }
992 2         5 $str;
993             }
994              
995              
996             1;