processNocacheCode()   B
last analyzed

Complexity

Conditions 11
Paths 3

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 3
nop 2
dl 0
loc 31
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Smarty Internal Plugin Smarty Template Compiler Base
4
 * This file contains the basic classes and methods for compiling Smarty templates with lexer/parser
5
 *
6
 * @package    Smarty
7
 * @subpackage Compiler
8
 * @author     Uwe Tews
9
 */
10
11
/**
12
 * Main abstract compiler class
13
 *
14
 * @package    Smarty
15
 * @subpackage Compiler
16
 *
17
 * @property Smarty_Internal_SmartyTemplateCompiler $prefixCompiledCode  = ''
18
 * @property Smarty_Internal_SmartyTemplateCompiler $postfixCompiledCode = ''
19
 * @method   registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false)
20
 * @method   unregisterPostCompileCallback($key)
21
 */
22
abstract class Smarty_Internal_TemplateCompilerBase
23
{
24
    /**
25
     * compile tag objects cache
26
     *
27
     * @var array
28
     */
29
    public static $_tag_objects = array();
30
31
    /**
32
     * counter for prefix variable number
33
     *
34
     * @var int
35
     */
36
    public static $prefixVariableNumber = 0;
37
38
    /**
39
     * Smarty object
40
     *
41
     * @var Smarty
42
     */
43
    public $smarty = null;
44
45
    /**
46
     * Parser object
47
     *
48
     * @var Smarty_Internal_Templateparser
49
     */
50
    public $parser = null;
51
52
    /**
53
     * hash for nocache sections
54
     *
55
     * @var mixed
56
     */
57
    public $nocache_hash = null;
58
59
    /**
60
     * suppress generation of nocache code
61
     *
62
     * @var bool
63
     */
64
    public $suppressNocacheProcessing = false;
65
66
    /**
67
     * caching enabled (copied from template object)
68
     *
69
     * @var int
70
     */
71
    public $caching = 0;
72
73
    /**
74
     * tag stack
75
     *
76
     * @var array
77
     */
78
    public $_tag_stack = array();
79
80
    /**
81
     * tag stack count
82
     *
83
     * @var array
84
     */
85
    public $_tag_stack_count = array();
86
87
    /**
88
     * Plugins used by template
89
     *
90
     * @var array
91
     */
92
    public $required_plugins = array('compiled' => array(), 'nocache' => array());
93
94
    /**
95
     * Required plugins stack
96
     *
97
     * @var array
98
     */
99
    public $required_plugins_stack = array();
100
101
    /**
102
     * current template
103
     *
104
     * @var Smarty_Internal_Template
105
     */
106
    public $template = null;
107
108
    /**
109
     * merged included sub template data
110
     *
111
     * @var array
112
     */
113
    public $mergedSubTemplatesData = array();
114
115
    /**
116
     * merged sub template code
117
     *
118
     * @var array
119
     */
120
    public $mergedSubTemplatesCode = array();
121
122
    /**
123
     * collected template properties during compilation
124
     *
125
     * @var array
126
     */
127
    public $templateProperties = array();
128
129
    /**
130
     * source line offset for error messages
131
     *
132
     * @var int
133
     */
134
    public $trace_line_offset = 0;
135
136
    /**
137
     * trace uid
138
     *
139
     * @var string
140
     */
141
    public $trace_uid = '';
142
143
    /**
144
     * trace file path
145
     *
146
     * @var string
147
     */
148
    public $trace_filepath = '';
149
150
    /**
151
     * stack for tracing file and line of nested {block} tags
152
     *
153
     * @var array
154
     */
155
    public $trace_stack = array();
156
157
    /**
158
     * plugins loaded by default plugin handler
159
     *
160
     * @var array
161
     */
162
    public $default_handler_plugins = array();
163
164
    /**
165
     * saved preprocessed modifier list
166
     *
167
     * @var mixed
168
     */
169
    public $default_modifier_list = null;
170
171
    /**
172
     * force compilation of complete template as nocache
173
     *
174
     * @var boolean
175
     */
176
    public $forceNocache = false;
177
178
    /**
179
     * flag if compiled template file shall we written
180
     *
181
     * @var bool
182
     */
183
    public $write_compiled_code = true;
184
185
    /**
186
     * Template functions
187
     *
188
     * @var array
189
     */
190
    public $tpl_function = array();
191
192
    /**
193
     * called sub functions from template function
194
     *
195
     * @var array
196
     */
197
    public $called_functions = array();
198
199
    /**
200
     * compiled template or block function code
201
     *
202
     * @var string
203
     */
204
    public $blockOrFunctionCode = '';
205
206
    /**
207
     * php_handling setting either from Smarty or security
208
     *
209
     * @var int
210
     */
211
    public $php_handling = 0;
212
213
    /**
214
     * flags for used modifier plugins
215
     *
216
     * @var array
217
     */
218
    public $modifier_plugins = array();
219
220
    /**
221
     * type of already compiled modifier
222
     *
223
     * @var array
224
     */
225
    public $known_modifier_type = array();
226
227
    /**
228
     * parent compiler object for merged subtemplates and template functions
229
     *
230
     * @var Smarty_Internal_TemplateCompilerBase
231
     */
232
    public $parent_compiler = null;
233
234
    /**
235
     * Flag true when compiling nocache section
236
     *
237
     * @var bool
238
     */
239
    public $nocache = false;
240
241
    /**
242
     * Flag true when tag is compiled as nocache
243
     *
244
     * @var bool
245
     */
246
    public $tag_nocache = false;
247
248
    /**
249
     * Compiled tag prefix code
250
     *
251
     * @var array
252
     */
253
    public $prefix_code = array();
254
255
    /**
256
     * used prefix variables by current compiled tag
257
     *
258
     * @var array
259
     */
260
    public $usedPrefixVariables = array();
261
262
    /**
263
     * Prefix code  stack
264
     *
265
     * @var array
266
     */
267
    public $prefixCodeStack = array();
268
269
    /**
270
     * Tag has compiled code
271
     *
272
     * @var bool
273
     */
274
    public $has_code = false;
275
276
    /**
277
     * A variable string was compiled
278
     *
279
     * @var bool
280
     */
281
    public $has_variable_string = false;
282
283
    /**
284
     * Stack for {setfilter} {/setfilter}
285
     *
286
     * @var array
287
     */
288
    public $variable_filter_stack = array();
289
290
    /**
291
     * variable filters for {setfilter} {/setfilter}
292
     *
293
     * @var array
294
     */
295
    public $variable_filters = array();
296
297
    /**
298
     * Nesting count of looping tags like {foreach}, {for}, {section}, {while}
299
     *
300
     * @var int
301
     */
302
    public $loopNesting = 0;
303
304
    /**
305
     * Strip preg pattern
306
     *
307
     * @var string
308
     */
309
    public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';
310
311
    /**
312
     * plugin search order
313
     *
314
     * @var array
315
     */
316
    public $plugin_search_order = array(
317
        'function',
318
        'block',
319
        'compiler',
320
        'class'
321
    );
322
323
    /**
324
     * General storage area for tag compiler plugins
325
     *
326
     * @var array
327
     */
328
    public $_cache = array();
329
330
    /**
331
     * Lexer preg pattern for left delimiter
332
     *
333
     * @var string
334
     */
335
    private $ldelPreg = '[{]';
336
337
    /**
338
     * Lexer preg pattern for right delimiter
339
     *
340
     * @var string
341
     */
342
    private $rdelPreg = '[}]';
343
344
    /**
345
     * Length of right delimiter
346
     *
347
     * @var int
348
     */
349
    private $rdelLength = 0;
350
351
    /**
352
     * Length of left delimiter
353
     *
354
     * @var int
355
     */
356
    private $ldelLength = 0;
357
358
    /**
359
     * Lexer preg pattern for user literals
360
     *
361
     * @var string
362
     */
363
    private $literalPreg = '';
364
365
    /**
366
     * Initialize compiler
367
     *
368
     * @param Smarty $smarty global instance
369
     */
370
    public function __construct(Smarty $smarty)
371
    {
372
        $this->smarty = $smarty;
373
        $this->nocache_hash = str_replace(
374
            array(
375
                '.',
376
                ','
377
            ),
378
            '_',
379
            uniqid(mt_rand(), true)
380
        );
381
    }
382
383
    /**
384
     * Method to compile a Smarty template
385
     *
386
     * @param Smarty_Internal_Template                  $template template object to compile
387
     * @param bool                                      $nocache  true is shall be compiled in nocache mode
388
     * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler
389
     *
390
     * @return bool true if compiling succeeded, false if it failed
391
     * @throws \Exception
392
     */
393
    public function compileTemplate(
394
        Smarty_Internal_Template $template,
395
        $nocache = null,
396
        Smarty_Internal_TemplateCompilerBase $parent_compiler = null
397
    ) {
398
        // get code frame of compiled template
399
        $_compiled_code = $template->smarty->ext->_codeFrame->create(
400
            $template,
401
            $this->compileTemplateSource(
402
                $template,
403
                $nocache,
404
                $parent_compiler
405
            ),
406
            $this->postFilter($this->blockOrFunctionCode) .
407
            join('', $this->mergedSubTemplatesCode),
408
            false,
409
            $this
410
        );
411
        return $_compiled_code;
412
    }
413
414
    /**
415
     * Compile template source and run optional post filter
416
     *
417
     * @param \Smarty_Internal_Template             $template
418
     * @param null|bool                             $nocache flag if template must be compiled in nocache mode
419
     * @param \Smarty_Internal_TemplateCompilerBase $parent_compiler
420
     *
421
     * @return string
422
     * @throws \Exception
423
     */
424
    public function compileTemplateSource(
425
        Smarty_Internal_Template $template,
426
        $nocache = null,
427
        Smarty_Internal_TemplateCompilerBase $parent_compiler = null
428
    ) {
429
        try {
430
            // save template object in compiler class
431
            $this->template = $template;
432
            if (property_exists($this->template->smarty, 'plugin_search_order')) {
433
                $this->plugin_search_order = $this->template->smarty->plugin_search_order;
0 ignored issues
show
Documentation introduced by
The property plugin_search_order does not exist on object<Smarty>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
434
            }
435
            if ($this->smarty->debugging) {
436
                if (!isset($this->smarty->_debug)) {
437
                    $this->smarty->_debug = new Smarty_Internal_Debug();
438
                }
439
                $this->smarty->_debug->start_compile($this->template);
440
            }
441
            if (isset($this->template->smarty->security_policy)) {
442
                $this->php_handling = $this->template->smarty->security_policy->php_handling;
443
            } else {
444
                $this->php_handling = $this->template->smarty->php_handling;
445
            }
446
            $this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
447
            $nocache = isset($nocache) ? $nocache : false;
448
            if (empty($template->compiled->nocache_hash)) {
449
                $template->compiled->nocache_hash = $this->nocache_hash;
450
            } else {
451
                $this->nocache_hash = $template->compiled->nocache_hash;
452
            }
453
            $this->caching = $template->caching;
454
            // flag for nocache sections
455
            $this->nocache = $nocache;
456
            $this->tag_nocache = false;
457
            // reset has nocache code flag
458
            $this->template->compiled->has_nocache_code = false;
459
            $this->has_variable_string = false;
460
            $this->prefix_code = array();
461
            // add file dependency
462
            if ($this->smarty->merge_compiled_includes || $this->template->source->handler->checkTimestamps()) {
463
                $this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] =
464
                    array(
465
                        $this->template->source->filepath,
466
                        $this->template->source->getTimeStamp(),
467
                        $this->template->source->type,
468
                    );
469
            }
470
            $this->smarty->_current_file = $this->template->source->filepath;
471
            // get template source
472
            if (!empty($this->template->source->components)) {
473
                // we have array of inheritance templates by extends: resource
474
                // generate corresponding source code sequence
475
                $_content =
476
                    Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template);
477
            } else {
478
                // get template source
479
                $_content = $this->template->source->getContent();
480
            }
481
            $_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true));
0 ignored issues
show
Documentation introduced by
$this->doCompile($this->...ilter($_content), true) is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
482
            if (!empty($this->required_plugins[ 'compiled' ]) || !empty($this->required_plugins[ 'nocache' ])) {
483
                $_compiled_code = '<?php ' . $this->compileRequiredPlugins() . "?>\n" . $_compiled_code;
484
            }
485
        } catch (Exception $e) {
486
            if ($this->smarty->debugging) {
487
                $this->smarty->_debug->end_compile($this->template);
488
            }
489
            $this->_tag_stack = array();
490
            // free memory
491
            $this->parent_compiler = null;
492
            $this->template = null;
493
            $this->parser = null;
494
            throw $e;
495
        }
496
        if ($this->smarty->debugging) {
497
            $this->smarty->_debug->end_compile($this->template);
498
        }
499
        $this->parent_compiler = null;
500
        $this->parser = null;
501
        return $_compiled_code;
502
    }
503
504
    /**
505
     * Optionally process compiled code by post filter
506
     *
507
     * @param string $code compiled code
508
     *
509
     * @return string
510
     * @throws \SmartyException
511
     */
512
    public function postFilter($code)
513
    {
514
        // run post filter if on code
515
        if (!empty($code)
516
            && (isset($this->smarty->autoload_filters[ 'post' ]) || isset($this->smarty->registered_filters[ 'post' ]))
517
        ) {
518
            return $this->smarty->ext->_filterHandler->runFilter('post', $code, $this->template);
519
        } else {
520
            return $code;
521
        }
522
    }
523
524
    /**
525
     * Run optional prefilter
526
     *
527
     * @param string $_content template source
528
     *
529
     * @return string
530
     * @throws \SmartyException
531
     */
532
    public function preFilter($_content)
533
    {
534
        // run pre filter if required
535
        if ($_content !== ''
536
            && ((isset($this->smarty->autoload_filters[ 'pre' ]) || isset($this->smarty->registered_filters[ 'pre' ])))
537
        ) {
538
            return $this->smarty->ext->_filterHandler->runFilter('pre', $_content, $this->template);
539
        } else {
540
            return $_content;
541
        }
542
    }
543
544
    /**
545
     * Compile Tag
546
     * This is a call back from the lexer/parser
547
     *
548
     * Save current prefix code
549
     * Compile tag
550
     * Merge tag prefix code with saved one
551
     * (required nested tags in attributes)
552
     *
553
     * @param string $tag       tag name
554
     * @param array  $args      array with tag attributes
555
     * @param array  $parameter array with compilation parameter
556
     *
557
     * @throws SmartyCompilerException
558
     * @throws SmartyException
559
     * @return string compiled code
560
     */
561
    public function compileTag($tag, $args, $parameter = array())
562
    {
563
        $this->prefixCodeStack[] = $this->prefix_code;
564
        $this->prefix_code = array();
565
        $result = $this->compileTag2($tag, $args, $parameter);
566
        $this->prefix_code = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
567
        return $result;
568
    }
569
570
    /**
571
     * compile variable
572
     *
573
     * @param string $variable
574
     *
575
     * @return string
576
     */
577
    public function compileVariable($variable)
578
    {
579
        if (!strpos($variable, '(')) {
580
            // not a variable variable
581
            $var = trim($variable, '\'');
582
            $this->tag_nocache = $this->tag_nocache |
583
                                 $this->template->ext->getTemplateVars->_getVariable(
584
                                     $this->template,
585
                                     $var,
586
                                     null,
587
                                     true,
588
                                     false
589
                                 )->nocache;
590
            // todo $this->template->compiled->properties['variables'][$var] = $this->tag_nocache | $this->nocache;
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
591
        }
592
        return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';
593
    }
594
595
    /**
596
     * compile config variable
597
     *
598
     * @param string $variable
599
     *
600
     * @return string
601
     */
602
    public function compileConfigVariable($variable)
603
    {
604
        // return '$_smarty_tpl->config_vars[' . $variable . ']';
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
605
        return '$_smarty_tpl->smarty->ext->configLoad->_getConfigVariable($_smarty_tpl, ' . $variable . ')';
606
    }
607
608
    /**
609
     * compile PHP function call
610
     *
611
     * @param string $name
612
     * @param array  $parameter
613
     *
614
     * @return string
615
     * @throws \SmartyCompilerException
616
     */
617
    public function compilePHPFunctionCall($name, $parameter)
618
    {
619
        if (!$this->smarty->security_policy || $this->smarty->security_policy->isTrustedPhpFunction($name, $this)) {
620
            if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0
621
                || strcasecmp($name, 'array') === 0 || is_callable($name)
622
            ) {
623
                $func_name = strtolower($name);
624
                $par = implode(',', $parameter);
625
                $parHasFuction = strpos($par, '(') !== false;
626
                if ($func_name === 'isset') {
627
                    if (count($parameter) === 0) {
628
                        $this->trigger_template_error('Illegal number of parameter in "isset()"');
629
                    }
630
                    if ($parHasFuction) {
631
                        $pa = array();
632
                        foreach ($parameter as $p) {
633
                            $pa[] = (strpos($p, '(') === false) ? ('isset(' . $p . ')') : ('(' . $p . ' !== null )');
634
                        }
635
                        return '(' . implode(' && ', $pa) . ')';
636
                    } else {
637
                        $isset_par = str_replace("')->value", "',null,true,false)->value", $par);
638
                    }
639
                    return $name . '(' . $isset_par . ')';
640
                } elseif (in_array(
641
                    $func_name,
642
                    array(
643
                        'empty',
644
                        'reset',
645
                        'current',
646
                        'end',
647
                        'prev',
648
                        'next'
649
                    )
650
                )
651
                ) {
652
                    if (count($parameter) !== 1) {
653
                        $this->trigger_template_error("Illegal number of parameter in '{$func_name()}'");
654
                    }
655
                    if ($func_name === 'empty') {
656
                        if ($parHasFuction && version_compare(PHP_VERSION, '5.5.0', '<')) {
657
                            return '(' . $parameter[ 0 ] . ' === false )';
658
                        } else {
659
                            return $func_name . '(' .
660
                                   str_replace("')->value", "',null,true,false)->value", $parameter[ 0 ]) . ')';
661
                        }
662
                    } else {
663
                        return $func_name . '(' . $parameter[ 0 ] . ')';
664
                    }
665
                } else {
666
                    return $name . '(' . implode(',', $parameter) . ')';
667
                }
668
            } else {
669
                $this->trigger_template_error("unknown function '{$name}'");
670
            }
671
        }
672
    }
673
674
    /**
675
     * This method is called from parser to process a text content section
676
     * - remove text from inheritance child templates as they may generate output
677
     * - strip text if strip is enabled
678
     *
679
     * @param string $text
680
     *
681
     * @return null|\Smarty_Internal_ParseTree_Text
682
     */
683
    public function processText($text)
684
    {
685
        if ((string)$text != '') {
686
            $store = array();
687
            $_store = 0;
688
            if ($this->parser->strip) {
689
                if (strpos($text, '<') !== false) {
690
                    // capture html elements not to be messed with
691
                    $_offset = 0;
692
                    if (preg_match_all(
693
                        '#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
694
                        $text,
695
                        $matches,
696
                        PREG_OFFSET_CAPTURE | PREG_SET_ORDER
697
                    )
698
                    ) {
699
                        foreach ($matches as $match) {
700
                            $store[] = $match[ 0 ][ 0 ];
701
                            $_length = strlen($match[ 0 ][ 0 ]);
702
                            $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
703
                            $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
704
                            $_offset += $_length - strlen($replace);
705
                            $_store++;
706
                        }
707
                    }
708
                    $expressions = array(// replace multiple spaces between tags by a single space
709
                                         '#(:SMARTY@!@|>)[\040\011]+(?=@!@SMARTY:|<)#s'                            => '\1 \2',
710
                                         // remove newline between tags
711
                                         '#(:SMARTY@!@|>)[\040\011]*[\n]\s*(?=@!@SMARTY:|<)#s'                     => '\1\2',
712
                                         // remove multiple spaces between attributes (but not in attribute values!)
713
                                         '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
714
                                         '#>[\040\011]+$#Ss'                                                       => '> ',
715
                                         '#>[\040\011]*[\n]\s*$#Ss'                                                => '>',
716
                                         $this->stripRegEx                                                         => '',
717
                    );
718
                    $text = preg_replace(array_keys($expressions), array_values($expressions), $text);
719
                    $_offset = 0;
720
                    if (preg_match_all(
721
                        '#@!@SMARTY:([0-9]+):SMARTY@!@#is',
722
                        $text,
723
                        $matches,
724
                        PREG_OFFSET_CAPTURE | PREG_SET_ORDER
725
                    )
726
                    ) {
727
                        foreach ($matches as $match) {
728
                            $_length = strlen($match[ 0 ][ 0 ]);
729
                            $replace = $store[ $match[ 1 ][ 0 ] ];
730
                            $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
731
                            $_offset += strlen($replace) - $_length;
732
                            $_store++;
733
                        }
734
                    }
735
                } else {
736
                    $text = preg_replace($this->stripRegEx, '', $text);
737
                }
738
            }
739
            return new Smarty_Internal_ParseTree_Text($text);
740
        }
741
        return null;
742
    }
743
744
    /**
745
     * lazy loads internal compile plugin for tag and calls the compile method
746
     * compile objects cached for reuse.
747
     * class name format:  Smarty_Internal_Compile_TagName
748
     * plugin filename format: Smarty_Internal_TagName.php
749
     *
750
     * @param string $tag    tag name
751
     * @param array  $args   list of tag attributes
752
     * @param mixed  $param1 optional parameter
753
     * @param mixed  $param2 optional parameter
754
     * @param mixed  $param3 optional parameter
755
     *
756
     * @return bool|string compiled code or false
757
     * @throws \SmartyCompilerException
758
     */
759
    public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
760
    {
761
        /* @var Smarty_Internal_CompileBase $tagCompiler */
762
        $tagCompiler = $this->getTagCompiler($tag);
763
        // compile this tag
764
        return $tagCompiler === false ? false : $tagCompiler->compile($args, $this, $param1, $param2, $param3);
765
    }
766
767
    /**
768
     * lazy loads internal compile plugin for tag compile objects cached for reuse.
769
     *
770
     * class name format:  Smarty_Internal_Compile_TagName
771
     * plugin filename format: Smarty_Internal_TagName.php
772
     *
773
     * @param string $tag tag name
774
     *
775
     * @return bool|\Smarty_Internal_CompileBase tag compiler object or false if not found
776
     */
777
    public function getTagCompiler($tag)
778
    {
779
        // re-use object if already exists
780
        if (!isset(self::$_tag_objects[ $tag ])) {
781
            // lazy load internal compiler plugin
782
            $_tag = explode('_', $tag);
783
            $_tag = array_map('ucfirst', $_tag);
784
            $class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);
785
            if (class_exists($class_name)
786
                && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))
787
            ) {
788
                self::$_tag_objects[ $tag ] = new $class_name;
789
            } else {
790
                self::$_tag_objects[ $tag ] = false;
791
            }
792
        }
793
        return self::$_tag_objects[ $tag ];
794
    }
795
796
    /**
797
     * Check for plugins and return function name
798
     *
799
     * @param        $plugin_name
800
     * @param string $plugin_type type of plugin
801
     *
802
     * @return string call name of function
803
     * @throws \SmartyException
804
     */
805
    public function getPlugin($plugin_name, $plugin_type)
806
    {
807
        $function = null;
808
        if ($this->caching && ($this->nocache || $this->tag_nocache)) {
809
            if (isset($this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
810
                $function =
811
                    $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
812
            } elseif (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
813
                $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ] =
814
                    $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ];
815
                $function =
816
                    $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
817
            }
818
        } else {
819
            if (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
820
                $function =
821
                    $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
822
            } elseif (isset($this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
823
                $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ] =
824
                    $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ];
825
                $function =
826
                    $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
827
            }
828
        }
829
        if (isset($function)) {
830
            if ($plugin_type === 'modifier') {
831
                $this->modifier_plugins[ $plugin_name ] = true;
832
            }
833
            return $function;
834
        }
835
        // loop through plugin dirs and find the plugin
836
        $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
837
        $file = $this->smarty->loadPlugin($function, false);
838
        if (is_string($file)) {
839
            if ($this->caching && ($this->nocache || $this->tag_nocache)) {
840
                $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
841
                    $file;
842
                $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
843
                    $function;
844
            } else {
845
                $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
846
                    $file;
847
                $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
848
                    $function;
849
            }
850
            if ($plugin_type === 'modifier') {
851
                $this->modifier_plugins[ $plugin_name ] = true;
852
            }
853
            return $function;
854
        }
855
        if (is_callable($function)) {
856
            // plugin function is defined in the script
857
            return $function;
858
        }
859
        return false;
860
    }
861
862
    /**
863
     * Check for plugins by default plugin handler
864
     *
865
     * @param string $tag         name of tag
866
     * @param string $plugin_type type of plugin
867
     *
868
     * @return bool true if found
869
     * @throws \SmartyCompilerException
870
     */
871
    public function getPluginFromDefaultHandler($tag, $plugin_type)
872
    {
873
        $callback = null;
874
        $script = null;
875
        $cacheable = true;
876
        $result = call_user_func_array(
877
            $this->smarty->default_plugin_handler_func,
878
            array(
879
                $tag,
880
                $plugin_type,
881
                $this->template,
882
                &$callback,
883
                &$script,
884
                &$cacheable,
885
            )
886
        );
887
        if ($result) {
888
            $this->tag_nocache = $this->tag_nocache || !$cacheable;
889
            if ($script !== null) {
890
                if (is_file($script)) {
891
                    if ($this->caching && ($this->nocache || $this->tag_nocache)) {
892
                        $this->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'file' ] =
893
                            $script;
894
                        $this->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'function' ] =
895
                            $callback;
896
                    } else {
897
                        $this->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'file' ] =
898
                            $script;
899
                        $this->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'function' ] =
900
                            $callback;
901
                    }
902
                    include_once $script;
903
                } else {
904
                    $this->trigger_template_error("Default plugin handler: Returned script file '{$script}' for '{$tag}' not found");
905
                }
906
            }
907
            if (is_callable($callback)) {
908
                $this->default_handler_plugins[ $plugin_type ][ $tag ] = array(
909
                    $callback,
910
                    true,
911
                    array()
912
                );
913
                return true;
914
            } else {
915
                $this->trigger_template_error("Default plugin handler: Returned callback for '{$tag}' not callable");
916
            }
917
        }
918
        return false;
919
    }
920
921
    /**
922
     * Append code segments and remove unneeded ?> <?php transitions
923
     *
924
     * @param string $left
925
     * @param string $right
926
     *
927
     * @return string
928
     */
929
    public function appendCode($left, $right)
930
    {
931
        if (preg_match('/\s*\?>\s?$/D', $left) && preg_match('/^<\?php\s+/', $right)) {
932
            $left = preg_replace('/\s*\?>\s?$/D', "\n", $left);
933
            $left .= preg_replace('/^<\?php\s+/', '', $right);
934
        } else {
935
            $left .= $right;
936
        }
937
        return $left;
938
    }
939
940
    /**
941
     * Inject inline code for nocache template sections
942
     * This method gets the content of each template element from the parser.
943
     * If the content is compiled code and it should be not cached the code is injected
944
     * into the rendered output.
945
     *
946
     * @param string  $content content of template element
947
     * @param boolean $is_code true if content is compiled code
948
     *
949
     * @return string  content
950
     */
951
    public function processNocacheCode($content, $is_code)
952
    {
953
        // If the template is not evaluated and we have a nocache section and or a nocache tag
954
        if ($is_code && !empty($content)) {
955
            // generate replacement code
956
            if ((!($this->template->source->handler->recompiled) || $this->forceNocache) && $this->caching
957
                && !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache)
958
            ) {
959
                $this->template->compiled->has_nocache_code = true;
960
                $_output = addcslashes($content, '\'\\');
961
                $_output = str_replace('^#^', '\'', $_output);
962
                $_output =
963
                    "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/{$_output}/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
964
                // make sure we include modifier plugins for nocache code
965
                foreach ($this->modifier_plugins as $plugin_name => $dummy) {
966
                    if (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ])) {
967
                        $this->required_plugins[ 'nocache' ][ $plugin_name ][ 'modifier' ] =
968
                            $this->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ];
969
                    }
970
                }
971
            } else {
972
                $_output = $content;
973
            }
974
        } else {
975
            $_output = $content;
976
        }
977
        $this->modifier_plugins = array();
978
        $this->suppressNocacheProcessing = false;
979
        $this->tag_nocache = false;
980
        return $_output;
981
    }
982
983
    /**
984
     * Get Id
985
     *
986
     * @param string $input
987
     *
988
     * @return bool|string
989
     */
990
    public function getId($input)
991
    {
992
        if (preg_match('~^([\'"]*)([0-9]*[a-zA-Z_]\w*)\1$~', $input, $match)) {
993
            return $match[ 2 ];
994
        }
995
        return false;
996
    }
997
998
    /**
999
     * Get variable name from string
1000
     *
1001
     * @param string $input
1002
     *
1003
     * @return bool|string
1004
     */
1005
    public function getVariableName($input)
1006
    {
1007
        if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) {
1008
            return $match[ 1 ];
1009
        }
1010
        return false;
1011
    }
1012
1013
    /**
1014
     * Set nocache flag in variable or create new variable
1015
     *
1016
     * @param string $varName
1017
     */
1018
    public function setNocacheInVariable($varName)
1019
    {
1020
        // create nocache var to make it know for further compiling
1021
        if ($_var = $this->getId($varName)) {
1022
            if (isset($this->template->tpl_vars[ $_var ])) {
1023
                $this->template->tpl_vars[ $_var ] = clone $this->template->tpl_vars[ $_var ];
1024
                $this->template->tpl_vars[ $_var ]->nocache = true;
1025
            } else {
1026
                $this->template->tpl_vars[ $_var ] = new Smarty_Variable(null, true);
1027
            }
1028
        }
1029
    }
1030
1031
    /**
1032
     * @param array $_attr tag attributes
1033
     * @param array $validScopes
1034
     *
1035
     * @return int|string
1036
     * @throws \SmartyCompilerException
1037
     */
1038
    public function convertScope($_attr, $validScopes)
1039
    {
1040
        $_scope = 0;
1041
        if (isset($_attr[ 'scope' ])) {
1042
            $_scopeName = trim($_attr[ 'scope' ], '\'"');
1043
            if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) {
1044
                $_scope = $_scopeName;
1045
            } elseif (is_string($_scopeName)) {
1046
                $_scopeName = trim($_scopeName, '\'"');
1047
                $_scope = isset($validScopes[ $_scopeName ]) ? $validScopes[ $_scopeName ] : false;
1048
            } else {
1049
                $_scope = false;
1050
            }
1051
            if ($_scope === false) {
1052
                $err = var_export($_scopeName, true);
1053
                $this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);
1054
            }
1055
        }
1056
        return $_scope;
1057
    }
1058
1059
    /**
1060
     * Generate nocache code string
1061
     *
1062
     * @param string $code PHP code
1063
     *
1064
     * @return string
1065
     */
1066
    public function makeNocacheCode($code)
1067
    {
1068
        return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " .
1069
               str_replace('^#^', '\'', addcslashes($code, '\'\\')) .
1070
               "?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
1071
    }
1072
1073
    /**
1074
     * display compiler error messages without dying
1075
     * If parameter $args is empty it is a parser detected syntax error.
1076
     * In this case the parser is called to obtain information about expected tokens.
1077
     * If parameter $args contains a string this is used as error message
1078
     *
1079
     * @param string    $args    individual error message or null
1080
     * @param string    $line    line-number
1081
     * @param null|bool $tagline if true the line number of last tag
1082
     *
1083
     * @throws \SmartyCompilerException when an unexpected token is found
1084
     */
1085
    public function trigger_template_error($args = null, $line = null, $tagline = null)
1086
    {
1087
        $lex = $this->parser->lex;
1088
        if ($tagline === true) {
1089
            // get line number of Tag
1090
            $line = $lex->taglineno;
1091
        } elseif (!isset($line)) {
1092
            // get template source line which has error
1093
            $line = $lex->line;
1094
        } else {
1095
            $line = (int)$line;
1096
        }
1097
        if (in_array(
1098
            $this->template->source->type,
1099
            array(
1100
                'eval',
1101
                'string'
1102
            )
1103
        )
1104
        ) {
1105
            $templateName = $this->template->source->type . ':' . trim(
1106
                    preg_replace(
1107
                        '![\t\r\n]+!',
1108
                        ' ',
1109
                        strlen($lex->data) > 40 ?
1110
                            substr($lex->data, 0, 40) .
1111
                            '...' : $lex->data
1112
                    )
1113
                );
1114
        } else {
1115
            $templateName = $this->template->source->type . ':' . $this->template->source->filepath;
1116
        }
1117
        //        $line += $this->trace_line_offset;
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1118
        $match = preg_split("/\n/", $lex->data);
1119
        $error_text =
1120
            'Syntax error in template "' . (empty($this->trace_filepath) ? $templateName : $this->trace_filepath) .
1121
            '"  on line ' . ($line + $this->trace_line_offset) . ' "' .
1122
            trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])) . '" ';
1123
        if (isset($args)) {
1124
            // individual error message
1125
            $error_text .= $args;
1126
        } else {
1127
            $expect = array();
1128
            // expected token from parser
1129
            $error_text .= ' - Unexpected "' . $lex->value . '"';
1130
            if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {
1131
                foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
1132
                    $exp_token = $this->parser->yyTokenName[ $token ];
1133
                    if (isset($lex->smarty_token_names[ $exp_token ])) {
1134
                        // token type from lexer
1135
                        $expect[] = '"' . $lex->smarty_token_names[ $exp_token ] . '"';
1136
                    } else {
1137
                        // otherwise internal token name
1138
                        $expect[] = $this->parser->yyTokenName[ $token ];
1139
                    }
1140
                }
1141
                $error_text .= ', expected one of: ' . implode(' , ', $expect);
1142
            }
1143
        }
1144
        if ($this->smarty->_parserdebug) {
1145
            $this->parser->errorRunDown();
1146
            echo ob_get_clean();
1147
            flush();
1148
        }
1149
        $e = new SmartyCompilerException($error_text);
1150
        $e->line = $line;
1151
        $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));
1152
        $e->desc = $args;
1153
        $e->template = $this->template->source->filepath;
1154
        throw $e;
1155
    }
1156
1157
    /**
1158
     * Return var_export() value with all white spaces removed
1159
     *
1160
     * @param mixed $value
1161
     *
1162
     * @return string
1163
     */
1164
    public function getVarExport($value)
1165
    {
1166
        return preg_replace('/\s/', '', var_export($value, true));
1167
    }
1168
1169
    /**
1170
     *  enter double quoted string
1171
     *  - save tag stack count
1172
     */
1173
    public function enterDoubleQuote()
1174
    {
1175
        array_push($this->_tag_stack_count, $this->getTagStackCount());
1176
    }
1177
1178
    /**
1179
     * Return tag stack count
1180
     *
1181
     * @return int
1182
     */
1183
    public function getTagStackCount()
1184
    {
1185
        return count($this->_tag_stack);
1186
    }
1187
1188
    /**
1189
     * @param $lexerPreg
1190
     *
1191
     * @return mixed
1192
     */
1193
    public function replaceDelimiter($lexerPreg)
1194
    {
1195
        return str_replace(
1196
            array('SMARTYldel', 'SMARTYliteral', 'SMARTYrdel', 'SMARTYautoliteral', 'SMARTYal'),
1197
            array(
1198
                $this->ldelPreg, $this->literalPreg, $this->rdelPreg,
1199
                $this->smarty->getAutoLiteral() ? '{1,}' : '{9}',
1200
                $this->smarty->getAutoLiteral() ? '' : '\\s*'
1201
            ),
1202
            $lexerPreg
1203
        );
1204
    }
1205
1206
    /**
1207
     * Build lexer regular expressions for left and right delimiter and user defined literals
1208
     */
1209
    public function initDelimiterPreg()
1210
    {
1211
        $ldel = $this->smarty->getLeftDelimiter();
1212
        $this->ldelLength = strlen($ldel);
1213
        $this->ldelPreg = '';
1214
        foreach (str_split($ldel, 1) as $chr) {
1215
            $this->ldelPreg .= '[' . preg_quote($chr,'/') . ']';
1216
        }
1217
        $rdel = $this->smarty->getRightDelimiter();
1218
        $this->rdelLength = strlen($rdel);
1219
        $this->rdelPreg = '';
1220
        foreach (str_split($rdel, 1) as $chr) {
1221
            $this->rdelPreg .= '[' . preg_quote($chr,'/') . ']';
1222
        }
1223
        $literals = $this->smarty->getLiterals();
1224
        if (!empty($literals)) {
1225
            foreach ($literals as $key => $literal) {
1226
                $literalPreg = '';
1227
                foreach (str_split($literal, 1) as $chr) {
1228
                    $literalPreg .= '[' . preg_quote($chr,'/') . ']';
1229
                }
1230
                $literals[ $key ] = $literalPreg;
1231
            }
1232
            $this->literalPreg = '|' . implode('|', $literals);
1233
        } else {
1234
            $this->literalPreg = '';
1235
        }
1236
    }
1237
1238
    /**
1239
     *  leave double quoted string
1240
     *  - throw exception if block in string was not closed
1241
     *
1242
     * @throws \SmartyCompilerException
1243
     */
1244
    public function leaveDoubleQuote()
1245
    {
1246
        if (array_pop($this->_tag_stack_count) !== $this->getTagStackCount()) {
1247
            $tag = $this->getOpenBlockTag();
1248
            $this->trigger_template_error(
1249
                "unclosed '{{$tag}}' in doubled quoted string",
1250
                null,
1251
                true
1252
            );
1253
        }
1254
    }
1255
1256
    /**
1257
     * Get left delimiter preg
1258
     *
1259
     * @return string
1260
     */
1261
    public function getLdelPreg()
1262
    {
1263
        return $this->ldelPreg;
1264
    }
1265
1266
    /**
1267
     * Get right delimiter preg
1268
     *
1269
     * @return string
1270
     */
1271
    public function getRdelPreg()
1272
    {
1273
        return $this->rdelPreg;
1274
    }
1275
1276
    /**
1277
     * Get length of left delimiter
1278
     *
1279
     * @return int
1280
     */
1281
    public function getLdelLength()
1282
    {
1283
        return $this->ldelLength;
1284
    }
1285
1286
    /**
1287
     * Get length of right delimiter
1288
     *
1289
     * @return int
1290
     */
1291
    public function getRdelLength()
1292
    {
1293
        return $this->rdelLength;
1294
    }
1295
1296
    /**
1297
     * Get name of current open block tag
1298
     *
1299
     * @return string|boolean
1300
     */
1301
    public function getOpenBlockTag()
1302
    {
1303
        $tagCount = $this->getTagStackCount();
1304
        if ($tagCount) {
1305
            return $this->_tag_stack[ $tagCount - 1 ][ 0 ];
1306
        } else {
1307
            return false;
1308
        }
1309
    }
1310
1311
    /**
1312
     * Check if $value contains variable elements
1313
     *
1314
     * @param mixed $value
1315
     *
1316
     * @return bool|int
1317
     */
1318
    public function isVariable($value)
1319
    {
1320
        if (is_string($value)) {
1321
            return preg_match('/[$(]/', $value);
1322
        }
1323
        if (is_bool($value) || is_numeric($value)) {
1324
            return false;
1325
        }
1326
        if (is_array($value)) {
1327
            foreach ($value as $k => $v) {
1328
                if ($this->isVariable($k) || $this->isVariable($v)) {
1329
                    return true;
1330
                }
1331
            }
1332
            return false;
1333
        }
1334
        return false;
1335
    }
1336
1337
    /**
1338
     * Get new prefix variable name
1339
     *
1340
     * @return string
1341
     */
1342
    public function getNewPrefixVariable()
1343
    {
1344
        ++self::$prefixVariableNumber;
1345
        return $this->getPrefixVariable();
1346
    }
1347
1348
    /**
1349
     * Get current prefix variable name
1350
     *
1351
     * @return string
1352
     */
1353
    public function getPrefixVariable()
1354
    {
1355
        return '$_prefixVariable' . self::$prefixVariableNumber;
1356
    }
1357
1358
    /**
1359
     * append  code to prefix buffer
1360
     *
1361
     * @param string $code
1362
     */
1363
    public function appendPrefixCode($code)
1364
    {
1365
        $this->prefix_code[] = $code;
1366
    }
1367
1368
    /**
1369
     * get prefix code string
1370
     *
1371
     * @return string
1372
     */
1373
    public function getPrefixCode()
1374
    {
1375
        $code = '';
1376
        $prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
1377
        $this->prefixCodeStack[] = array();
1378
        foreach ($prefixArray as $c) {
1379
            $code = $this->appendCode($code, $c);
1380
        }
1381
        $this->prefix_code = array();
1382
        return $code;
1383
    }
1384
1385
    /**
1386
     * Save current required plugins
1387
     *
1388
     * @param bool $init if true init required plugins
1389
     */
1390
    public function saveRequiredPlugins($init = false)
1391
    {
1392
        $this->required_plugins_stack[] = $this->required_plugins;
1393
        if ($init) {
1394
            $this->required_plugins = array('compiled' => array(), 'nocache' => array());
1395
        }
1396
    }
1397
1398
    /**
1399
     * Restore required plugins
1400
     */
1401
    public function restoreRequiredPlugins()
1402
    {
1403
        $this->required_plugins = array_pop($this->required_plugins_stack);
1404
    }
1405
1406
    /**
1407
     * Compile code to call Smarty_Internal_Template::_checkPlugins()
1408
     * for required plugins
1409
     *
1410
     * @return string
1411
     */
1412
    public function compileRequiredPlugins()
1413
    {
1414
        $code = $this->compileCheckPlugins($this->required_plugins[ 'compiled' ]);
1415
        if ($this->caching && !empty($this->required_plugins[ 'nocache' ])) {
1416
            $code .= $this->makeNocacheCode($this->compileCheckPlugins($this->required_plugins[ 'nocache' ]));
1417
        }
1418
        return $code;
1419
    }
1420
1421
    /**
1422
     * Compile code to call Smarty_Internal_Template::_checkPlugins
1423
     *   - checks if plugin is callable require otherwise
1424
     *
1425
     * @param $requiredPlugins
1426
     *
1427
     * @return string
1428
     */
1429
    public function compileCheckPlugins($requiredPlugins)
1430
    {
1431
        if (!empty($requiredPlugins)) {
1432
            $plugins = array();
1433
            foreach ($requiredPlugins as $plugin) {
1434
                foreach ($plugin as $data) {
1435
                    $plugins[] = $data;
1436
                }
1437
            }
1438
            return '$_smarty_tpl->_checkPlugins(' . $this->getVarExport($plugins) . ');' . "\n";
1439
        } else {
1440
            return '';
1441
        }
1442
    }
1443
1444
    /**
1445
     * method to compile a Smarty template
1446
     *
1447
     * @param mixed $_content template source
1448
     * @param bool  $isTemplateSource
1449
     *
1450
     * @return bool true if compiling succeeded, false if it failed
1451
     */
1452
    abstract protected function doCompile($_content, $isTemplateSource = false);
1453
1454
    /**
1455
     * Compile Tag
1456
     *
1457
     * @param string $tag       tag name
1458
     * @param array  $args      array with tag attributes
1459
     * @param array  $parameter array with compilation parameter
1460
     *
1461
     * @throws SmartyCompilerException
1462
     * @throws SmartyException
1463
     * @return string compiled code
1464
     */
1465
    private function compileTag2($tag, $args, $parameter)
1466
    {
1467
        $plugin_type = '';
1468
        // $args contains the attributes parsed and compiled by the lexer/parser
1469
        // assume that tag does compile into code, but creates no HTML output
1470
        $this->has_code = true;
1471
        // log tag/attributes
1472
        if (isset($this->smarty->_cache[ 'get_used_tags' ])) {
1473
            $this->template->_cache[ 'used_tags' ][] = array(
1474
                $tag,
1475
                $args
1476
            );
1477
        }
1478
        // check nocache option flag
1479
        foreach ($args as $arg) {
1480
            if (!is_array($arg)) {
1481
                if ($arg === "'nocache'" || $arg === 'nocache') {
1482
                    $this->tag_nocache = true;
1483
                }
1484
            } else {
1485
                foreach ($arg as $k => $v) {
1486
                    if (($k === "'nocache'" || $k === 'nocache') && (trim($v, "'\" ") === 'true')) {
1487
                        $this->tag_nocache = true;
1488
                    }
1489
                }
1490
            }
1491
        }
1492
        // compile the smarty tag (required compile classes to compile the tag are auto loaded)
1493
        if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler($tag, $args, $parameter); of type boolean|string adds the type boolean to the return on line 1508 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1494
            if (isset($this->parent_compiler->tpl_function[ $tag ])
1495
                || (isset($this->template->smarty->ext->_tplFunction)
1496
                    && $this->template->smarty->ext->_tplFunction->getTplFunction($this->template, $tag) !== false)
1497
            ) {
1498
                // template defined by {template} tag
1499
                $args[ '_attr' ][ 'name' ] = "'{$tag}'";
1500
                $_output = $this->callTagCompiler('call', $args, $parameter);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...l', $args, $parameter); of type boolean|string adds the type boolean to the return on line 1508 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1501
            }
1502
        }
1503
        if ($_output !== false) {
1504
            if ($_output !== true) {
1505
                // did we get compiled code
1506
                if ($this->has_code) {
1507
                    // return compiled code
1508
                    return $_output;
1509
                }
1510
            }
1511
            // tag did not produce compiled code
1512
            return null;
1513
        } else {
1514
            // map_named attributes
1515
            if (isset($args[ '_attr' ])) {
1516
                foreach ($args[ '_attr' ] as $key => $attribute) {
1517
                    if (is_array($attribute)) {
1518
                        $args = array_merge($args, $attribute);
1519
                    }
1520
                }
1521
            }
1522
            // not an internal compiler tag
1523
            if (strlen($tag) < 6 || substr($tag, -5) !== 'close') {
1524
                // check if tag is a registered object
1525
                if (isset($this->smarty->registered_objects[ $tag ]) && isset($parameter[ 'object_method' ])) {
1526
                    $method = $parameter[ 'object_method' ];
1527
                    if (!in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])
1528
                        && (empty($this->smarty->registered_objects[ $tag ][ 1 ])
1529
                            || in_array($method, $this->smarty->registered_objects[ $tag ][ 1 ]))
1530
                    ) {
1531
                        return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...ameter, $tag, $method); of type boolean|string adds the type boolean to the return on line 1531 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1532
                    } elseif (in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])) {
1533
                        return $this->callTagCompiler(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...ameter, $tag, $method); of type boolean|string adds the type boolean to the return on line 1533 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1534
                            'private_object_block_function',
1535
                            $args,
1536
                            $parameter,
1537
                            $tag,
1538
                            $method
1539
                        );
1540
                    } else {
1541
                        // throw exception
1542
                        $this->trigger_template_error(
1543
                            'not allowed method "' . $method . '" in registered object "' .
1544
                            $tag . '"',
1545
                            null,
1546
                            true
1547
                        );
1548
                    }
1549
                }
1550
                // check if tag is registered
1551
                foreach (array(
1552
                    Smarty::PLUGIN_COMPILER,
1553
                    Smarty::PLUGIN_FUNCTION,
1554
                    Smarty::PLUGIN_BLOCK,
1555
                ) as $plugin_type) {
1556
                    if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) {
1557
                        // if compiler function plugin call it now
1558
                        if ($plugin_type === Smarty::PLUGIN_COMPILER) {
1559
                            $new_args = array();
1560
                            foreach ($args as $key => $mixed) {
1561
                                if (is_array($mixed)) {
1562
                                    $new_args = array_merge($new_args, $mixed);
1563
                                } else {
1564
                                    $new_args[ $key ] = $mixed;
1565
                                }
1566
                            }
1567
                            if (!$this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 1 ]) {
1568
                                $this->tag_nocache = true;
1569
                            }
1570
                            return call_user_func_array(
1571
                                $this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ],
1572
                                array(
1573
                                    $new_args,
1574
                                    $this
1575
                                )
1576
                            );
1577
                        }
1578
                        // compile registered function or block function
1579
                        if ($plugin_type === Smarty::PLUGIN_FUNCTION || $plugin_type === Smarty::PLUGIN_BLOCK) {
1580
                            return $this->callTagCompiler(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...rgs, $parameter, $tag); of type boolean|string adds the type boolean to the return on line 1580 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1581
                                'private_registered_' . $plugin_type,
1582
                                $args,
1583
                                $parameter,
1584
                                $tag
1585
                            );
1586
                        }
1587
                    }
1588
                }
1589
                // check plugins from plugins folder
1590
                foreach ($this->plugin_search_order as $plugin_type) {
1591
                    if ($plugin_type === Smarty::PLUGIN_COMPILER
1592
                        && $this->smarty->loadPlugin('smarty_compiler_' . $tag)
1593
                        && (!isset($this->smarty->security_policy)
1594
                            || $this->smarty->security_policy->isTrustedTag($tag, $this))
1595
                    ) {
1596
                        $plugin = 'smarty_compiler_' . $tag;
1597
                        if (is_callable($plugin)) {
1598
                            // convert arguments format for old compiler plugins
1599
                            $new_args = array();
1600
                            foreach ($args as $key => $mixed) {
1601
                                if (is_array($mixed)) {
1602
                                    $new_args = array_merge($new_args, $mixed);
1603
                                } else {
1604
                                    $new_args[ $key ] = $mixed;
1605
                                }
1606
                            }
1607
                            return $plugin($new_args, $this->smarty);
1608
                        }
1609
                        if (class_exists($plugin, false)) {
1610
                            $plugin_object = new $plugin;
1611
                            if (method_exists($plugin_object, 'compile')) {
1612
                                return $plugin_object->compile($args, $this);
1613
                            }
1614
                        }
1615
                        throw new SmartyException("Plugin '{$tag}' not callable");
1616
                    } else {
1617
                        if ($function = $this->getPlugin($tag, $plugin_type)) {
1618
                            if (!isset($this->smarty->security_policy)
1619
                                || $this->smarty->security_policy->isTrustedTag($tag, $this)
1620
                            ) {
1621
                                return $this->callTagCompiler(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...eter, $tag, $function); of type boolean|string adds the type boolean to the return on line 1621 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1622
                                    'private_' . $plugin_type . '_plugin',
1623
                                    $args,
1624
                                    $parameter,
1625
                                    $tag,
1626
                                    $function
1627
                                );
1628
                            }
1629
                        }
1630
                    }
1631
                }
1632
                if (is_callable($this->smarty->default_plugin_handler_func)) {
1633
                    $found = false;
1634
                    // look for already resolved tags
1635
                    foreach ($this->plugin_search_order as $plugin_type) {
1636
                        if (isset($this->default_handler_plugins[ $plugin_type ][ $tag ])) {
1637
                            $found = true;
1638
                            break;
1639
                        }
1640
                    }
1641
                    if (!$found) {
1642
                        // call default handler
1643
                        foreach ($this->plugin_search_order as $plugin_type) {
1644
                            if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
1645
                                $found = true;
1646
                                break;
1647
                            }
1648
                        }
1649
                    }
1650
                    if ($found) {
1651
                        // if compiler function plugin call it now
1652
                        if ($plugin_type === Smarty::PLUGIN_COMPILER) {
1653
                            $new_args = array();
1654
                            foreach ($args as $key => $mixed) {
1655
                                if (is_array($mixed)) {
1656
                                    $new_args = array_merge($new_args, $mixed);
1657
                                } else {
1658
                                    $new_args[ $key ] = $mixed;
1659
                                }
1660
                            }
1661
                            return call_user_func_array(
1662
                                $this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ],
1663
                                array(
1664
                                    $new_args,
1665
                                    $this
1666
                                )
1667
                            );
1668
                        } else {
1669
                            return $this->callTagCompiler(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...rgs, $parameter, $tag); of type boolean|string adds the type boolean to the return on line 1669 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1670
                                'private_registered_' . $plugin_type,
1671
                                $args,
1672
                                $parameter,
1673
                                $tag
1674
                            );
1675
                        }
1676
                    }
1677
                }
1678
            } else {
1679
                // compile closing tag of block function
1680
                $base_tag = substr($tag, 0, -5);
1681
                // check if closing tag is a registered object
1682
                if (isset($this->smarty->registered_objects[ $base_tag ]) && isset($parameter[ 'object_method' ])) {
1683
                    $method = $parameter[ 'object_method' ];
1684
                    if (in_array($method, $this->smarty->registered_objects[ $base_tag ][ 3 ])) {
1685
                        return $this->callTagCompiler(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...ameter, $tag, $method); of type boolean|string adds the type boolean to the return on line 1685 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1686
                            'private_object_block_function',
1687
                            $args,
1688
                            $parameter,
1689
                            $tag,
1690
                            $method
1691
                        );
1692
                    } else {
1693
                        // throw exception
1694
                        $this->trigger_template_error(
1695
                            'not allowed closing tag method "' . $method .
1696
                            '" in registered object "' . $base_tag . '"',
1697
                            null,
1698
                            true
1699
                        );
1700
                    }
1701
                }
1702
                // registered block tag ?
1703
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])
1704
                    || isset($this->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])
1705
                ) {
1706
                    return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...rgs, $parameter, $tag); of type boolean|string adds the type boolean to the return on line 1706 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1707
                }
1708
                // registered function tag ?
1709
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) {
1710
                    return $this->callTagCompiler('private_registered_function', $args, $parameter, $tag);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...rgs, $parameter, $tag); of type boolean|string adds the type boolean to the return on line 1710 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1711
                }
1712
                // block plugin?
1713
                if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
1714
                    return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...eter, $tag, $function); of type boolean|string adds the type boolean to the return on line 1714 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1715
                }
1716
                // function plugin?
1717
                if ($function = $this->getPlugin($tag, Smarty::PLUGIN_FUNCTION)) {
1718
                    if (!isset($this->smarty->security_policy)
1719
                        || $this->smarty->security_policy->isTrustedTag($tag, $this)
1720
                    ) {
1721
                        return $this->callTagCompiler('private_function_plugin', $args, $parameter, $tag, $function);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...eter, $tag, $function); of type boolean|string adds the type boolean to the return on line 1721 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
1722
                    }
1723
                }
1724
                // registered compiler plugin ?
1725
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ])) {
1726
                    // if compiler function plugin call it now
1727
                    $args = array();
1728
                    if (!$this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 1 ]) {
1729
                        $this->tag_nocache = true;
1730
                    }
1731
                    return call_user_func_array(
1732
                        $this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ],
1733
                        array(
1734
                            $args,
1735
                            $this
1736
                        )
1737
                    );
1738
                }
1739
                if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
1740
                    $plugin = 'smarty_compiler_' . $tag;
1741
                    if (is_callable($plugin)) {
1742
                        return $plugin($args, $this->smarty);
1743
                    }
1744
                    if (class_exists($plugin, false)) {
1745
                        $plugin_object = new $plugin;
1746
                        if (method_exists($plugin_object, 'compile')) {
1747
                            return $plugin_object->compile($args, $this);
1748
                        }
1749
                    }
1750
                    throw new SmartyException("Plugin '{$tag}' not callable");
1751
                }
1752
            }
1753
            $this->trigger_template_error("unknown tag '{$tag}'", null, true);
1754
        }
1755
    }
1756
}
1757