← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:15 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Templates.pm
StatementsExecuted 79966 statements in 116ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
475470.0ms169msFoswiki::Templates::::readTemplateFoswiki::Templates::readTemplate
1022118.5ms52.5msFoswiki::Templates::::_readTemplateFileFoswiki::Templates::_readTemplateFile
3092113.1ms20.3msFoswiki::Templates::::tmplPFoswiki::Templates::tmplP (recurses: max depth 9, inclusive time 57.1ms)
100117.13ms16.1msFoswiki::Templates::::_readFileFoswiki::Templates::_readFile
100116.84ms6.84msFoswiki::Templates::::_decommentFoswiki::Templates::_decomment
308642.71ms23.6msFoswiki::Templates::::expandTemplateFoswiki::Templates::expandTemplate (recurses: max depth 8, inclusive time 48.4ms)
111988µs988µsFoswiki::Templates::::finishFoswiki::Templates::finish
11120µs20µsFoswiki::Templates::::newFoswiki::Templates::new
11115µs13.3msFoswiki::Templates::::_expandTrivialTemplateFoswiki::Templates::_expandTrivialTemplate
11114µs27µsFoswiki::Templates::::BEGIN@33Foswiki::Templates::BEGIN@33
11112µs27µsFoswiki::Templates::::BEGIN@136Foswiki::Templates::BEGIN@136
11111µs21µsFoswiki::Templates::::BEGIN@214Foswiki::Templates::BEGIN@214
11110µs14µsFoswiki::Templates::::BEGIN@34Foswiki::Templates::BEGIN@34
11110µs36µsFoswiki::Templates::::BEGIN@35Foswiki::Templates::BEGIN@35
1119µs21µsFoswiki::Templates::::BEGIN@216Foswiki::Templates::BEGIN@216
1118µs41µsFoswiki::Templates::::BEGIN@49Foswiki::Templates::BEGIN@49
1117µs23µsFoswiki::Templates::::BEGIN@138Foswiki::Templates::BEGIN@138
1114µs4µsFoswiki::Templates::::BEGIN@37Foswiki::Templates::BEGIN@37
1114µs4µsFoswiki::Templates::::BEGIN@39Foswiki::Templates::BEGIN@39
0000s0sFoswiki::Templates::::getTemplateFromCacheFoswiki::Templates::getTemplateFromCache
0000s0sFoswiki::Templates::::haveTemplateFoswiki::Templates::haveTemplate
0000s0sFoswiki::Templates::::saveTemplateToCacheFoswiki::Templates::saveTemplateToCache
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Templates
6
7Support for Skin Template directives
8
9=cut
10
11=begin TML
12
13The following tokens are supported by this language:
14
15| %<nop>TMPL:P% | Instantiates a previously defined template |
16| %<nop>TMPL:DEF% | Opens a template definition |
17| %<nop>TMPL:END% | Closes a template definition |
18| %<nop>TMPL:INCLUDE% | Includes another file of templates |
19
20Note; the template cache does not get reset during initialisation, so
21the haveTemplate test will return true if a template was loaded during
22a previous run when used with mod_perl or speedycgi. Frustrating for
23the template author, but they just have to switch off
24the accelerators during development.
25
26This is to all intents and purposes a singleton object. It could
27easily be coverted into a true singleton (template manager).
28
29=cut
30
31package Foswiki::Templates;
32
33229µs240µs
# spent 27µs (14+13) within Foswiki::Templates::BEGIN@33 which was called: # once (14µs+13µs) by Foswiki::templates at line 33
use strict;
# spent 27µs making 1 call to Foswiki::Templates::BEGIN@33 # spent 13µs making 1 call to strict::import
34224µs218µs
# spent 14µs (10+4) within Foswiki::Templates::BEGIN@34 which was called: # once (10µs+4µs) by Foswiki::templates at line 34
use warnings;
# spent 14µs making 1 call to Foswiki::Templates::BEGIN@34 # spent 4µs making 1 call to warnings::import
35226µs262µs
# spent 36µs (10+26) within Foswiki::Templates::BEGIN@35 which was called: # once (10µs+26µs) by Foswiki::templates at line 35
use Assert;
# spent 36µs making 1 call to Foswiki::Templates::BEGIN@35 # spent 26µs making 1 call to Exporter::import
36
37243µs14µs
# spent 4µs within Foswiki::Templates::BEGIN@37 which was called: # once (4µs+0s) by Foswiki::templates at line 37
use Foswiki::Attrs ();
# spent 4µs making 1 call to Foswiki::Templates::BEGIN@37
38
39
# spent 4µs within Foswiki::Templates::BEGIN@39 which was called: # once (4µs+0s) by Foswiki::templates at line 44
BEGIN {
4014µs if ( $Foswiki::cfg{UseLocale} ) {
41 require locale;
42 import locale();
43 }
44121µs14µs}
# spent 4µs making 1 call to Foswiki::Templates::BEGIN@39
45
46# Enable TRACE to get HTML comments in the output showing where templates
47# (both DEFs and files) open and close. Will probably bork the output, so
48# normally you should use it with a bin/view command-line.
492245µs274µs
# spent 41µs (8+33) within Foswiki::Templates::BEGIN@49 which was called: # once (8µs+33µs) by Foswiki::templates at line 49
use constant TRACE => 0;
# spent 41µs making 1 call to Foswiki::Templates::BEGIN@49 # spent 33µs making 1 call to constant::import
50
511500nsmy $MAX_EXPANSION_RECURSIONS = 999;
52
53=begin TML
54
55---++ ClassMethod new ( $session )
56
57Constructor. Creates a new template database object.
58 * $session - session (Foswiki) object
59
60=cut
61
62
# spent 20µs within Foswiki::Templates::new which was called: # once (20µs+0s) by Foswiki::templates at line 2323 of /var/www/foswikidev/core/lib/Foswiki.pm
sub new {
6311µs my ( $class, $session ) = @_;
64114µs my $this = bless( { session => $session }, $class );
65
661900ns $this->{VARS} = {};
6711µs $this->{VARS}->{sep}->{text} = ' | ';
681400ns $this->{expansionRecursions} = {};
6917µs return $this;
70}
71
72=begin TML
73
74---++ ObjectMethod finish()
75Break circular references.
76
77=cut
78
79# Note to developers; please undef *all* fields in the object explicitly,
80# whether they are references or not. That way this method is "golden
81# documentation" of the live fields in the object.
82
# spent 988µs within Foswiki::Templates::finish which was called: # once (988µs+0s) by Foswiki::finish at line 2488 of /var/www/foswikidev/core/lib/Foswiki.pm
sub finish {
831500ns my $this = shift;
841984µs undef $this->{VARS};
8511µs undef $this->{session};
8616µs undef $this->{expansionRecursions};
87}
88
89=begin TML
90
91---++ ObjectMethod haveTemplate( $name ) -> $boolean
92
93Return true if the template exists and is loaded into the cache
94
95=cut
96
97sub haveTemplate {
98 my ( $this, $template ) = @_;
99
100 return exists( $this->{VARS}->{$template} );
101}
102
103# Expand only simple templates that can be expanded statically.
104# Templates with conditions can only be expanded after the
105# context is fully known.
106
# spent 13.3ms (15µs+13.3) within Foswiki::Templates::_expandTrivialTemplate which was called: # once (15µs+13.3ms) by Foswiki::Templates::readTemplate at line 368
sub _expandTrivialTemplate {
10711µs my ( $this, $text ) = @_;
108
109 # SMELL: unchecked implicit untaint?
11012µs $text =~ m/%TMPL\:P\{(.*)}%/;
11113µs116µs my $attrs = new Foswiki::Attrs($1);
# spent 16µs making 1 call to Foswiki::Attrs::new
112
113 # Can't expand context-dependant templates
1141400ns return $text if ( $attrs->{context} );
11515µs113.3ms return $this->tmplP($attrs);
# spent 13.3ms making 1 call to Foswiki::Templates::tmplP
116}
117
118=begin TML
119
120---++ ObjectMethod expandTemplate( $params ) -> $string
121
122Expand the template specified in the parameter string using =tmplP=.
123
124Examples:
125<verbatim>
126$tmpls->expandTemplate("blah");
127$tmpls->expandTemplate(context="view" then="sigh" else="humph");
128</verbatim>
129
130=cut
131
132
# spent 23.6ms (2.71+20.9) within Foswiki::Templates::expandTemplate which was called 308 times, avg 77µs/call: # 180 times (1.48ms+11.7ms) by Foswiki::Templates::tmplP at line 215, avg 73µs/call # 40 times (281µs+4.51ms) by Foswiki::Search::loadTemplates at line 511 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 120µs/call # 40 times (573µs+2.44ms) by Foswiki::Search::loadTemplates at line 510 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 75µs/call # 40 times (302µs+1.72ms) by Foswiki::Search::loadTemplates at line 522 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 51µs/call # 4 times (34µs+257µs) by Foswiki::Func::expandTemplate at line 2600 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 73µs/call # 4 times (46µs+221µs) by Foswiki::inlineAlert at line 2621 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 67µs/call
sub expandTemplate {
133308244µs my ( $this, $params ) = @_;
134
135308625µs3085.20ms my $attrs = new Foswiki::Attrs($params);
# spent 5.20ms making 308 calls to Foswiki::Attrs::new, avg 17µs/call
136235µs243µs
# spent 27µs (12+16) within Foswiki::Templates::BEGIN@136 which was called: # once (12µs+16µs) by Foswiki::templates at line 136
no warnings 'recursion';
# spent 27µs making 1 call to Foswiki::Templates::BEGIN@136 # spent 16µs making 1 call to warnings::unimport
137308600µs3086.97ms my $value = $this->tmplP($attrs);
# spent 64.1ms making 308 calls to Foswiki::Templates::tmplP, avg 208µs/call, recursion: max depth 9, sum of overlapping time 57.1ms
1382345µs238µs
# spent 23µs (7+15) within Foswiki::Templates::BEGIN@138 which was called: # once (7µs+15µs) by Foswiki::templates at line 138
use warnings 'recursion';
# spent 23µs making 1 call to Foswiki::Templates::BEGIN@138 # spent 15µs making 1 call to warnings::import
139308923µs return $value;
140}
141
142=begin TML
143
144---+ ObjectMethod tmplP( $attrs ) -> $string
145
146Return value expanded text of the template, as found from looking
147in the register of template definitions. The attrs can contain a template
148name in _DEFAULT, and / or =context=, =then= and =else= values.
149
150Recursively expands any contained TMPL:P tags.
151
152Note that it would be trivial to add template parameters to this,
153simply by iterating over the other parameters (other than _DEFAULT, context,
154then and else) and doing a s/// in the template for that parameter value. This
155would add considerably to the power of templates.
156
157=cut
158
159
# spent 20.3ms (13.1+7.12) within Foswiki::Templates::tmplP which was called 309 times, avg 66µs/call: # 308 times (13.1ms+-6.09ms) by Foswiki::Templates::expandTemplate at line 137, avg 23µs/call # once (74µs+13.2ms) by Foswiki::Templates::_expandTrivialTemplate at line 115
sub tmplP {
160309164µs my ( $this, $params ) = @_;
161
162309251µs309601µs $params->remove('_RAW'); # don't need to iterate over _RAW
# spent 601µs making 309 calls to Foswiki::Attrs::remove, avg 2µs/call
163309378µs309631µs my $template = $params->remove('_DEFAULT') || '';
# spent 631µs making 309 calls to Foswiki::Attrs::remove, avg 2µs/call
164309323µs309495µs my $context = $params->remove('context');
# spent 495µs making 309 calls to Foswiki::Attrs::remove, avg 2µs/call
165309338µs309455µs my $then = $params->remove('then');
# spent 455µs making 309 calls to Foswiki::Attrs::remove, avg 1µs/call
166309319µs309440µs my $else = $params->remove('else');
# spent 440µs making 309 calls to Foswiki::Attrs::remove, avg 1µs/call
16730958µs if ($context) {
168216µs $template = $then if defined($then);
1692126µs foreach my $id ( split( /\,\s*/, $context ) ) {
1702126µs unless ( $this->{session}->{context}->{$id} ) {
171122µs $template = ( $else || '' );
172126µs last;
173 }
174 }
175 }
176
17730937µs return '' unless $template;
178
179307295µs $this->{expansionRecursions}->{$template} += 1;
180
181307168µs if ( $this->{expansionRecursions}->{$template} > $MAX_EXPANSION_RECURSIONS )
182 {
183 throw Foswiki::OopsException(
184 'attention',
185 def => 'template_recursion',
186 params => [$template]
187 );
188 }
189
190307111µs my $val = '';
191307213µs if ( exists( $this->{VARS}->{$template} ) ) {
192302271µs $val = $this->{VARS}->{$template}->{text};
193 $val = "<!--$template-->\n$val<!--/$template-->\n" if (TRACE);
194
195302372µs foreach my $p ( keys %$params ) {
196811µs if ( $p eq 'then' || $p eq 'else' ) {
197 $val =~ s/%$p%/$this->expandTemplate($1)/ge;
198 }
199 elsif ( defined( $params->{$p} ) ) {
200870µs $val =~ s/%$p%/$params->{$p}/ge;
201 }
202 }
203
204 # process default values; this will clean up orphaned %p% params
205302537µs foreach my $p ( keys %{ $this->{VARS}->{$template}->{params} } ) {
206
207 # resolve dynamic lookups such as %TMPL:DEF{"LIBJS" name="%id%"}%
208 my $pvalue = $this->{VARS}->{$template}->{params}->{$p};
209 $pvalue =~ s/\%(.*?)\%/$params->{$1}/g;
210 $val =~ s/%$p%/$pvalue/ge;
211 }
212
213302396µs $val =~ s/%TMPL:PREV%/%TMPL:P{"$template:_PREV"}%/g;
214255µs230µs
# spent 21µs (11+10) within Foswiki::Templates::BEGIN@214 which was called: # once (11µs+10µs) by Foswiki::templates at line 214
no warnings 'recursion';
# spent 21µs making 1 call to Foswiki::Templates::BEGIN@214 # spent 10µs making 1 call to warnings::unimport
2154821.26ms18013.2ms $val =~ s/%TMPL:P\{(.*?)\}%/$this->expandTemplate($1)/ge;
# spent 61.6ms making 180 calls to Foswiki::Templates::expandTemplate, avg 342µs/call, recursion: max depth 8, sum of overlapping time 48.4ms
21621.87ms232µs
# spent 21µs (9+12) within Foswiki::Templates::BEGIN@216 which was called: # once (9µs+12µs) by Foswiki::templates at line 216
use warnings 'recursion';
# spent 21µs making 1 call to Foswiki::Templates::BEGIN@216 # spent 12µs making 1 call to warnings::import
217 }
218
219307187µs $this->{expansionRecursions}->{$template} -= 1;
220307824µs return $val;
221}
222
223=begin TML
224
225---++ ObjectMethod readTemplate ( $name, %options ) -> $text
226
227Reads a template, loading the definitions therein.
228
229Return value: expanded template text
230
231By default throws an OopsException if the template was not found or the
232access controls denied access.
233
234%options include:
235 * =skin= - skin name,
236 * =web= - web to search
237 * =no_oops= - if true, will not throw an exception. Instead, returns undef.
238
239If template text is found, extracts include statements and fully expands them.
240Also extracts template definitions and adds them to the
241list of loaded templates, overwriting any previous definition.
242
243=cut
244
245
# spent 169ms (70.0+98.9) within Foswiki::Templates::readTemplate which was called 47 times, avg 3.59ms/call: # 40 times (48.6ms+52.8ms) by Foswiki::Search::loadTemplates at line 495 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2.54ms/call # 4 times (8.83ms+21.2ms) by Foswiki::inlineAlert at line 2619 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 7.50ms/call # once (12.3ms+22.7ms) by Foswiki::UI::View::view at line 292 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (108µs+1.39ms) by Foswiki::Func::readTemplate at line 2535 of /var/www/foswikidev/core/lib/Foswiki/Func.pm # once (193µs+759µs) by Foswiki::Func::loadTemplate at line 2568 of /var/www/foswikidev/core/lib/Foswiki/Func.pm
sub readTemplate {
2464783µs my ( $this, $name, %opts ) = @_;
247 ASSERT($name) if DEBUG;
24847287µs476.36ms my $skins = $opts{skins} || $this->{session}->getSkin();
# spent 6.36ms making 47 calls to Foswiki::getSkin, avg 135µs/call
24947146µs my $web = $opts{web} || $this->{session}->{webName};
250
25147120µs $this->{files} = ();
252
253 # recursively read template file(s)
25447246µs4718.9ms my $text = _readTemplateFile( $this, $name, $skins, $web );
# spent 18.9ms making 47 calls to Foswiki::Templates::_readTemplateFile, avg 402µs/call
255
256 # Check file was found
2574720µs unless ( defined $text ) {
258
259 # if no_oops is given, return undef silently
260 if ( $opts{no_oops} ) {
261 return undef;
262 }
263 else {
264 throw Foswiki::OopsException(
265 'attention',
266 def => 'no_such_template',
267 params => [
268 $name,
269
270 # More info for overridable templates
271 ( $name =~ m/^(view|edit)$/ ) ? $name . '_TEMPLATE' : ''
272 ]
273 );
274 }
275 }
276
277 # SMELL: unchecked implicit untaint?
27847442µs while ( $text =~ m/%TMPL\:INCLUDE\{[\s\"]*(.*?)[\"\s]*\}%/s ) {
279491.12ms $text =~ s/%TMPL\:INCLUDE\{[\s\"]*(.*?)[\"\s]*\}%/
2805598µs5533.7ms _readTemplateFile( $this, $1, $skins, $web ) || ''/ge;
# spent 33.7ms making 55 calls to Foswiki::Templates::_readTemplateFile, avg 612µs/call
281 }
282
28347130µs if ( $text !~ /%TMPL\:/ ) {
284
285 # no %TMPL's to process
286
287 # SMELL: legacy - leading spaces to tabs, should not be required
288 $text =~ s|^(( {3})+)|"\t" x (length($1)/3)|gem;
289
290 return $text;
291 }
292
2934793µs my $result = '';
2944744µs my $key = '';
2954741µs my $val = '';
2964723µs my $delim = '';
297471.93ms foreach ( split( /(%TMPL\:)/, $text ) ) {
298500114.9ms if (/^(%TMPL\:)$/) {
299 $delim = $1;
300 }
301 elsif ( (/^DEF\{(.*?)\}%(.*)/s) && ($1) ) {
302
303 # handle %TMPL:DEF{"key"}% and %TMPL:DEF{"key" p="1"}%
3041075151µs if ($key) {
305
306 # if the key is already defined, rename the existing
307 # template to key:_PREV
30855µs my $new_value = $val;
30952µs my $prev_key = $key;
31057µs my $prev_value = $this->{VARS}->{$prev_key}->{text};
31154µs $this->{VARS}->{$prev_key}->{text} = $new_value;
31253µs while ($prev_value) {
31361µs $new_value = $prev_value;
31464µs $prev_key = "$prev_key:_PREV";
31567µs $prev_value = $this->{VARS}->{$prev_key}->{text};
31665µs $this->{VARS}->{$prev_key}->{text} = $new_value;
317 }
318 }
319
32010752.70ms107522.2ms my $attrs = new Foswiki::Attrs($1);
# spent 22.2ms making 1075 calls to Foswiki::Attrs::new, avg 21µs/call
3211075354µs $key = $attrs->{_DEFAULT};
322
323 # store params in TMPL:DEF for later retrieval
32410751.27ms10752.51ms $attrs->remove('_DEFAULT');
# spent 2.51ms making 1075 calls to Foswiki::Attrs::remove, avg 2µs/call
3251075967µs10751.92ms $attrs->remove('_RAW');
# spent 1.92ms making 1075 calls to Foswiki::Attrs::remove, avg 2µs/call
32610751.15ms foreach my $p ( keys %$attrs ) {
327 $this->{VARS}->{$key}->{params}->{$p} = $attrs->{$p};
328 }
329
330 # SMELL: unchecked implicit untaint?
33110751.36ms $val = $2;
332
333 }
334 elsif (/^END%[\s\n\r]*(.*)/s) {
335
336 # handle %TMPL:END%
337
338 # if the key is already defined, rename the existing template to
339 # key:_PREV
3401071243µs my $new_value = $val;
3411071175µs my $prev_key = $key;
34210711.88ms my $prev_value = $this->{VARS}->{$prev_key}->{text};
3431071845µs $this->{VARS}->{$prev_key}->{text} = $new_value;
3441071384µs while ($prev_value) {
3457614796µs $new_value = $prev_value;
34676142.72ms $prev_key = "$prev_key:_PREV";
347761414.7ms $prev_value = $this->{VARS}->{$prev_key}->{text};
348761416.3ms $this->{VARS}->{$prev_key}->{text} = $new_value;
349 }
350
3511071186µs $key = '';
3521071103µs $val = '';
353
354 # SMELL: unchecked implicit untaint?
3551071720µs $result .= $1;
356
357 }
358 elsif ($key) {
359 $val .= "$delim$_";
360
361 }
362 else {
3634870µs $result .= "$delim$_";
364 }
365 }
366
367 # handle %TMPL:P{"..."}% recursively
3684848µs113.3ms $result =~ s/(%TMPL\:P\{.*?\}%)/_expandTrivialTemplate( $this, $1)/ge;
# spent 13.3ms making 1 call to Foswiki::Templates::_expandTrivialTemplate
369
370 # SMELL: legacy - leading spaces to tabs, should not be required
3714780µs $result =~ s|^(( {3})+)|"\t" x (length($1)/3)|gem;
372
373 $this->saveTemplateToCache( '_complete', $name, $skins, $web, $result )
374 if (TRACE);
37547214µs return $result;
376}
377
378# STATIC: Return value: raw template text, or undef if read fails
379
# spent 52.5ms (18.5+34.0) within Foswiki::Templates::_readTemplateFile which was called 102 times, avg 515µs/call: # 55 times (9.54ms+24.1ms) by Foswiki::Templates::readTemplate at line 280, avg 612µs/call # 47 times (8.96ms+9.92ms) by Foswiki::Templates::readTemplate at line 254, avg 402µs/call
sub _readTemplateFile {
380102154µs my ( $this, $name, $skins, $web ) = @_;
38110261µs my $session = $this->{session};
382
383 # SMELL: not i18n-friendly (can't have accented characters in template name)
384 # zap anything suspicious
385102128µs $name =~ s/[^A-Za-z0-9_,.\/]//g;
386
387 # if the name ends in .tmpl, then this is an explicit include from
388 # the templates directory. No further searching required.
389102109µs if ( $name =~ m/\.tmpl$/ ) {
390 my $text =
391 _decomment(
392 _readFile( $session, "$Foswiki::cfg{TemplateDir}/$name" ) );
393 $this->saveTemplateToCache( '_cache', $name, $skins, $web, $text )
394 if (TRACE);
395 return $text;
396 }
397
39810250µs my $userdirweb = $web;
39910241µs my $userdirname = $name;
400102160µs if ( $name =~ m/^(.+)\.(.+?)$/ ) {
401
402 # ucfirst taints if use locale is in force
403 $userdirweb = Foswiki::Sandbox::untaintUnchecked( ucfirst($1) );
404 $userdirname = Foswiki::Sandbox::untaintUnchecked( ucfirst($2) );
405
406 # if the name can be parsed into $web.$name, then this is an attempt
407 # to explicit include that topic. No further searching required.
408 if ( $session->topicExists( $userdirweb, $userdirname ) ) {
409 my $meta =
410 Foswiki::Meta->load( $session, $userdirweb, $userdirname );
411
412 # Check we are allowed access
413 unless ( $meta->haveAccess( 'VIEW', $session->{user} ) ) {
414 return $this->{session}->inlineAlert( 'alerts', 'access_denied',
415 "$userdirweb.$userdirname" );
416 }
417 my $text = $meta->text();
418 $text = '' unless defined $text;
419
420 $text =
421 "<!--$userdirweb/$userdirname-->\n"
422 . $text
423 . "<!--/$userdirweb/$userdirname-->\n"
424 if (TRACE);
425
426 $text = _decomment($text);
427 $this->saveTemplateToCache( '_cache', $name, $skins, $web, $text )
428 if (TRACE);
429 return $text;
430 }
431 }
432 else {
433
434 # ucfirst taints if use locale is in force
435102364µs102612µs $userdirweb =
# spent 612µs making 102 calls to Foswiki::Sandbox::untaintUnchecked, avg 6µs/call
436 Foswiki::Sandbox::untaintUnchecked( ucfirst($userdirweb) );
437102234µs102243µs $userdirname =
# spent 243µs making 102 calls to Foswiki::Sandbox::untaintUnchecked, avg 2µs/call
438 Foswiki::Sandbox::untaintUnchecked( ucfirst($userdirname) );
439 }
440
441102241µs my @skinList = split( /\,\s*/, $skins );
44210250µs my $nrskins = $#skinList;
443
4441021.03ms my @templatePath = split( /\s*,\s*/, $Foswiki::cfg{TemplatePath} );
445102139µs if (
446 ( $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{Enabled} )
447 && ( lc($name) eq 'foswiki' )
448 && defined(
449 $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{TemplatePath}
450 )
451 )
452 {
453
454 # TWikiCompatibility, need to test to see if there is a twiki.skin tmpl
455 @templatePath =
456 @{ $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{TemplatePath} };
457 }
458
459 # Search the $Foswiki::cfg{TemplatePath} for the skinned versions
46010245µs my @candidates = ();
461
46210236µs $nrskins = 0 if $nrskins < 0;
463
46410236µs my $nrtemplates = $#templatePath;
465
466102329µs for ( my $templateixd = 0 ; $templateixd <= $nrtemplates ; $templateixd++ )
467 {
468816721µs for ( my $idx = 0 ; $idx <= $nrskins ; $idx++ ) {
469816247µs my $file = $templatePath[$templateixd];
470816105µs my $userdir = 0;
471
472 # also need to do %PUBURL% etc.?
473 # push the first time even if not modified
474816174µs my $skin = $skinList[$idx] || '';
475
476 # consider skin templates first
477 # this is done by giving the template path with 'skin' in it
478 # a higher sort priority (so a lower number: 0)
479816414µs my $isSkinned = ( $file =~ m/\$skin/ ? 0 : 1 );
480
481816130µs my $webName = $web || '';
482816101µs my $tmplName = $name || '';
483816494µs unless ( $file =~ m/.tmpl$/ ) {
484
485 # Could also use $Skin, $Web, $Name to indicate uppercase
48640877µs $userdir = 1;
487
488 # Again untainting when using ucfirst
489408503µs4081.06ms $skin = Foswiki::Sandbox::untaintUnchecked( ucfirst($skin) );
# spent 1.06ms making 408 calls to Foswiki::Sandbox::untaintUnchecked, avg 3µs/call
49040856µs $webName = $userdirweb;
491408109µs $tmplName = $userdirname;
492 }
493816841µs $file =~ s/\$skin/$skin/g;
494816705µs $file =~ s/\$web/$webName/g;
4958161.20ms $file =~ s/\$name/$tmplName/g;
496
497# sort priority is:
498# primary: if template path has 'skin' in it; so that skin templates are considered first
499# secondary: the skin order number
500# tertiary: the template path order number
501
5028161.59ms push(
503 @candidates,
504 {
505 primary => $isSkinned,
506 secondary => $idx,
507 tertiary => $templateixd,
508 file => $file,
509 userdir => $userdir,
510 skin => $skin
511 }
512 );
513 }
514 }
515
516 # sort
517 @candidates = sort {
5181326768µs foreach my $i (qw/primary secondary tertiary/)
519 {
52028561.95ms if ( $a->{$i} < $b->{$i} ) {
521 return -1;
522 }
523 elsif ( $a->{$i} > $b->{$i} ) {
524 return 1;
525 }
526 }
527 return 0;
528 } @candidates;
529
53010274µs foreach my $candidate (@candidates) {
531432235µs my $file = $candidate->{file};
532
5334321.36ms if ( $candidate->{userdir} ) {
534
535116350µs1161.10ms my ( $web1, $name1 ) =
# spent 1.10ms making 116 calls to Foswiki::normalizeWebTopicName, avg 9µs/call
536 $session->normalizeWebTopicName( $web, $file );
537
538116349µs1168.07ms if ( $session->topicExists( $web1, $name1 ) ) {
# spent 8.07ms making 116 calls to Foswiki::topicExists, avg 70µs/call
539
540 # recursion prevention.
541 next
542 if (
543 defined(
544 $this->{files}
545 ->{ 'topic' . $session->{user}, $name1, $web1 }
546 )
547 );
548 $this->{files}->{ 'topic' . $session->{user}, $name1, $web1 } =
549 1;
550
551 # access control
552 my $meta = Foswiki::Meta->load( $session, $web1, $name1 );
553 next unless $meta->haveAccess( 'VIEW', $session->{user} );
554
555 my $text = $meta->text();
556 $text = '' unless defined $text;
557
558 $text = "<!--$web1.$name1-->\n$text<!--/$web1.$name1-->\n"
559 if (TRACE);
560
561 $text = _decomment($text);
562 $this->saveTemplateToCache( '_cache', $name, $skins, $web,
563 $text )
564 if (TRACE);
565 return $text;
566 }
567 }
568 elsif ( -e $file ) {
569145222µs next if ( defined( $this->{files}->{$file} ) );
570
571 # recursion prevention.
572100142µs $this->{files}->{$file} = 1;
573
574100456µs20023.0ms my $text = _decomment( _readFile( $session, $file ) );
# spent 16.1ms making 100 calls to Foswiki::Templates::_readFile, avg 161µs/call # spent 6.84ms making 100 calls to Foswiki::Templates::_decomment, avg 68µs/call
575 $this->saveTemplateToCache( '_cache', $name, $skins, $web, $text )
576 if (TRACE);
577100942µs return $text;
578 }
579 }
580
581 # File was not found
582212µs return undef;
583}
584
585
# spent 16.1ms (7.13+8.99) within Foswiki::Templates::_readFile which was called 100 times, avg 161µs/call: # 100 times (7.13ms+8.99ms) by Foswiki::Templates::_readTemplateFile at line 574, avg 161µs/call
sub _readFile {
586100116µs my ( $session, $fn ) = @_;
58710015µs my $F;
588
5891023.23ms3013.96ms if ( open( $F, '<:encoding(utf-8)', $fn ) ) {
# spent 2.01ms making 100 calls to Encode::find_encoding, avg 20µs/call # spent 1.40ms making 100 calls to Encode::Encoding::renew, avg 14µs/call # spent 411µs making 1 call to PerlIO::import # spent 136µs making 100 calls to Encode::Encoding::needs_lines, avg 1µs/call
590100176µs local $/;
5911006.46ms5905.23ms my $text = <$F>;
# spent 4.85ms making 295 calls to Encode::utf8::decode_xs, avg 16µs/call # spent 374µs making 295 calls to Encode::Encoding::renewed, avg 1µs/call
592100709µs close($F);
593
594 $text = "<!--$fn-->\n$text<!--/$fn-->\n" if (TRACE);
595
596100666µs return $text;
597 }
598 else {
599 $session->logger->log( 'warning', "$fn: $!" );
600 return undef;
601 }
602}
603
604
# spent 6.84ms within Foswiki::Templates::_decomment which was called 100 times, avg 68µs/call: # 100 times (6.84ms+0s) by Foswiki::Templates::_readTemplateFile at line 574, avg 68µs/call
sub _decomment {
605100122µs my $text = shift;
606
60710025µs return $text unless $text;
608
609 # Kill comments, marked by %{ ... }%
610 # (and remove whitespace either side of the comment)
6111006.44ms $text =~ s/\s*%\{.*?\}%\s*//sg;
612100330µs return $text;
613}
614
615#See http://wikiring.com/Blog/BlogEntry8?cat=WikiRing
616#used for debugging templates, and later maybe for speed.
617sub saveTemplateToCache {
618 my ( $this, $cacheName, $name, $skins, $web, $tmplText ) = @_;
619 $skins = '' unless ( defined($skins) );
620 $web = '' unless ( defined($web) );
621
622 my $tmpl_cachedir = $Foswiki::cfg{TemplateDir} . $cacheName;
623 mkdir($tmpl_cachedir) unless ( -e $tmpl_cachedir );
624 my $filename = Foswiki::Sandbox::untaintUnchecked(
625 $tmpl_cachedir . '/' . $name . '__' . $skins . '__' . $web . '.tmpl' );
626
627 open( my $file, '>:encoding(utf-8)', $filename ) or do {
628 die "Can't create file $filename - $!\n" if DEBUG;
629 print STDERR "Can't create file $filename - $!\n";
630
631 return;
632 };
633 print $file $tmplText;
634 close($file);
635}
636
637#unused, but can be used for a speedup by caching the expanded Template
638sub getTemplateFromCache {
639 my ( $this, $name, $skins, $web ) = @_;
640 $skins = '' unless ( defined($skins) );
641 $web = '' unless ( defined($web) );
642
643 my $tmpl_cachedir = $Foswiki::cfg{TemplateDir} . '_cache';
644 mkdir($tmpl_cachedir) unless ( -e $tmpl_cachedir );
645 my $filename = Foswiki::Sandbox::untaintUnchecked(
646 $tmpl_cachedir . '/' . $name . '__' . $skins . '__' . $web . '.tmpl' );
647
648 if ( -e $filename ) {
649 open( my $in_file, '<:encoding(utf-8)', $filename ) or return;
650 local $/ = undef; # set to read to EOF
651 my $data = <$in_file>;
652 close($in_file);
653 return $data;
654 }
655}
656
65712µs1;
658__END__