Completed
Branch master (78c2af)
by Pierre-Henry
52:17 queued 17:37
created

sysplugins/smarty_internal_compile_include.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Smarty Internal Plugin Compile Include
4
 * Compiles the {include} tag
5
 *
6
 * @package    Smarty
7
 * @subpackage Compiler
8
 * @author     Uwe Tews
9
 */
10
11
/**
12
 * Smarty Internal Plugin Compile Include Class
13
 *
14
 * @package    Smarty
15
 * @subpackage Compiler
16
 */
17
class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
18
{
19
    /**
20
     * caching mode to create nocache code but no cache file
21
     */
22
    const CACHING_NOCACHE_CODE = 9999;
23
24
    /**
25
     * Attribute definition: Overwrites base class.
26
     *
27
     * @var array
28
     * @see Smarty_Internal_CompileBase
29
     */
30
    public $required_attributes = array('file');
31
32
    /**
33
     * Attribute definition: Overwrites base class.
34
     *
35
     * @var array
36
     * @see Smarty_Internal_CompileBase
37
     */
38
    public $shorttag_order = array('file');
39
40
    /**
41
     * Attribute definition: Overwrites base class.
42
     *
43
     * @var array
44
     * @see Smarty_Internal_CompileBase
45
     */
46
    public $option_flags = array('nocache', 'inline', 'caching', 'bubble_up');
47
48
    /**
49
     * Attribute definition: Overwrites base class.
50
     *
51
     * @var array
52
     * @see Smarty_Internal_CompileBase
53
     */
54
    public $optional_attributes = array('_any');
55
56
    /**
57
     * Valid scope names
58
     *
59
     * @var array
60
     */
61
    public $valid_scopes = array('local'  => true, 'parent' => true, 'root' => true,
62
                                 'tpl_root' => true);
63
64
    /**
65
     * Compiles code for the {include} tag
66
     *
67
     * @param  array                                  $args      array with attributes from parser
68
     * @param  Smarty_Internal_SmartyTemplateCompiler $compiler  compiler object
69
     * @param  array                                  $parameter array with compilation parameter
70
     *
71
     * @throws SmartyCompilerException
72
     * @return string compiled code
73
     */
74
    public function compile($args, Smarty_Internal_SmartyTemplateCompiler $compiler, $parameter)
75
    {
76
        // check and get attributes
77
        $_attr = $this->getAttributes($compiler, $args);
78
79
        $hashResourceName = $fullResourceName = $source_resource = $_attr['file'];
80
        $variable_template = false;
81
        $cache_tpl = false;
82
        // parse resource_name
83
        if (preg_match('/^([\'"])(([A-Za-z0-9_\-]{2,})[:])?(([^$()]+)|(.+))\1$/', $source_resource, $match)) {
84
            $type = !empty($match[3]) ? $match[3] : $compiler->template->smarty->default_resource_type;
85
            $name = !empty($match[5]) ? $match[5] : $match[6];
86
            $handler = Smarty_Resource::load($compiler->smarty, $type);
87
            if ($handler->recompiled || $handler->uncompiled) {
88
                $variable_template = true;
89
            }
90
            if (!$variable_template) {
91
                if ($type != 'string') {
92
                    $fullResourceName = "{$type}:{$name}";
93
                    $compiled = $compiler->parent_compiler->template->compiled;
94
                    if (isset($compiled->includes[$fullResourceName])) {
95
                        $compiled->includes[$fullResourceName] ++;
96
                        $cache_tpl = true;
97
                    } else {
98
                        $compiled->includes[$fullResourceName] = 1;
99
                    }
100
                    $fullResourceName = '"' . $fullResourceName . '"';
101
                }
102
            }
103
            if (empty($match[5])) {
104
                $variable_template = true;
105
            }
106
        } else {
107
            $variable_template = true;
108
        }
109
110
        if (isset($_attr['assign'])) {
111
            // output will be stored in a smarty variable instead of being displayed
112
            $_assign = $_attr['assign'];
113
        }
114
115
        // scope setup
116
        $_scope = Smarty::SCOPE_LOCAL;
117
        if (isset($_attr['scope'])) {
118
            $_attr['scope'] = trim($_attr['scope'], "'\"");
119
            if (!isset($this->valid_scopes[$_attr['scope']])) {
120
                $compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null, true);
121
            }
122
            if ($_attr['scope'] != 'local') {
123
                if ($_attr['scope'] == 'parent') {
124
                    $_scope = Smarty::SCOPE_PARENT;
125
                } elseif ($_attr['scope'] == 'root') {
126
                    $_scope = Smarty::SCOPE_ROOT;
127
                } elseif ($_attr['scope'] == 'tpl_root') {
128
                    $_scope = Smarty::SCOPE_TPL_ROOT;
129
                }
130
                $_scope += (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ] == 'false') ? 0 :
131
                    Smarty::SCOPE_BUBBLE_UP;
132
            }
133
        }
134
135
        // set flag to cache subtemplate object when called within loop or template name is variable.
136
        if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) {
137
            $_cache_tpl = 'true';
138
        } else {
139
            $_cache_tpl = 'false';
140
        }
141
        // assume caching is off
142
        $_caching = Smarty::CACHING_OFF;
143
144
        if ($_attr['nocache'] === true) {
145
            $compiler->tag_nocache = true;
146
        }
147
148
        $call_nocache = $compiler->tag_nocache || $compiler->nocache;
149
150
        // caching was on and {include} is not in nocache mode
151
        if ($compiler->template->caching && !$compiler->nocache && !$compiler->tag_nocache) {
152
            $_caching = self::CACHING_NOCACHE_CODE;
153
        }
154
155
        // flag if included template code should be merged into caller
156
        $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr['inline'] === true) &&
157
            !$compiler->template->source->handler->recompiled;
158
159
        if ($merge_compiled_includes && $_attr['inline'] !== true) {
160
            // variable template name ?
161
            if ($variable_template) {
162
                $merge_compiled_includes = false;
163
                if ($compiler->template->caching) {
164
                    // must use individual cache file
165
                    //$_attr['caching'] = 1;
166
                }
167
            }
168
            // variable compile_id?
169
            if (isset($_attr['compile_id'])) {
170
                if (!((substr_count($_attr['compile_id'], '"') == 2 || substr_count($_attr['compile_id'], "'") == 2 ||
171
                        is_numeric($_attr['compile_id']))) || substr_count($_attr['compile_id'], '(') != 0 ||
172
                    substr_count($_attr['compile_id'], '$_smarty_tpl->') != 0
173
                ) {
174
                    $merge_compiled_includes = false;
175
                    if ($compiler->template->caching) {
176
                        // must use individual cache file
177
                        //$_attr['caching'] = 1;
178
                    }
179
                }
180
            }
181
        }
182
183
        /*
184
        * if the {include} tag provides individual parameter for caching or compile_id
185
        * the subtemplate must not be included into the common cache file and is treated like
186
        * a call in nocache mode.
187
        *
188
        */
189
        if ($_attr['nocache'] !== true && $_attr['caching']) {
190
            $_caching = $_new_caching = (int) $_attr['caching'];
191
            $call_nocache = true;
192
        } else {
193
            $_new_caching = Smarty::CACHING_LIFETIME_CURRENT;
194
        }
195
        if (isset($_attr['cache_lifetime'])) {
196
            $_cache_lifetime = $_attr['cache_lifetime'];
197
            $call_nocache = true;
198
            $_caching = $_new_caching;
199
        } else {
200
            $_cache_lifetime = '$_smarty_tpl->cache_lifetime';
201
        }
202
        if (isset($_attr['cache_id'])) {
203
            $_cache_id = $_attr['cache_id'];
204
            $call_nocache = true;
205
            $_caching = $_new_caching;
206
        } else {
207
            $_cache_id = '$_smarty_tpl->cache_id';
208
        }
209
        if (isset($_attr['compile_id'])) {
210
            $_compile_id = $_attr['compile_id'];
211
        } else {
212
            $_compile_id = '$_smarty_tpl->compile_id';
213
        }
214
215
        // if subtemplate will be called in nocache mode do not merge
216
        if ($compiler->template->caching && $call_nocache) {
217
            $merge_compiled_includes = false;
218
        }
219
220
        $has_compiled_template = false;
221
        if ($merge_compiled_includes) {
222
            $c_id = isset($_attr['compile_id']) ? $_attr['compile_id'] : $compiler->template->compile_id;
223
            // we must observe different compile_id and caching
224
            $t_hash = sha1($c_id . ($_caching ? '--caching' : '--nocaching'));
225
            if (!isset($compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash])) {
226
                $has_compiled_template =
227
                    $this->compileInlineTemplate($compiler, $fullResourceName, $_caching, $hashResourceName, $t_hash,
228
                                                 $c_id);
229
            } else {
230
                $has_compiled_template = true;
231
            }
232
        }
233
        // delete {include} standard attributes
234
        unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['compile_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline'], $_attr['bubble_up']);
235
        // remaining attributes must be assigned as smarty variable
236
        $_vars_nc = '';
237
        if (!empty($_attr)) {
238
            if ($_scope == Smarty::SCOPE_LOCAL) {
239
                $_pairs = array();
240
                // create variables
241
                foreach ($_attr as $key => $value) {
242
                    $_pairs[] = "'$key'=>$value";
243
                    $_vars_nc .= "\$_smarty_tpl->tpl_vars['$key'] =  new Smarty_Variable($value);\n";
244
                }
245
                $_vars = 'array(' . join(',', $_pairs) . ')';
246
            } else {
247
                $compiler->trigger_template_error('variable passing not allowed in parent/global scope', null, true);
248
            }
249
        } else {
250
            $_vars = 'array()';
251
        }
252
        $update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache &&
253
            $_compile_id != '$_smarty_tpl->compile_id';
254
        if ($has_compiled_template && !$call_nocache) {
255
            $_output = "<?php\n";
256
            if ($update_compile_id) {
257
                $_output .= $compiler->makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n");
258
            }
259
            if (!empty($_vars_nc) && $_caching == 9999 && $compiler->template->caching) {
260
                //$compiler->suppressNocacheProcessing = false;
261
                $_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n", true), 6, - 3);
262
                //$compiler->suppressNocacheProcessing = true;
263
            }
264
            if (isset($_assign)) {
265
                $_output .= "ob_start();\n";
266
            }
267
            $_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['func']}');\n";
0 ignored issues
show
The variable $_vars does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $t_hash does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
268
            if (isset($_assign)) {
269
                $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
270
            }
271
            if ($update_compile_id) {
272
                $_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n");
273
            }
274
            $_output .= "?>\n";
275
276
            return $_output;
277
        }
278
279
        if ($call_nocache) {
280
            $compiler->tag_nocache = true;
281
        }
282
        $_output = "<?php ";
283
        if ($update_compile_id) {
284
            $_output .= "\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n";
285
        }
286
        // was there an assign attribute
287
        if (isset($_assign)) {
288
            $_output .= "ob_start();\n";
289
        }
290
        $_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_scope, {$_cache_tpl});\n";
291
        if (isset($_assign)) {
292
            $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
293
        }
294
        if ($update_compile_id) {
295
            $_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n";
296
        }
297
        $_output .= "?>\n";
298
        return $_output;
299
    }
300
301
    /**
302
     * Compile inline sub template
303
     *
304
     * @param \Smarty_Internal_SmartyTemplateCompiler $compiler
305
     * @param                                         $fullResourceName
306
     * @param                                         $_caching
307
     * @param                                         $hashResourceName
308
     * @param                                         $t_hash
309
     * @param                                         $c_id
310
     *
311
     * @return bool
312
     */
313
    public function compileInlineTemplate(Smarty_Internal_SmartyTemplateCompiler $compiler, $fullResourceName,
314
                                          $_caching, $hashResourceName, $t_hash, $c_id)
315
    {
316
        $compiler->smarty->allow_ambiguous_resources = true;
317
        /* @var Smarty_Internal_Template $tpl */
318
        $tpl =
319
            new $compiler->smarty->template_class (trim($fullResourceName, '"\''), $compiler->smarty, $compiler->template,
320
                                                   $compiler->template->cache_id, $c_id, $_caching);
321
        if (!($tpl->source->handler->uncompiled) && $tpl->source->exists) {
322
            $compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['uid'] = $tpl->source->uid;
323
            if (isset($compiler->template->ext->_inheritance)) {
324
                $tpl->ext->_inheritance = clone $compiler->template->ext->_inheritance;
325
            }
326
            $tpl->compiled = new Smarty_Template_Compiled();
327
            $tpl->compiled->nocache_hash = $compiler->parent_compiler->template->compiled->nocache_hash;
328
            $tpl->loadCompiler();
329
            // save unique function name
330
            $compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['func'] =
331
            $tpl->compiled->unifunc = 'content_' . str_replace(array('.', ','), '_', uniqid('', true));
332
            // make sure whole chain gets compiled
333
            $tpl->mustCompile = true;
334
            $compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['nocache_hash'] =
335
                $tpl->compiled->nocache_hash;
336
            if ($compiler->template->source->type == 'file') {
337
                $sourceInfo = $compiler->template->source->filepath;
338
            } else {
339
                $basename = $compiler->template->source->handler->getBasename($compiler->template->source);
340
                $sourceInfo = $compiler->template->source->type .':' . ($basename ? $basename : $compiler->template->source->name);
341
            }
342
            // get compiled code
343
            $compiled_code = "<?php\n\n";
344
            $compiled_code .= "/* Start inline template \"{$sourceInfo}\" =============================*/\n";
345
            $compiled_code .= "function {$tpl->compiled->unifunc} (\$_smarty_tpl) {\n";
346
            $compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler);
347
            $compiled_code .= "<?php\n";
348
            $compiled_code .= "}\n?>\n";
349
            $compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode);
350
            $compiled_code .= "<?php\n\n";
351
            $compiled_code .= "/* End inline template \"{$sourceInfo}\" =============================*/\n";
352
            $compiled_code .= "?>";
353
            unset($tpl->compiler);
354
            if ($tpl->compiled->has_nocache_code) {
355
                // replace nocache_hash
356
                $compiled_code =
357
                    str_replace("{$tpl->compiled->nocache_hash}", $compiler->template->compiled->nocache_hash,
358
                                $compiled_code);
359
                $compiler->template->compiled->has_nocache_code = true;
360
            }
361
            $compiler->parent_compiler->mergedSubTemplatesCode[$tpl->compiled->unifunc] = $compiled_code;
362
            return true;
363
        } else {
364
            return false;
365
        }
366
    }
367
}
368