1: <?php
2: /**
3: * Smarty Internal Plugin Compile Function
4: * Compiles the {function} {/function} tags
5: *
6: * @package Smarty
7: * @subpackage Compiler
8: * @author Uwe Tews
9: */
10:
11: /**
12: * Smarty Internal Plugin Compile Function Class
13: *
14: * @package Smarty
15: * @subpackage Compiler
16: */
17: class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase
18: {
19: /**
20: * Attribute definition: Overwrites base class.
21: *
22: * @var array
23: * @see Smarty_Internal_CompileBase
24: */
25: public $required_attributes = array('name');
26:
27: /**
28: * Attribute definition: Overwrites base class.
29: *
30: * @var array
31: * @see Smarty_Internal_CompileBase
32: */
33: public $shorttag_order = array('name');
34:
35: /**
36: * Attribute definition: Overwrites base class.
37: *
38: * @var array
39: * @see Smarty_Internal_CompileBase
40: */
41: public $optional_attributes = array('_any');
42:
43: /**
44: * Compiles code for the {function} tag
45: *
46: * @param array $args array with attributes from parser
47: * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
48: *
49: * @return bool true
50: * @throws \SmartyCompilerException
51: */
52: public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
53: {
54: // check and get attributes
55: $_attr = $this->getAttributes($compiler, $args);
56: if ($_attr[ 'nocache' ] === true) {
57: $compiler->trigger_template_error('nocache option not allowed', null, true);
58: }
59: unset($_attr[ 'nocache' ]);
60: $_name = trim($_attr[ 'name' ], '\'"');
61:
62: if (!preg_match('/^[a-zA-Z0-9_\x80-\xff]+$/', $_name)) {
63: $compiler->trigger_template_error("Function name contains invalid characters: {$_name}", null, true);
64: }
65:
66: $compiler->parent_compiler->tpl_function[ $_name ] = array();
67: $save = array(
68: $_attr, $compiler->parser->current_buffer, $compiler->template->compiled->has_nocache_code,
69: $compiler->template->caching
70: );
71: $this->openTag($compiler, 'function', $save);
72: // Init temporary context
73: $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
74: $compiler->template->compiled->has_nocache_code = false;
75: $compiler->saveRequiredPlugins(true);
76: return true;
77: }
78: }
79:
80: /**
81: * Smarty Internal Plugin Compile Functionclose Class
82: *
83: * @package Smarty
84: * @subpackage Compiler
85: */
86: class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
87: {
88: /**
89: * Compiler object
90: *
91: * @var object
92: */
93: private $compiler = null;
94:
95: /**
96: * Compiles code for the {/function} tag
97: *
98: * @param array $args array with attributes from parser
99: * @param object|\Smarty_Internal_TemplateCompilerBase $compiler compiler object
100: *
101: * @return bool true
102: */
103: public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
104: {
105: $this->compiler = $compiler;
106: $saved_data = $this->closeTag($compiler, array('function'));
107: $_attr = $saved_data[ 0 ];
108: $_name = trim($_attr[ 'name' ], '\'"');
109: $compiler->parent_compiler->tpl_function[ $_name ][ 'compiled_filepath' ] =
110: $compiler->parent_compiler->template->compiled->filepath;
111: $compiler->parent_compiler->tpl_function[ $_name ][ 'uid' ] = $compiler->template->source->uid;
112: $_parameter = $_attr;
113: unset($_parameter[ 'name' ]);
114: // default parameter
115: $_paramsArray = array();
116: foreach ($_parameter as $_key => $_value) {
117: if (is_int($_key)) {
118: $_paramsArray[] = "$_key=>$_value";
119: } else {
120: $_paramsArray[] = "'$_key'=>$_value";
121: }
122: }
123: if (!empty($_paramsArray)) {
124: $_params = 'array(' . implode(',', $_paramsArray) . ')';
125: $_paramsCode = "\$params = array_merge($_params, \$params);\n";
126: } else {
127: $_paramsCode = '';
128: }
129: $_functionCode = $compiler->parser->current_buffer;
130: // setup buffer for template function code
131: $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
132: $_funcName = "smarty_template_function_{$_name}_{$compiler->template->compiled->nocache_hash}";
133: $_funcNameCaching = $_funcName . '_nocache';
134: if ($compiler->template->compiled->has_nocache_code) {
135: $compiler->parent_compiler->tpl_function[ $_name ][ 'call_name_caching' ] = $_funcNameCaching;
136: $output = "<?php\n";
137: $output .= $compiler->cStyleComment(" {$_funcNameCaching} ") . "\n";
138: $output .= "if (!function_exists('{$_funcNameCaching}')) {\n";
139: $output .= "function {$_funcNameCaching} (Smarty_Internal_Template \$_smarty_tpl,\$params) {\n";
140: $output .= "ob_start();\n";
141: $output .= $compiler->compileRequiredPlugins();
142: $output .= "\$_smarty_tpl->compiled->has_nocache_code = true;\n";
143: $output .= $_paramsCode;
144: $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}\n";
145: $output .= "\$params = var_export(\$params, true);\n";
146: $output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
147: $output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->saveTemplateVariables(\\\$_smarty_tpl, '{$_name}');\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new Smarty_Variable(\\\$value, \\\$_smarty_tpl->isRenderingCache);\n}\n?>";
148: $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";?>";
149: $compiler->parser->current_buffer->append_subtree(
150: $compiler->parser,
151: new Smarty_Internal_ParseTree_Tag(
152: $compiler->parser,
153: $output
154: )
155: );
156: $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
157: $output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php ";
158: $output .= "\\\$_smarty_tpl->smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n";
159: $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>";
160: $output .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n";
161: $output .= "}\n}\n";
162: $output .= $compiler->cStyleComment("/ {$_funcName}_nocache ") . "\n\n";
163: $output .= "?>\n";
164: $compiler->parser->current_buffer->append_subtree(
165: $compiler->parser,
166: new Smarty_Internal_ParseTree_Tag(
167: $compiler->parser,
168: $output
169: )
170: );
171: $_functionCode = new Smarty_Internal_ParseTree_Tag(
172: $compiler->parser,
173: preg_replace_callback(
174: "/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/",
175: array($this, 'removeNocache'),
176: $_functionCode->to_smarty_php($compiler->parser)
177: )
178: );
179: }
180: $compiler->parent_compiler->tpl_function[ $_name ][ 'call_name' ] = $_funcName;
181: $output = "<?php\n";
182: $output .= $compiler->cStyleComment(" {$_funcName} ") . "\n";
183: $output .= "if (!function_exists('{$_funcName}')) {\n";
184: $output .= "function {$_funcName}(Smarty_Internal_Template \$_smarty_tpl,\$params) {\n";
185: $output .= $_paramsCode;
186: $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value, \$_smarty_tpl->isRenderingCache);\n}\n";
187: $output .= $compiler->compileCheckPlugins(array_merge($compiler->required_plugins[ 'compiled' ],
188: $compiler->required_plugins[ 'nocache' ]));
189: $output .= "?>\n";
190: $compiler->parser->current_buffer->append_subtree(
191: $compiler->parser,
192: new Smarty_Internal_ParseTree_Tag(
193: $compiler->parser,
194: $output
195: )
196: );
197: $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
198: $output = "<?php\n}}\n";
199: $output .= $compiler->cStyleComment("/ {$_funcName} ") . "\n\n";
200: $output .= "?>\n";
201: $compiler->parser->current_buffer->append_subtree(
202: $compiler->parser,
203: new Smarty_Internal_ParseTree_Tag(
204: $compiler->parser,
205: $output
206: )
207: );
208: $compiler->parent_compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser);
209: // restore old buffer
210: $compiler->parser->current_buffer = $saved_data[ 1 ];
211: // restore old status
212: $compiler->restoreRequiredPlugins();
213: $compiler->template->compiled->has_nocache_code = $saved_data[ 2 ];
214: $compiler->template->caching = $saved_data[ 3 ];
215: return true;
216: }
217:
218: /**
219: * Remove nocache code
220: *
221: * @param $match
222: *
223: * @return string
224: */
225: public function removeNocache($match)
226: {
227: $code =
228: preg_replace(
229: "/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/",
230: '',
231: $match[ 0 ]
232: );
233: $code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code);
234: return $code;
235: }
236: }
237: