Completed
Branch master (e379bd)
by Pierre-Henry
33:06
created

compilePHPFunctionCall()   C

Complexity

Conditions 14
Paths 13

Size

Total Lines 46
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 34
nc 13
nop 2
dl 0
loc 46
rs 5.0744
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
/**
4
 * Smarty Internal Plugin Smarty Template Compiler Base
5
 * This file contains the basic classes and methods for compiling Smarty templates with lexer/parser
6
 *
7
 * @package    Smarty
8
 * @subpackage Compiler
9
 * @author     Uwe Tews
10
 */
11
12
/**
13
 * Main abstract compiler class
14
 *
15
 * @package    Smarty
16
 * @subpackage Compiler
17
 *
18
 * @property Smarty_Internal_SmartyTemplateCompiler $prefixCompiledCode  = ''
19
 * @property Smarty_Internal_SmartyTemplateCompiler $postfixCompiledCode = ''
20
 * @method registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false)
21
 * @method unregisterPostCompileCallback($key)
22
 */
23
abstract class Smarty_Internal_TemplateCompilerBase
24
{
25
26
    /**
27
     * Smarty object
28
     *
29
     * @var Smarty
30
     */
31
    public $smarty = null;
32
33
    /**
34
     * Parser object
35
     *
36
     * @var Smarty_Internal_Templateparser
37
     */
38
    public $parser = null;
39
40
    /**
41
     * hash for nocache sections
42
     *
43
     * @var mixed
44
     */
45
    public $nocache_hash = null;
46
47
    /**
48
     * suppress generation of nocache code
49
     *
50
     * @var bool
51
     */
52
    public $suppressNocacheProcessing = false;
53
54
    /**
55
     * compile tag objects cache
56
     *
57
     * @var array
58
     */
59
    static $_tag_objects = array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $_tag_objects.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
60
61
    /**
62
     * tag stack
63
     *
64
     * @var array
65
     */
66
    public $_tag_stack = array();
67
68
    /**
69
     * current template
70
     *
71
     * @var Smarty_Internal_Template
72
     */
73
    public $template = null;
74
75
    /**
76
     * merged included sub template data
77
     *
78
     * @var array
79
     */
80
    public $mergedSubTemplatesData = array();
81
82
    /**
83
     * merged sub template code
84
     *
85
     * @var array
86
     */
87
    public $mergedSubTemplatesCode = array();
88
89
    /**
90
     * collected template properties during compilation
91
     *
92
     * @var array
93
     */
94
    public $templateProperties = array();
95
96
    /**
97
     * source line offset for error messages
98
     *
99
     * @var int
100
     */
101
    public $trace_line_offset = 0;
102
103
    /**
104
     * trace uid
105
     *
106
     * @var string
107
     */
108
    public $trace_uid = '';
109
110
    /**
111
     * trace file path
112
     *
113
     * @var string
114
     */
115
    public $trace_filepath = '';
116
117
    /**
118
     * stack for tracing file and line of nested {block} tags
119
     *
120
     * @var array
121
     */
122
    public $trace_stack = array();
123
124
    /**
125
     * plugins loaded by default plugin handler
126
     *
127
     * @var array
128
     */
129
    public $default_handler_plugins = array();
130
131
    /**
132
     * saved preprocessed modifier list
133
     *
134
     * @var mixed
135
     */
136
    public $default_modifier_list = null;
137
138
    /**
139
     * force compilation of complete template as nocache
140
     *
141
     * @var boolean
142
     */
143
    public $forceNocache = false;
144
145
    /**
146
     * flag if compiled template file shall we written
147
     *
148
     * @var bool
149
     */
150
    public $write_compiled_code = true;
151
152
    /**
153
     * Template functions
154
     *
155
     * @var array
156
     */
157
    public $tpl_function = array();
158
159
    /**
160
     * called sub functions from template function
161
     *
162
     * @var array
163
     */
164
    public $called_functions = array();
165
166
    /**
167
     * compiled template or block function code
168
     *
169
     * @var string
170
     */
171
    public $blockOrFunctionCode = '';
172
173
    /**
174
     * php_handling setting either from Smarty or security
175
     *
176
     * @var int
177
     */
178
    public $php_handling = 0;
179
180
    /**
181
     * flags for used modifier plugins
182
     *
183
     * @var array
184
     */
185
    public $modifier_plugins = array();
186
187
    /**
188
     * type of already compiled modifier
189
     *
190
     * @var array
191
     */
192
    public $known_modifier_type = array();
193
194
    /**
195
     * parent compiler object for merged subtemplates and template functions
196
     *
197
     * @var Smarty_Internal_TemplateCompilerBase
198
     */
199
    public $parent_compiler = null;
200
201
    /**
202
     * Flag true when compiling nocache section
203
     *
204
     * @var bool
205
     */
206
    public $nocache = false;
207
208
    /**
209
     * Flag true when tag is compiled as nocache
210
     *
211
     * @var bool
212
     */
213
    public $tag_nocache = false;
214
215
    /**
216
     * Compiled tag prefix code
217
     *
218
     * @var array
219
     */
220
    public $prefix_code = array();
221
222
    /**
223
     * Prefix code  stack
224
     *
225
     * @var array
226
     */
227
    public $prefixCodeStack = array();
228
229
    /**
230
     * Tag has compiled code
231
     *
232
     * @var bool
233
     */
234
    public $has_code = false;
235
236
    /**
237
     * A variable string was compiled
238
     *
239
     * @var bool
240
     */
241
    public $has_variable_string = false;
242
243
    /**
244
     * Tag creates output
245
     *
246
     * @var bool
247
     */
248
    public $has_output = false;
249
250
    /**
251
     * Stack for {setfilter} {/setfilter}
252
     *
253
     * @var array
254
     */
255
    public $variable_filter_stack = array();
256
257
    /**
258
     * variable filters for {setfilter} {/setfilter}
259
     *
260
     * @var array
261
     */
262
    public $variable_filters = array();
263
264
    /**
265
     * Nesting count of looping tags like {foreach}, {for}, {section}, {while}
266
     *
267
     * @var int
268
     */
269
    public $loopNesting = 0;
270
271
    /**
272
     * Strip preg pattern
273
     *
274
     * @var string
275
     */
276
    public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';
277
278
    /**
279
     * plugin search order
280
     *
281
     * @var array
282
     */
283
    public $plugin_search_order = array('function', 'block', 'compiler', 'class');
284
285
    /**
286
     * General storage area for tag compiler plugins
287
     *
288
     * @var array
289
     */
290
    public $_cache = array();
291
292
    /**
293
     * counter for prefix variable number
294
     *
295
     * @var int
296
     */
297
    public static $prefixVariableNumber = 0;
298
299
    /**
300
     * method to compile a Smarty template
301
     *
302
     * @param mixed $_content template source
303
     * @param bool  $isTemplateSource
304
     *
305
     * @return bool true if compiling succeeded, false if it failed
306
     */
307
    abstract protected function doCompile($_content, $isTemplateSource = false);
308
309
    /**
310
     * Initialize compiler
311
     *
312
     * @param Smarty $smarty global instance
313
     */
314
    public function __construct(Smarty $smarty)
315
    {
316
        $this->smarty = $smarty;
317
        $this->nocache_hash = str_replace(array('.', ','), '_', uniqid(rand(), true));
318
    }
319
320
    /**
321
     * Method to compile a Smarty template
322
     *
323
     * @param  Smarty_Internal_Template                 $template template object to compile
324
     * @param  bool                                     $nocache  true is shall be compiled in nocache mode
325
     * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler
326
     *
327
     * @return bool true if compiling succeeded, false if it failed
328
     * @throws \Exception
329
     */
330
    public function compileTemplate(Smarty_Internal_Template $template, $nocache = null,
331
                                    Smarty_Internal_TemplateCompilerBase $parent_compiler = null)
332
    {
333
        // get code frame of compiled template
334
        $_compiled_code = $template->smarty->ext->_codeFrame->create($template,
335
                                                                     $this->compileTemplateSource($template, $nocache,
336
                                                                                                  $parent_compiler),
337
                                                                     $this->postFilter($this->blockOrFunctionCode) .
338
                                                                     join('', $this->mergedSubTemplatesCode), false,
339
                                                                     $this);
340
        return $_compiled_code;
341
    }
342
343
    /**
344
     * Compile template source and run optional post filter
345
     *
346
     * @param \Smarty_Internal_Template             $template
347
     * @param null|bool                             $nocache flag if template must be compiled in nocache mode
348
     * @param \Smarty_Internal_TemplateCompilerBase $parent_compiler
349
     *
350
     * @return string
351
     * @throws \Exception
352
     */
353
    public function compileTemplateSource(Smarty_Internal_Template $template, $nocache = null,
354
                                          Smarty_Internal_TemplateCompilerBase $parent_compiler = null)
355
    {
356
        try {
357
            // save template object in compiler class
358
            $this->template = $template;
359
            if (property_exists($this->template->smarty, 'plugin_search_order')) {
360
                $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...
361
            }
362
            if ($this->smarty->debugging) {
363
                if (!isset($this->smarty->_debug)) {
364
                    $this->smarty->_debug = new Smarty_Internal_Debug();
365
                }
366
                $this->smarty->_debug->start_compile($this->template);
367
            }
368
            if (isset($this->template->smarty->security_policy)) {
369
                $this->php_handling = $this->template->smarty->security_policy->php_handling;
370
            } else {
371
                $this->php_handling = $this->template->smarty->php_handling;
372
            }
373
            $this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
374
            $nocache = isset($nocache) ? $nocache : false;
375
            if (empty($template->compiled->nocache_hash)) {
376
                $template->compiled->nocache_hash = $this->nocache_hash;
377
            } else {
378
                $this->nocache_hash = $template->compiled->nocache_hash;
379
            }
380
            // flag for nocache sections
381
            $this->nocache = $nocache;
382
            $this->tag_nocache = false;
383
            // reset has nocache code flag
384
            $this->template->compiled->has_nocache_code = false;
385
            $this->has_variable_string = false;
386
            $this->prefix_code = array();
387
            // add file dependency
388
            if ($this->smarty->merge_compiled_includes || $this->template->source->handler->checkTimestamps()) {
389
                $this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] =
390
                    array($this->template->source->filepath, $this->template->source->getTimeStamp(),
391
                          $this->template->source->type,);
392
            }
393
            $this->smarty->_current_file = $this->template->source->filepath;
394
            // get template source
395
            if (!empty($this->template->source->components)) {
396
                // we have array of inheritance templates by extends: resource
397
                // generate corresponding source code sequence
398
                $_content =
399
                    Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template->source->components);
400
            } else {
401
                // get template source
402
                $_content = $this->template->source->getContent();
403
            }
404
            $_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...
405
        }
406
        catch (Exception $e) {
407
            if ($this->smarty->debugging) {
408
                $this->smarty->_debug->end_compile($this->template);
409
            }
410
            $this->_tag_stack = array();
411
            // free memory
412
            $this->parent_compiler = null;
413
            $this->template = null;
414
            $this->parser = null;
415
            throw $e;
416
        }
417
        if ($this->smarty->debugging) {
418
            $this->smarty->_debug->end_compile($this->template);
419
        }
420
        $this->parent_compiler = null;
421
        $this->parser = null;
422
        return $_compiled_code;
423
    }
424
425
    /**
426
     * Optionally process compiled code by post filter
427
     *
428
     * @param string $code compiled code
429
     *
430
     * @return string
431
     * @throws \SmartyException
432
     */
433
    public function postFilter($code)
434
    {
435
        // run post filter if on code
436
        if (!empty($code) &&
437
            (isset($this->smarty->autoload_filters[ 'post' ]) || isset($this->smarty->registered_filters[ 'post' ]))
438
        ) {
439
            return $this->smarty->ext->_filterHandler->runFilter('post', $code, $this->template);
440
        } else {
441
            return $code;
442
        }
443
    }
444
445
    /**
446
     * Run optional prefilter
447
     *
448
     * @param string $_content template source
449
     *
450
     * @return string
451
     * @throws \SmartyException
452
     */
453
    public function preFilter($_content)
454
    {
455
        // run pre filter if required
456
        if ($_content != '' &&
457
            ((isset($this->smarty->autoload_filters[ 'pre' ]) || isset($this->smarty->registered_filters[ 'pre' ])))
458
        ) {
459
            return $this->smarty->ext->_filterHandler->runFilter('pre', $_content, $this->template);
460
        } else {
461
            return $_content;
462
        }
463
    }
464
465
    /**
466
     * Compile Tag
467
     * This is a call back from the lexer/parser
468
     *
469
     * Save current prefix code
470
     * Compile tag
471
     * Merge tag prefix code with saved one
472
     * (required nested tags in attributes)
473
     *
474
     * @param  string $tag       tag name
475
     * @param  array  $args      array with tag attributes
476
     * @param  array  $parameter array with compilation parameter
477
     *
478
     * @throws SmartyCompilerException
479
     * @throws SmartyException
480
     * @return string compiled code
481
     */
482
    public function compileTag($tag, $args, $parameter = array())
483
    {
484
        $this->prefixCodeStack[] = $this->prefix_code;
485
        $this->prefix_code = array();
486
        $result = $this->compileTag2($tag, $args, $parameter);
487
        $this->prefix_code = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
488
        return $result;
489
    }
490
491
    /**
492
     * Compile Tag
493
     *
494
     * @param  string $tag       tag name
495
     * @param  array  $args      array with tag attributes
496
     * @param  array  $parameter array with compilation parameter
497
     *
498
     * @throws SmartyCompilerException
499
     * @throws SmartyException
500
     * @return string compiled code
501
     */
502
    private function compileTag2($tag, $args, $parameter)
503
    {
504
        $plugin_type = '';
505
        // $args contains the attributes parsed and compiled by the lexer/parser
506
        // assume that tag does compile into code, but creates no HTML output
507
        $this->has_code = true;
508
        $this->has_output = false;
509
        // log tag/attributes
510
        if (isset($this->smarty->_cache[ 'get_used_tags' ])) {
511
            $this->template->_cache[ 'used_tags' ][] = array($tag, $args);
512
        }
513
        // check nocache option flag
514
        foreach ($args as $arg) {
515
            if (!is_array($arg)) {
516
                if ($arg === "'nocache'" || $arg === 'nocache') {
517
                    $this->tag_nocache = true;
518
                }
519
            } else {
520
                foreach ($arg as $k => $v) {
521
                    if (($k === "'nocache'" || $k === 'nocache') && (trim($v, "'\" ") == 'true')) {
522
                        $this->tag_nocache = true;
523
                    }
524
                }
525
            }
526
        }
527
        // compile the smarty tag (required compile classes to compile the tag are auto loaded)
528
        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 string|boolean adds the type boolean to the return on line 545 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
529
            if (isset($this->parent_compiler->tpl_function[ $tag ]) ||
530
                (isset ($this->template->smarty->ext->_tplFunction) && $this->template->smarty->ext->_tplFunction->getTplFunction($this->template, $tag) !== false)) {
531
                // template defined by {template} tag
532
                $args[ '_attr' ][ 'name' ] = "'" . $tag . "'";
533
                $_output = $this->callTagCompiler('call', $args, $parameter);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...l', $args, $parameter); of type string|boolean adds the type boolean to the return on line 545 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
534
            }
535
        }
536
        if ($_output !== false) {
537
            if ($_output !== true) {
538
                // did we get compiled code
539
                if ($this->has_code) {
540
                    // Does it create output?
541
                    if ($this->has_output) {
542
                        $_output .= "\n";
543
                    }
544
                    // return compiled code
545
                    return $_output;
546
                }
547
            }
548
            // tag did not produce compiled code
549
            return null;
550
        } else {
551
            // map_named attributes
552
            if (isset($args[ '_attr' ])) {
553
                foreach ($args[ '_attr' ] as $key => $attribute) {
554
                    if (is_array($attribute)) {
555
                        $args = array_merge($args, $attribute);
556
                    }
557
                }
558
            }
559
            // not an internal compiler tag
560
            if (strlen($tag) < 6 || substr($tag, - 5) != 'close') {
561
                // check if tag is a registered object
562
                if (isset($this->smarty->registered_objects[ $tag ]) && isset($parameter[ 'object_method' ])) {
563
                    $method = $parameter[ 'object_method' ];
564
                    if (!in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ]) &&
565
                        (empty($this->smarty->registered_objects[ $tag ][ 1 ]) ||
566
                         in_array($method, $this->smarty->registered_objects[ $tag ][ 1 ]))
567
                    ) {
568
                        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 string|boolean adds the type boolean to the return on line 568 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
569
                    } elseif (in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])) {
570
                        return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag,
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...ameter, $tag, $method); of type string|boolean adds the type boolean to the return on line 570 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
571
                                                      $method);
572
                    } else {
573
                        // throw exception
574
                        $this->trigger_template_error('not allowed method "' . $method . '" in registered object "' .
575
                                                      $tag . '"', null, true);
576
                    }
577
                }
578
                // check if tag is registered
579
                foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK,) as $plugin_type)
580
                {
581
                    if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) {
582
                        // if compiler function plugin call it now
583
                        if ($plugin_type == Smarty::PLUGIN_COMPILER) {
584
                            $new_args = array();
585
                            foreach ($args as $key => $mixed) {
586
                                if (is_array($mixed)) {
587
                                    $new_args = array_merge($new_args, $mixed);
588
                                } else {
589
                                    $new_args[ $key ] = $mixed;
590
                                }
591
                            }
592
                            if (!$this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 1 ]) {
593
                                $this->tag_nocache = true;
594
                            }
595
                            return call_user_func_array($this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ],
596
                                                        array($new_args, $this));
597
                        }
598
                        // compile registered function or block function
599
                        if ($plugin_type == Smarty::PLUGIN_FUNCTION || $plugin_type == Smarty::PLUGIN_BLOCK) {
600
                            return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter,
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...rgs, $parameter, $tag); of type string|boolean adds the type boolean to the return on line 600 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
601
                                                          $tag);
602
                        }
603
                    }
604
                }
605
                // check plugins from plugins folder
606
                foreach ($this->plugin_search_order as $plugin_type) {
607
                    if ($plugin_type == Smarty::PLUGIN_COMPILER &&
608
                        $this->smarty->loadPlugin('smarty_compiler_' . $tag) &&
609
                        (!isset($this->smarty->security_policy) ||
610
                         $this->smarty->security_policy->isTrustedTag($tag, $this))
611
                    ) {
612
                        $plugin = 'smarty_compiler_' . $tag;
613
                        if (is_callable($plugin)) {
614
                            // convert arguments format for old compiler plugins
615
                            $new_args = array();
616
                            foreach ($args as $key => $mixed) {
617
                                if (is_array($mixed)) {
618
                                    $new_args = array_merge($new_args, $mixed);
619
                                } else {
620
                                    $new_args[ $key ] = $mixed;
621
                                }
622
                            }
623
624
                            return $plugin($new_args, $this->smarty);
625
                        }
626
                        if (class_exists($plugin, false)) {
627
                            $plugin_object = new $plugin;
628
                            if (method_exists($plugin_object, 'compile')) {
629
                                return $plugin_object->compile($args, $this);
630
                            }
631
                        }
632
                        throw new SmartyException("Plugin \"{$tag}\" not callable");
633
                    } else {
634
                        if ($function = $this->getPlugin($tag, $plugin_type)) {
635
                            if (!isset($this->smarty->security_policy) ||
636
                                $this->smarty->security_policy->isTrustedTag($tag, $this)
637
                            ) {
638
                                return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter,
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...eter, $tag, $function); of type string|boolean adds the type boolean to the return on line 638 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
639
                                                              $tag, $function);
640
                            }
641
                        }
642
                    }
643
                }
644
                if (is_callable($this->smarty->default_plugin_handler_func)) {
645
                    $found = false;
646
                    // look for already resolved tags
647
                    foreach ($this->plugin_search_order as $plugin_type) {
648
                        if (isset($this->default_handler_plugins[ $plugin_type ][ $tag ])) {
649
                            $found = true;
650
                            break;
651
                        }
652
                    }
653
                    if (!$found) {
654
                        // call default handler
655
                        foreach ($this->plugin_search_order as $plugin_type) {
656
                            if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
657
                                $found = true;
658
                                break;
659
                            }
660
                        }
661
                    }
662
                    if ($found) {
663
                        // if compiler function plugin call it now
664
                        if ($plugin_type == Smarty::PLUGIN_COMPILER) {
665
                            $new_args = array();
666
                            foreach ($args as $mixed) {
667
                                $new_args = array_merge($new_args, $mixed);
668
                            }
669
                            return call_user_func_array($this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ],
670
                                                        array($new_args, $this));
671
                        } else {
672
                            return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter,
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...rgs, $parameter, $tag); of type string|boolean adds the type boolean to the return on line 672 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
673
                                                          $tag);
674
                        }
675
                    }
676
                }
677
            } else {
678
                // compile closing tag of block function
679
                $base_tag = substr($tag, 0, - 5);
680
                // check if closing tag is a registered object
681
                if (isset($this->smarty->registered_objects[ $base_tag ]) && isset($parameter[ 'object_method' ])) {
682
                    $method = $parameter[ 'object_method' ];
683
                    if (in_array($method, $this->smarty->registered_objects[ $base_tag ][ 3 ])) {
684
                        return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag,
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->callTagCompiler('...ameter, $tag, $method); of type string|boolean adds the type boolean to the return on line 684 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
685
                                                      $method);
686
                    } else {
687
                        // throw exception
688
                        $this->trigger_template_error('not allowed closing tag method "' . $method .
689
                                                      '" in registered object "' . $base_tag . '"', null, true);
690
                    }
691
                }
692
                // registered block tag ?
693
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ]) ||
694
                    isset($this->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])
695
                ) {
696
                    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 string|boolean adds the type boolean to the return on line 696 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
697
                }
698
                // registered function tag ?
699
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) {
700
                    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 string|boolean adds the type boolean to the return on line 700 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
701
                }
702
                // block plugin?
703
                if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
704
                    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 string|boolean adds the type boolean to the return on line 704 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
705
                }
706
                // function plugin?
707
                if ($function = $this->getPlugin($tag, Smarty::PLUGIN_FUNCTION)) {
708
                    if (!isset($this->smarty->security_policy) ||
709
                        $this->smarty->security_policy->isTrustedTag($tag, $this)
710
                    ) {
711
                        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 string|boolean adds the type boolean to the return on line 711 which is incompatible with the return type documented by Smarty_Internal_TemplateCompilerBase::compileTag2 of type string.
Loading history...
712
                    }
713
                }
714
                // registered compiler plugin ?
715
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ])) {
716
                    // if compiler function plugin call it now
717
                    $args = array();
718
                    if (!$this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 1 ]) {
719
                        $this->tag_nocache = true;
720
                    }
721
                    return call_user_func_array($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ],
722
                                                array($args, $this));
723
                }
724
                if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
725
                    $plugin = 'smarty_compiler_' . $tag;
726
                    if (is_callable($plugin)) {
727
                        return $plugin($args, $this->smarty);
728
                    }
729
                    if (class_exists($plugin, false)) {
730
                        $plugin_object = new $plugin;
731
                        if (method_exists($plugin_object, 'compile')) {
732
                            return $plugin_object->compile($args, $this);
733
                        }
734
                    }
735
                    throw new SmartyException("Plugin \"{$tag}\" not callable");
736
                }
737
            }
738
            $this->trigger_template_error("unknown tag \"" . $tag . "\"", null, true);
739
        }
740
    }
741
742
    /**
743
     * compile variable
744
     *
745
     * @param string $variable
746
     *
747
     * @return string
748
     */
749
    public function compileVariable($variable)
750
    {
751
        if (strpos($variable, '(') == 0) {
752
            // not a variable variable
753
            $var = trim($variable, '\'');
754
            $this->tag_nocache = $this->tag_nocache |
755
                                 $this->template->ext->getTemplateVars->_getVariable($this->template, $var, null, true,
756
                                                                                     false)->nocache;
757
            // 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...
758
        }
759
        return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';
760
    }
761
762
    /**
763
     * compile config variable
764
     *
765
     * @param string $variable
766
     *
767
     * @return string
768
     */
769
    public function compileConfigVariable($variable)
770
    {
771
        // 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...
772
        return '$_smarty_tpl->smarty->ext->configLoad->_getConfigVariable($_smarty_tpl, ' . $variable . ')';
773
    }
774
775
    /**
776
     * compile PHP function call
777
     *
778
     * @param string       $name
779
     * @param        array $parameter
780
     *
781
     * @return string
782
     */
783
    public function compilePHPFunctionCall($name, $parameter)
784
    {
785
        if (!$this->smarty->security_policy || $this->smarty->security_policy->isTrustedPhpFunction($name, $this)) {
786
            if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0 ||
787
                strcasecmp($name, 'array') === 0 || is_callable($name)
788
            ) {
789
                $func_name = strtolower($name);
790
                $par = implode(',', $parameter);
791
                $parHasFuction = strpos($par, '(') !== false;
792
                if ($func_name == 'isset') {
793
                    if (count($parameter) == 0) {
794
                        $this->trigger_template_error('Illegal number of paramer in "isset()"');
795
                    }
796
                    if ($parHasFuction) {
797
                        $prefixVar = $this->getNewPrefixVariable();
798
                        $this->appendPrefixCode("<?php $prefixVar" . '=' . $par . ';?>');
799
                        $isset_par = $prefixVar;
800
                    } else {
801
                        $isset_par = str_replace("')->value", "',null,true,false)->value", $par);
802
                    }
803
                    return $name . "(" . $isset_par . ")";
804
                } elseif (in_array($func_name, array('empty', 'reset', 'current', 'end', 'prev', 'next'))) {
805
                    if (count($parameter) != 1) {
806
                        $this->trigger_template_error('Illegal number of paramer in "empty()"');
807
                    }
808
                    if ($func_name == 'empty') {
809
                        if ($parHasFuction) {
810
                            $prefixVar = $this->getNewPrefixVariable();
811
                            $this->appendPrefixCode("<?php $prefixVar" . '=' . $par . ';?>');
812
813
                            return $func_name . '(' . $prefixVar . ')';
814
                        } else {
815
                            return $func_name . '(' .
816
                                   str_replace("')->value", "',null,true,false)->value", $parameter[ 0 ]) . ')';
817
                        }
818
                    } else {
819
                        return $func_name . '(' . $parameter[ 0 ] . ')';
820
                    }
821
                } else {
822
                    return $name . "(" . implode(',', $parameter) . ")";
823
                }
824
            } else {
825
                $this->trigger_template_error("unknown function \"" . $name . "\"");
826
            }
827
        }
828
    }
829
830
    /**
831
     * This method is called from parser to process a text content section
832
     * - remove text from inheritance child templates as they may generate output
833
     * - strip text if strip is enabled
834
     *
835
     * @param string $text
836
     *
837
     * @return null|\Smarty_Internal_ParseTree_Text
838
     */
839
    public function processText($text)
840
    {
841
        if ((string) $text != '') {
842
            $store = array();
843
            $_store = 0;
844
            if ($this->parser->strip) {
845
                if (strpos($text, '<') !== false) {
846
                    // capture html elements not to be messed with
847
                    $_offset = 0;
848
                    if (preg_match_all('#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
849
                                       $text, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
850
                        foreach ($matches as $match) {
851
                            $store[] = $match[ 0 ][ 0 ];
852
                            $_length = strlen($match[ 0 ][ 0 ]);
853
                            $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
854
                            $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
855
856
                            $_offset += $_length - strlen($replace);
857
                            $_store ++;
858
                        }
859
                    }
860
                    $expressions = array(// replace multiple spaces between tags by a single space
861
                                         '#(:SMARTY@!@|>)[\040\011]+(?=@!@SMARTY:|<)#s' => '\1 \2',
862
                                         // remove newline between tags
863
                                         '#(:SMARTY@!@|>)[\040\011]*[\n]\s*(?=@!@SMARTY:|<)#s' => '\1\2',
864
                                         // remove multiple spaces between attributes (but not in attribute values!)
865
                                         '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
866
                                         '#>[\040\011]+$#Ss' => '> ', '#>[\040\011]*[\n]\s*$#Ss' => '>',
867
                                         $this->stripRegEx => '',);
868
869
                    $text = preg_replace(array_keys($expressions), array_values($expressions), $text);
870
                    $_offset = 0;
871
                    if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $text, $matches,
872
                                       PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
873
                        foreach ($matches as $match) {
874
                            $_length = strlen($match[ 0 ][ 0 ]);
875
                            $replace = $store[ $match[ 1 ][ 0 ] ];
876
                            $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
877
878
                            $_offset += strlen($replace) - $_length;
879
                            $_store ++;
880
                        }
881
                    }
882
                } else {
883
                    $text = preg_replace($this->stripRegEx, '', $text);
884
                }
885
            }
886
            return new Smarty_Internal_ParseTree_Text($text);
887
        }
888
        return null;
889
    }
890
891
    /**
892
     * lazy loads internal compile plugin for tag and calls the compile method
893
     * compile objects cached for reuse.
894
     * class name format:  Smarty_Internal_Compile_TagName
895
     * plugin filename format: Smarty_Internal_TagName.php
896
     *
897
     * @param  string $tag    tag name
898
     * @param  array  $args   list of tag attributes
899
     * @param  mixed  $param1 optional parameter
900
     * @param  mixed  $param2 optional parameter
901
     * @param  mixed  $param3 optional parameter
902
     *
903
     * @return string|bool compiled code or false
904
     */
905
    public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
906
    {
907
        $tagCompiler = $this->getTagCompiler($tag);
908
        // compile this tag
909
        return $tagCompiler === false ? false : $tagCompiler->compile($args, $this, $param1, $param2, $param3);
910
    }
911
912
    /**
913
     * lazy loads internal compile plugin for tag compile objects cached for reuse.
914
     *
915
     * class name format:  Smarty_Internal_Compile_TagName
916
     * plugin filename format: Smarty_Internal_TagName.php
917
     *
918
     * @param  string $tag tag name
919
     *
920
     * @return Smarty_Internal_CompileBase|bool tag compiler object or false if not found
921
     */
922
    public function getTagCompiler($tag)
923
    {
924
        // re-use object if already exists
925
        if (!isset(self::$_tag_objects[ $tag ])) {
926
            // lazy load internal compiler plugin
927
            $_tag = explode('_', $tag);
928
            $_tag = array_map('ucfirst', $_tag);
929
            $class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);
930
            if (class_exists($class_name) &&
931
                (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))
932
            ) {
933
                self::$_tag_objects[ $tag ] = new $class_name;
934
            } else {
935
                self::$_tag_objects[ $tag ] = false;
936
            }
937
        }
938
        return self::$_tag_objects[ $tag ];
939
    }
940
941
    /**
942
     * Check for plugins and return function name
943
     *
944
     * @param         $plugin_name
945
     * @param  string $plugin_type type of plugin
946
     *
947
     * @return string call name of function
948
     */
949
    public function getPlugin($plugin_name, $plugin_type)
950
    {
951
        $function = null;
952
        if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
953
            if (isset($this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
954
                $function =
955
                    $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
956
            } elseif (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
957
                $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ] =
958
                    $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ];
959
                $function =
960
                    $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
961
            }
962
        } else {
963
            if (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
964
                $function =
965
                    $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
966
            } elseif (isset($this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
967
                $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ] =
968
                    $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ];
969
                $function =
970
                    $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
971
            }
972
        }
973
        if (isset($function)) {
974
            if ($plugin_type == 'modifier') {
975
                $this->modifier_plugins[ $plugin_name ] = true;
976
            }
977
978
            return $function;
979
        }
980
        // loop through plugin dirs and find the plugin
981
        $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
982
        $file = $this->smarty->loadPlugin($function, false);
983
984
        if (is_string($file)) {
985
            if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
986
                $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
987
                    $file;
988
                $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
989
                    $function;
990
            } else {
991
                $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
992
                    $file;
993
                $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
994
                    $function;
995
            }
996
            if ($plugin_type == 'modifier') {
997
                $this->modifier_plugins[ $plugin_name ] = true;
998
            }
999
1000
            return $function;
1001
        }
1002
        if (is_callable($function)) {
1003
            // plugin function is defined in the script
1004
            return $function;
1005
        }
1006
1007
        return false;
1008
    }
1009
1010
    /**
1011
     * Check for plugins by default plugin handler
1012
     *
1013
     * @param  string $tag         name of tag
1014
     * @param  string $plugin_type type of plugin
1015
     *
1016
     * @return boolean true if found
1017
     */
1018
    public function getPluginFromDefaultHandler($tag, $plugin_type)
1019
    {
1020
        $callback = null;
1021
        $script = null;
1022
        $cacheable = true;
1023
        $result = call_user_func_array($this->smarty->default_plugin_handler_func,
1024
                                       array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable,));
1025
        if ($result) {
1026
            $this->tag_nocache = $this->tag_nocache || !$cacheable;
1027
            if ($script !== null) {
1028
                if (is_file($script)) {
1029
                    if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
1030
                        $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'file' ] =
1031
                            $script;
1032
                        $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'function' ] =
1033
                            $callback;
1034
                    } else {
1035
                        $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'file' ] =
1036
                            $script;
1037
                        $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'function' ] =
1038
                            $callback;
1039
                    }
1040
                    require_once $script;
1041
                } else {
1042
                    $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found");
1043
                }
1044
            }
1045
            if (is_callable($callback)) {
1046
                $this->default_handler_plugins[ $plugin_type ][ $tag ] = array($callback, true, array());
1047
1048
                return true;
1049
            } else {
1050
                $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable");
1051
            }
1052
        }
1053
1054
        return false;
1055
    }
1056
1057
    /**
1058
     * Append code segments and remove unneeded ?> <?php transitions
1059
     *
1060
     * @param string $left
1061
     * @param string $right
1062
     *
1063
     * @return string
1064
     */
1065
    public function appendCode($left, $right)
1066
    {
1067
        if (preg_match('/\s*\?>\s*$/', $left) && preg_match('/^\s*<\?php\s+/', $right)) {
1068
            $left = preg_replace('/\s*\?>\s*$/', "\n", $left);
1069
            $left .= preg_replace('/^\s*<\?php\s+/', '', $right);
1070
        } else {
1071
            $left .= $right;
1072
        }
1073
        return $left;
1074
    }
1075
1076
    /**
1077
     * Inject inline code for nocache template sections
1078
     * This method gets the content of each template element from the parser.
1079
     * If the content is compiled code and it should be not cached the code is injected
1080
     * into the rendered output.
1081
     *
1082
     * @param  string  $content content of template element
1083
     * @param  boolean $is_code true if content is compiled code
1084
     *
1085
     * @return string  content
1086
     */
1087
    public function processNocacheCode($content, $is_code)
1088
    {
1089
        // If the template is not evaluated and we have a nocache section and or a nocache tag
1090
        if ($is_code && !empty($content)) {
1091
            // generate replacement code
1092
            if ((!($this->template->source->handler->recompiled) || $this->forceNocache) && $this->template->caching &&
1093
                !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache)
1094
            ) {
1095
                $this->template->compiled->has_nocache_code = true;
1096
                $_output = addcslashes($content, '\'\\');
1097
                $_output = str_replace("^#^", "'", $_output);
1098
                $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output .
1099
                           "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
1100
                // make sure we include modifier plugins for nocache code
1101
                foreach ($this->modifier_plugins as $plugin_name => $dummy) {
1102
                    if (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ])) {
1103
                        $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ 'modifier' ] =
1104
                            $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ];
1105
                    }
1106
                }
1107
            } else {
1108
                $_output = $content;
1109
            }
1110
        } else {
1111
            $_output = $content;
1112
        }
1113
        $this->modifier_plugins = array();
1114
        $this->suppressNocacheProcessing = false;
1115
        $this->tag_nocache = false;
1116
1117
        return $_output;
1118
    }
1119
1120
    /**
1121
     * Get Id
1122
     *
1123
     * @param string $input
1124
     *
1125
     * @return bool|string
1126
     */
1127
    public function getId($input)
1128
    {
1129
        if (preg_match('~^([\'"]*)([0-9]*[a-zA-Z_]\w*)\1$~', $input, $match)) {
1130
            return $match[ 2 ];
1131
        }
1132
        return false;
1133
    }
1134
1135
    /**
1136
     * Get variable name from string
1137
     *
1138
     * @param string $input
1139
     *
1140
     * @return bool|string
1141
     */
1142
    public function getVariableName($input)
1143
    {
1144
        if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) {
1145
            return $match[ 1 ];
1146
        }
1147
        return false;
1148
    }
1149
1150
    /**
1151
     * Set nocache flag in variable or create new variable
1152
     *
1153
     * @param string $varName
1154
     */
1155
    public function setNocacheInVariable($varName)
1156
    {
1157
        // create nocache var to make it know for further compiling
1158
        if ($_var = $this->getId($varName)) {
1159
            if (isset($this->template->tpl_vars[ $_var ])) {
1160
                $this->template->tpl_vars[ $_var ] = clone $this->template->tpl_vars[ $_var ];
1161
                $this->template->tpl_vars[ $_var ]->nocache = true;
1162
            } else {
1163
                $this->template->tpl_vars[ $_var ] = new Smarty_Variable(null, true);
1164
            }
1165
        }
1166
    }
1167
1168
    /**
1169
     * @param array $_attr tag attributes
1170
     * @param array $validScopes
1171
     *
1172
     * @return int|string
1173
     * @throws \SmartyCompilerException
1174
     */
1175
    public function convertScope($_attr, $validScopes)
1176
    {
1177
        $_scope = 0;
1178
        if (isset($_attr[ 'scope' ])) {
1179
            $_scopeName = trim($_attr[ 'scope' ], "'\"");
1180
            if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) {
1181
                $_scope = $_scopeName;
1182
            } elseif (is_string($_scopeName)) {
1183
                $_scopeName = trim($_scopeName, "'\"");
1184
                $_scope = isset($validScopes[ $_scopeName ]) ? $validScopes[ $_scopeName ] : false;
1185
            } else {
1186
                $_scope = false;
1187
            }
1188
            if ($_scope === false) {
1189
                $err = var_export($_scopeName, true);
1190
                $this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);
1191
            }
1192
        }
1193
        return $_scope;
1194
    }
1195
1196
    /**
1197
     * Generate nocache code string
1198
     *
1199
     * @param string $code PHP code
1200
     *
1201
     * @return string
1202
     */
1203
    public function makeNocacheCode($code)
1204
    {
1205
        return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " .
1206
               str_replace("^#^", "'", addcslashes($code, '\'\\')) .
1207
               "?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
1208
    }
1209
1210
    /**
1211
     * display compiler error messages without dying
1212
     * If parameter $args is empty it is a parser detected syntax error.
1213
     * In this case the parser is called to obtain information about expected tokens.
1214
     * If parameter $args contains a string this is used as error message
1215
     *
1216
     * @param  string   $args    individual error message or null
1217
     * @param  string   $line    line-number
1218
     * @param null|bool $tagline if true the line number of last tag
1219
     *
1220
     * @throws \SmartyCompilerException when an unexpected token is found
1221
     */
1222
    public function trigger_template_error($args = null, $line = null, $tagline = null)
1223
    {
1224
        $lex = $this->parser->lex;
1225
        if ($tagline === true) {
1226
            // get line number of Tag
1227
            $line = $lex->taglineno;
1228
        } elseif (!isset($line)) {
1229
            // get template source line which has error
1230
            $line = $lex->line;
1231
        } else {
1232
            $line = (int) $line;
1233
        }
1234
1235
        if (in_array($this->template->source->type, array('eval', 'string'))) {
1236
            $templateName = $this->template->source->type . ':' . trim(preg_replace('![\t\r\n]+!', ' ',
1237
                                                                                    strlen($lex->data) > 40 ?
1238
                                                                                        substr($lex->data, 0, 40) .
1239
                                                                                        '...' : $lex->data));
1240
        } else {
1241
            $templateName = $this->template->source->type . ':' . $this->template->source->filepath;
1242
        }
1243
1244
        //        $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...
1245
        $match = preg_split("/\n/", $lex->data);
1246
        $error_text =
1247
            'Syntax error in template "' . (empty($this->trace_filepath) ? $templateName : $this->trace_filepath) .
1248
            '"  on line ' . ($line + $this->trace_line_offset) . ' "' .
1249
            trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])) . '" ';
1250
        if (isset($args)) {
1251
            // individual error message
1252
            $error_text .= $args;
1253
        } else {
1254
            $expect = array();
1255
            // expected token from parser
1256
            $error_text .= ' - Unexpected "' . $lex->value . '"';
1257
            if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {
1258
                foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
1259
                    $exp_token = $this->parser->yyTokenName[ $token ];
1260
                    if (isset($lex->smarty_token_names[ $exp_token ])) {
1261
                        // token type from lexer
1262
                        $expect[] = '"' . $lex->smarty_token_names[ $exp_token ] . '"';
1263
                    } else {
1264
                        // otherwise internal token name
1265
                        $expect[] = $this->parser->yyTokenName[ $token ];
1266
                    }
1267
                }
1268
                $error_text .= ', expected one of: ' . implode(' , ', $expect);
1269
            }
1270
        }
1271
        $e = new SmartyCompilerException($error_text);
1272
        $e->line = $line;
1273
        $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));
1274
        $e->desc = $args;
1275
        $e->template = $this->template->source->filepath;
1276
        throw $e;
1277
    }
1278
1279
    /**
1280
     * Return var_export() value with all white spaces removed
1281
     *
1282
     * @param  mixed $value
1283
     *
1284
     * @return string
1285
     */
1286
    public function getVarExport($value)
1287
    {
1288
        return preg_replace('/\s/', '', var_export($value, true));
1289
    }
1290
1291
    /**
1292
     * Check if $value contains variable elements
1293
     *
1294
     * @param mixed $value
1295
     *
1296
     * @return bool|int
1297
     */
1298
    public function isVariable($value)
1299
    {
1300
        if (is_string($value)) {
1301
            return preg_match('/[$(]/', $value);
1302
        }
1303
        if (is_bool($value) || is_numeric($value)) {
1304
            return false;
1305
        }
1306
        if (is_array($value)) {
1307
            foreach ($value as $k => $v) {
1308
                if ($this->isVariable($k) || $this->isVariable($v)) {
1309
                    return true;
1310
                }
1311
            }
1312
            return false;
1313
        }
1314
        return false;
1315
    }
1316
1317
    /**
1318
     * Get new prefix variable name
1319
     *
1320
     * @return string
1321
     */
1322
    public function getNewPrefixVariable()
1323
    {
1324
        self::$prefixVariableNumber ++;
1325
        return $this->getPrefixVariable();
1326
    }
1327
1328
    /**
1329
     * Get current prefix variable name
1330
     *
1331
     * @return string
1332
     */
1333
    public function getPrefixVariable()
1334
    {
1335
        return '$_prefixVariable' . self::$prefixVariableNumber;
1336
    }
1337
1338
    /**
1339
     * append  code to prefix buffer
1340
     *
1341
     * @param string $code
1342
     */
1343
    public function appendPrefixCode($code)
1344
    {
1345
        $this->prefix_code[] = $code;
1346
    }
1347
1348
    /**
1349
     * get prefix code string
1350
     *
1351
     * @return string
1352
     */
1353
    public function getPrefixCode()
1354
    {
1355
        $code = '';
1356
        $prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
1357
        $this->prefixCodeStack[] = array();
1358
        foreach ($prefixArray as $c) {
1359
            $code = $this->appendCode($code, $c);
1360
        }
1361
        $this->prefix_code = array();
1362
        return $code;
1363
    }
1364
1365
}
1366