File Coverage

blib/lib/PLP/Functions.pm
Criterion Covered Total %
statement 71 122 58.2
branch 23 62 37.1
condition 0 3 0.0
subroutine 16 21 76.1
pod 12 13 92.3
total 122 221 55.2


line stmt bran cond sub pod time code
1             package PLP::Functions;
2              
3 3     3   83250 use strict;
  3         7  
  3         715  
4 3     3   19 use warnings;
  3         5  
  3         101  
5              
6 3     3   17 use base 'Exporter';
  3         10  
  3         849  
7 3     3   17 use Carp;
  3         7  
  3         324  
8 3     3   144 use Fcntl qw(:flock);
  3         6  
  3         946  
9              
10             our $VERSION = '1.01';
11             our @EXPORT = qw/Entity DecodeURI EncodeURI Include include PLP_END
12             EscapeHTML
13             AddCookie ReadFile WriteFile AutoURL Counter exit/;
14              
15             sub Include ($) {
16 3     3   15 no strict;
  3         7  
  3         12080  
17 2     2 1 3 $PLP::file = $_[0];
18 2         3 $PLP::inA = 0;
19 2         3 $PLP::inB = 0;
20 2         3 local $@;
21 2     1   14 eval 'package PLP::Script; no warnings; ' . PLP::source($PLP::file, 0, join ' ', (caller)[2,1]);
  1     1   6  
  1         2  
  1         49  
  1         5  
  1         1  
  1         28  
22 2 100       15 if ($@) {
23 1 50       4 PLP::Functions::exit() if $@ =~ /\cS\cT\cO\cP/;
24 1         3 PLP::error($@, 1);
25             }
26             }
27              
28             sub include ($) {
29 2     2 1 11 goto &Include;
30             }
31              
32             sub exit (;$) {
33 1     1 0 12 die "\cS\cT\cO\cP\n";
34             }
35              
36             sub PLP_END (&) {
37 2     2 1 5 push @PLP::END, shift;
38             }
39              
40             sub EscapeHTML {
41 5 100   5 1 267 @_ == 1 or croak "Unsupported parameters given to EscapeHTML";
42 4 100       18 unshift @_, shift if defined wantarray; # dereference if not void
43 4         9 for ($_[0]) {
44 4 100       13 defined or next;
45 3         22 s/&/&/g;
46 2         9 s/"/"/g;
47 2         8 s/
48 2         11 s/>/>/g;
49             }
50 3         17 return $_[0];
51             }
52              
53             sub Entity (@) {
54 2 50   2 1 21 my $ref = defined wantarray ? [@_] : \@_;
55 2         7 for (@$ref) {
56 2 50       8 defined or next;
57 2         4 eval {
58 2         10 s/&/&/g;
59 2         7 s/"/"/g;
60 2         6 s/
61 2         4 s/>/>/g;
62 2         8 s/\n/
\n/g;
63 2         6 s/\t/        /g;
64 2         8 s/ /  /g;
65             };
66             }
67 2 50       23 return defined wantarray ? (wantarray ? @$ref : "@$ref") : undef;
    50          
68             }
69              
70             sub DecodeURI (@) {
71 38 100   38 1 87 my $ref = defined wantarray ? [@_] : \@_;
72 38         63 for (@$ref) {
73 74 50       126 defined or next;
74 74         116 eval {
75 74         86 tr/+/ /; # Browsers do tr/ /+/ - I don't care about RFCs, but
76             # I do care about real-life situations.
77 74         155 s/%([0-9A-Fa-f][0-9A-Fa-f])/chr hex $1/ge;
  7         29  
78             };
79             }
80 38 50       135 return defined wantarray ? (wantarray ? @$ref : "@$ref") : undef;
    100          
81             }
82              
83             sub EncodeURI (@) {
84 1 50   1 1 7 my $ref = defined wantarray ? [@_] : \@_;
85 1         3 for (@$ref) {
86 1 50       5 defined or next;
87 1         1 eval {
88 1         7 s{([^A-Za-z0-9\-_.!~*'()/?:@\$,])}{sprintf("%%%02x", ord $1)}ge;
  4         20  
89             };
90             }
91 1 50       11 return defined wantarray ? (wantarray ? @$ref : "@$ref") : undef;
    50          
92             }
93              
94             sub AddCookie ($) {
95 0 0   0 1 0 if ($PLP::Script::header{'Set-Cookie'}) {
96 0         0 $PLP::Script::header{'Set-Cookie'} .= "\n" . $_[0];
97             } else {
98 0         0 $PLP::Script::header{'Set-Cookie'} = $_[0];
99             }
100             }
101              
102             sub ReadFile ($) {
103 0     0 1 0 local $/ = undef;
104 0 0       0 open (my $fh, '<', $_[0]) or do {
105 0         0 PLP::error("Cannot open $_[0] for reading ($!)", 1);
106 0         0 return undef;
107             };
108 0         0 my $r = readline $fh;
109 0         0 close $fh;
110 0         0 return $r;
111             }
112              
113             sub WriteFile ($$) {
114 0 0   0 1 0 open (my $fh, '>', $_[0]) or do {
115 0         0 PLP::error("Cannot open $_[0] for writing ($!)", 1);
116 0         0 return undef;
117             };
118 0         0 flock $fh, LOCK_EX;
119 0 0       0 print $fh $_[1] or do {
120 0         0 PLP::error("Cannot write to $_[0] ($!)");
121 0         0 return undef;
122             };
123 0 0       0 close $fh or do {
124 0         0 PLP::error("Cannot close $_[0] ($!)");
125 0         0 return undef;
126             };
127 0         0 return 1;
128             }
129              
130             sub Counter ($) {
131 0     0 1 0 local $/ = undef;
132 0         0 my $fh;
133 0 0 0     0 open $fh, '+<', $_[0] or
134             open $fh, '>', $_[0] or return undef;
135 0         0 flock $fh, 2;
136 0         0 seek $fh, 0, 0;
137 0         0 my $counter = <$fh>;
138 0         0 seek $fh, 0, 0;
139 0         0 truncate $fh, 0;
140 0 0       0 print $fh ++$counter or return undef;
141 0 0       0 close $fh or return undef;
142 0         0 return $counter;
143             }
144              
145             sub AutoURL ($) {
146             # This sub assumes your string does not match /(["<>])\cC\1/
147 0 0   0 1 0 my $ref = defined wantarray ? \(my $copy = $_[0]) : \$_[0];
148 0         0 eval {
149 0         0 $$ref =~ s/"/"\cC"/g; # Single characters are easier to match :)
150 0         0 $$ref =~ s/>/>\cC>/g; # so we can just use a character class []
151 0         0 $$ref =~ s/</<\cC
152            
153             # Now this is a big, ugly regex! But hey - it works :)
154 0         0 $$ref =~ s{((\w+://|www\.|WWW\.)[a-zA-Z0-9\.\@:-]+[^\"\'>< \r\t\n]*)}{
155 0         0 local $_ = $1;
156 0         0 my $scheme = $2;
157 0 0       0 s/// if (my $trailing) = /([\.,!\?\(\)\[\]]+$)/;
158 0         0 s/&(?!\x23?\w+;)/&/g;
159 0         0 s/\"/"/g;
160 0 0       0 my $href = ($scheme =~ /www\./i ? "http://$_" : $_);
161 0         0 qq{$_$trailing};
162             }eg;
163              
164 0         0 $$ref =~ s/"\cC"/"/g;
165 0         0 $$ref =~ s/>\cC>/>/g;
166 0         0 $$ref =~ s/<\cC
167             };
168 0 0       0 if ($@){ return defined wantarray ? @_ : undef } # return original on error
  0 0       0  
169 0 0       0 return defined wantarray ? $$ref : undef;
170             }
171              
172             1;
173              
174             =head1 NAME
175              
176             PLP::Functions - Functions that are available in PLP documents
177              
178             =head1 DESCRIPTION
179              
180             The functions are exported into the PLP::Script package that is used by PLP documents. Although uppercased letters are unusual in Perl, they were chosen to stand out.
181              
182             Most of these functions are context-hybird. Before using them, one should know about contexts in Perl. The three major contexts are: B, B and B context. You'll find more about context in L.
183              
184             Some context examples:
185              
186             print foo(); # foo is in list context (print LIST)
187             foo(); # foo is in void context
188             $bar = foo(); # foo is in scalar context
189             @bar = foo(); # foo is in list context
190             length foo(); # foo is in scalar context (length EXPR)
191              
192             =head2 The functions
193              
194             =over 10
195              
196             =item Include FILENAME
197              
198             Executes another PLP file, that will be parsed (i.e. code must be in C<< <: :> >>). As with Perl's C, the file is evaluated in its own lexical file scope, so lexical variables (C variables) are not shared. PLP's C<< <(filename)> >> includes at compile-time, is faster and is doesn't create a lexical scope (it shares lexical variables).
199              
200             Include can be used recursively, and there is no depth limit:
201              
202            
203             <:
204             include 'crash.plp';
205             # This example will loop forever,
206             # and dies with an out of memory error.
207             # Do not try this at home.
208             :>
209              
210             =item include FILENAME
211              
212             An alias for C.
213              
214             =item PLP_END BLOCK
215              
216             Adds a piece of code that is executed when at the end of the PLP document. This is useful when creating a template file:
217              
218            
219             <: PLP_END { :>
220            
221             <: } :>
222              
223             <(template.plp)>
224             Hello, world!
225              
226             You should use this function instead of Perl's built-in C blocks, because those do not work properly with mod_perl.
227              
228             =item EscapeHTML STRING
229              
230             Replaces HTML syntax characters by HTML entities, so the text can be output safely.
231             You should always use this when displaying user input (or database output),
232             to avoid cross-site-scripting vurnerabilities.
233              
234             In void context, B the value of the given variable.
235              
236             <: EscapeHTML($user_input); print "
$user_input
"; :>
237              
238             In other contexts, returns the changed version.
239              
240            
241              
242             Be warned that single quotes are not substituted, so always use double quotes for attributes.
243             Also does not convert whitespace for formatted output; use Entity() for that.
244              
245             To escape high-bit characters as well, refer to L.
246              
247             =item Entity LIST
248              
249             Formats given arguments for literal display in HTML documents.
250             Similar to EscapeHTML(), but also preserves newlines and consecutive spaces
251             using corresponding C<<
>> and C< > respectively.
252              
253             In void context, B the values of the given variables. In other contexts, returns the changed versions.
254              
255             <: print '

' . Entity($user_input) . '

'; :>
256              
257             Inside attributes, always use EscapeHTML() instead.
258              
259             =item EncodeURI LIST
260              
261             Encodes URI strings according to RFC 3986. All disallowed characters are replaced by their %-encoded values.
262              
263             In void context, B the values of the given variables. In other contexts, returns the changed versions.
264              
265             Link
266              
267             Note that the following reserved characters are I percent-encoded, even though they may have a special meaning in URIs:
268              
269             / ? : @ $
270              
271             This should be safe for escaping query values (as in the example above),
272             but otherwise it may be a better idea to use L instead.
273              
274             =item DecodeURI LIST
275              
276             Decodes %-encoded strings. Unlike L,
277             it also translates + characters to spaces (as browsers use those).
278              
279             In void context, B the values of the given variables. In other contexts, returns the changed versions.
280              
281             =item ReadFile FILENAME
282              
283             Returns the contents of FILENAME in one large string. Returns undef on failure.
284              
285             =item WriteFile FILENAME, STRING
286              
287             Writes STRING to FILENAME (overwrites FILENAME if it already exists). Returns true on success, false on failure.
288              
289             =item Counter FILENAME
290              
291             Increases the contents of FILENAME by one and returns the new value. Returns undef on failure. Fails silently.
292              
293             You are visitor number <:= Counter('counter.txt') :>.
294              
295             =item AutoURL STRING
296              
297             Replaces URLs (actually, replace things that look like URLs) by links.
298              
299             In void context, B the value of the given variable. In other contexts, returns the changed version.
300              
301             <: print AutoURL(Entity($user_input)); :>
302              
303             =item AddCookie STRING
304              
305             Adds a Set-Cookie header. STRING must be a valid Set-Cookie header value.
306              
307             =back
308              
309             =head1 AUTHOR
310              
311             Juerd Waalboer
312              
313             Current maintainer: Mischa POSLAWSKY
314              
315             =cut
316