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 */ 17class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase 18{ 19 20 /** 21 * Attribute definition: Overwrites base class. 22 * 23 * @var array 24 * @see Smarty_Internal_CompileBase 25 */ 26 public $required_attributes = array('name'); 27 28 /** 29 * Attribute definition: Overwrites base class. 30 * 31 * @var array 32 * @see Smarty_Internal_CompileBase 33 */ 34 public $shorttag_order = array('name'); 35 36 /** 37 * Attribute definition: Overwrites base class. 38 * 39 * @var array 40 * @see Smarty_Internal_CompileBase 41 */ 42 public $optional_attributes = array('_any'); 43 44 /** 45 * Compiles code for the {function} tag 46 * 47 * @param array $args array with attributes from parser 48 * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object 49 * @param array $parameter array with compilation parameter 50 * 51 * @return bool true 52 * @throws \SmartyCompilerException 53 */ 54 public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) 55 { 56 $compiler->loopNesting++; 57 // check and get attributes 58 $_attr = $this->getAttributes($compiler, $args); 59 60 if ($_attr['nocache'] === true) { 61 $compiler->trigger_template_error('nocache option not allowed', null, true); 62 } 63 unset($_attr['nocache']); 64 $_name = trim($_attr['name'], "'\""); 65 $compiler->parent_compiler->tpl_function[$_name] = $compiler->parent_compiler->template->tpl_function[$_name] = array(); 66 $save = array($_attr, $compiler->parser->current_buffer, $compiler->template->compiled->has_nocache_code, 67 $compiler->template->caching); 68 $this->openTag($compiler, 'function', $save); 69 // Init temporary context 70 $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); 71 $compiler->template->compiled->has_nocache_code = false; 72 return true; 73 } 74} 75 76/** 77 * Smarty Internal Plugin Compile Functionclose Class 78 * 79 * @package Smarty 80 * @subpackage Compiler 81 */ 82class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase 83{ 84 85 /** 86 * Compiler object 87 * 88 * @var object 89 */ 90 private $compiler = null; 91 92 /** 93 * Compiles code for the {/function} tag 94 * 95 * @param array $args array with attributes from parser 96 * @param object|\Smarty_Internal_TemplateCompilerBase $compiler compiler object 97 * @param array $parameter array with compilation parameter 98 * 99 * @return bool true 100 */ 101 public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) 102 { 103 $compiler->loopNesting--; 104 $this->compiler = $compiler; 105 $saved_data = $this->closeTag($compiler, array('function')); 106 $_attr = $saved_data[0]; 107 $_name = trim($_attr['name'], "'\""); 108 $compiler->parent_compiler->tpl_function[$_name]['called_functions'] = $compiler->parent_compiler->template->tpl_function[$_name]['called_functions'] = $compiler->called_functions; 109 $compiler->parent_compiler->tpl_function[$_name]['compiled_filepath'] = $compiler->parent_compiler->template->tpl_function[$_name]['compiled_filepath'] = $compiler->parent_compiler->template->compiled->filepath; 110 $compiler->parent_compiler->tpl_function[$_name]['uid'] = $compiler->parent_compiler->template->tpl_function[$_name]['uid'] = $compiler->template->source->uid; 111 $compiler->called_functions = array(); 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 133 $_funcName = "smarty_template_function_{$_name}_{$compiler->template->compiled->nocache_hash}"; 134 $_funcNameCaching = $_funcName . '_nocache'; 135 if ($compiler->template->compiled->has_nocache_code) { 136 $compiler->parent_compiler->tpl_function[$_name]['call_name_caching'] = $compiler->parent_compiler->template->tpl_function[$_name]['call_name_caching'] = $_funcNameCaching; 137 $output = "<?php\n"; 138 $output .= "/* {$_funcNameCaching} */\n"; 139 $output .= "if (!function_exists('{$_funcNameCaching}')) {\n"; 140 $output .= "function {$_funcNameCaching} (\$_smarty_tpl,\$params) {\n"; 141 $output .= "ob_start();\n"; 142 $output .= "\$_smarty_tpl->compiled->has_nocache_code = true;\n"; 143 $output .= $_paramsCode; 144 $output .= "\$_smarty_tpl->_cache['saved_tpl_vars'][] = \$_smarty_tpl->tpl_vars;\n"; 145 $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value);\n}"; 146 $output .= "\$params = var_export(\$params, true);\n"; 147 $output .= "echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php "; 148 $output .= "\\\$saved_tpl_vars = \\\$_smarty_tpl->tpl_vars;\nforeach (\$params as \\\$key => \\\$value) {\n\\\$_smarty_tpl->tpl_vars[\\\$key] = new Smarty_Variable(\\\$value);\n}\n?>"; 149 $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n\";?>"; 150 $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $output)); 151 $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); 152 $output = "<?php echo \"/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/<?php "; 153 $output .= "foreach (Smarty::\\\$global_tpl_vars as \\\$key => \\\$value){\n"; 154 $output .= "if (!isset(\\\$_smarty_tpl->tpl_vars[\\\$key]) || \\\$_smarty_tpl->tpl_vars[\\\$key] === \\\$value) \\\$saved_tpl_vars[\\\$key] = \\\$value;\n}\n"; 155 $output .= "\\\$_smarty_tpl->tpl_vars = \\\$saved_tpl_vars;?>\n"; 156 $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>"; 157 $output .= "<?php echo str_replace('{$compiler->template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n"; 158 $output .= "\$_smarty_tpl->tpl_vars = array_pop(\$_smarty_tpl->_cache['saved_tpl_vars']);\n}\n}\n"; 159 $output .= "/*/ {$_funcName}_nocache */\n\n"; 160 $output .= "?>\n"; 161 $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $output)); 162 $_functionCode = new Smarty_Internal_ParseTree_Tag($compiler->parser, preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", array($this, 163 'removeNocache'), $_functionCode->to_smarty_php($compiler->parser))); 164 } 165 $compiler->parent_compiler->tpl_function[$_name]['call_name'] = $compiler->parent_compiler->template->tpl_function[$_name]['call_name'] = $_funcName; 166 $output = "<?php\n"; 167 $output .= "/* {$_funcName} */\n"; 168 $output .= "if (!function_exists('{$_funcName}')) {\n"; 169 $output .= "function {$_funcName}(\$_smarty_tpl,\$params) {\n"; 170 $output .= "\$saved_tpl_vars = \$_smarty_tpl->tpl_vars;\n"; 171 $output .= $_paramsCode; 172 $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_Variable(\$value);\n}?>"; 173 $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $output)); 174 $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); 175 $output = "<?php foreach (Smarty::\$global_tpl_vars as \$key => \$value){\n"; 176 $output .= "if (!isset(\$_smarty_tpl->tpl_vars[\$key]) || \$_smarty_tpl->tpl_vars[\$key] === \$value) \$saved_tpl_vars[\$key] = \$value;\n}\n"; 177 $output .= "\$_smarty_tpl->tpl_vars = \$saved_tpl_vars;\n}\n}\n"; 178 $output .= "/*/ {$_funcName} */\n\n"; 179 $output .= "?>\n"; 180 $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $output)); 181 $compiler->parent_compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser); 182 // nocache plugins must be copied 183 if (!empty($compiler->template->compiled->required_plugins['nocache'])) { 184 foreach ($compiler->template->compiled->required_plugins['nocache'] as $plugin => $tmp) { 185 foreach ($tmp as $type => $data) { 186 $compiler->parent_compiler->template->compiled->required_plugins['compiled'][$plugin][$type] = $data; 187 } 188 } 189 } 190 // restore old buffer 191 192 $compiler->parser->current_buffer = $saved_data[1]; 193 // restore old status 194 $compiler->template->compiled->has_nocache_code = $saved_data[2]; 195 $compiler->template->caching = $saved_data[3]; 196 return true; 197 } 198 199 /** 200 * @param $match 201 * 202 * @return mixed 203 */ 204 function removeNocache($match) 205 { 206 $code = preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", '', $match[0]); 207 $code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code); 208 return $code; 209 } 210} 211