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

sysplugins/smarty_internal_compile_include.php (2 issues)

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