Commit | Line | Data |
---|---|---|
ccd27f54 S |
1 | <?php |
2 | /** | |
74f18453 | 3 | * Smarty Internal Plugin Compile PHP Expression |
ccd27f54 S |
4 | * Compiles any tag which will output an expression or variable |
5 | * | |
6 | * @package Smarty | |
7 | * @subpackage Compiler | |
8 | * @author Uwe Tews | |
9 | */ | |
10 | ||
11 | /** | |
74f18453 | 12 | * Smarty Internal Plugin Compile PHP Expression Class |
ccd27f54 S |
13 | * |
14 | * @package Smarty | |
15 | * @subpackage Compiler | |
16 | */ | |
17 | class Smarty_Internal_Compile_Private_Php extends Smarty_Internal_CompileBase | |
18 | { | |
cd8826ea | 19 | |
ccd27f54 S |
20 | /** |
21 | * Attribute definition: Overwrites base class. | |
22 | * | |
23 | * @var array | |
24 | * @see Smarty_Internal_CompileBase | |
25 | */ | |
26 | public $required_attributes = array('code', 'type'); | |
27 | ||
28 | /** | |
29 | * Compiles code for generating output from any expression | |
30 | * | |
31 | * @param array $args array with attributes from parser | |
32 | * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object | |
33 | * @param array $parameter array with compilation parameter | |
34 | * | |
35 | * @return string | |
36 | * @throws \SmartyException | |
37 | */ | |
38 | public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) | |
39 | { | |
40 | // check and get attributes | |
41 | $_attr = $this->getAttributes($compiler, $args); | |
42 | $compiler->has_code = false; | |
cd8826ea S |
43 | if ($_attr['type'] == 'xml') { |
44 | $compiler->tag_nocache = true; | |
45 | $save = $compiler->template->has_nocache_code; | |
46 | $compiler->template->has_nocache_code = $save; | |
47 | $output = addcslashes($_attr['code'], "'\\"); | |
48 | $compiler->parser->current_buffer->append_subtree(new Smarty_Internal_ParseTree_Tag($compiler->parser, $compiler->processNocacheCode("<?php echo '" . $output . "';?>", $compiler, true))); | |
49 | return ''; | |
ccd27f54 S |
50 | } |
51 | if ($_attr['type'] != 'tag') { | |
cd8826ea | 52 | if ($compiler->php_handling == Smarty::PHP_REMOVE) { |
ccd27f54 | 53 | return ''; |
cd8826ea S |
54 | } elseif ($compiler->php_handling == Smarty::PHP_QUOTE) { |
55 | $output = preg_replace_callback('#(<\?(?:php|=)?)|(<%)|(<script\s+language\s*=\s*["\']?\s*php\s*["\']?\s*>)|(\?>)|(%>)|(<\/script>)#i', array($this, | |
56 | 'quote'), $_attr['code']); | |
ccd27f54 S |
57 | $compiler->parser->current_buffer->append_subtree(new Smarty_Internal_ParseTree_Text($compiler->parser, $output)); |
58 | return ''; | |
cd8826ea S |
59 | } elseif ($compiler->php_handling == Smarty::PHP_PASSTHRU || $_attr['type'] == 'unmatched') { |
60 | $compiler->tag_nocache = true; | |
61 | $save = $compiler->template->has_nocache_code; | |
62 | $compiler->template->has_nocache_code = $save; | |
63 | $output = addcslashes($_attr['code'], "'\\"); | |
64 | $compiler->parser->current_buffer->append_subtree(new Smarty_Internal_ParseTree_Tag($compiler->parser, $compiler->processNocacheCode("<?php echo '" . $output . "';?>", $compiler, true))); | |
ccd27f54 | 65 | return ''; |
cd8826ea | 66 | } elseif ($compiler->php_handling == Smarty::PHP_ALLOW) { |
ccd27f54 S |
67 | if (!($compiler->smarty instanceof SmartyBC)) { |
68 | $compiler->trigger_template_error('$smarty->php_handling PHP_ALLOW not allowed. Use SmartyBC to enable it', $compiler->lex->taglineno); | |
69 | } | |
70 | $compiler->has_code = true; | |
71 | return $_attr['code']; | |
72 | } else { | |
73 | $compiler->trigger_template_error('Illegal $smarty->php_handling value', $compiler->lex->taglineno); | |
74 | } | |
75 | } else { | |
76 | $compiler->has_code = true; | |
cd8826ea S |
77 | if (!($compiler->smarty instanceof SmartyBC)) { |
78 | $compiler->trigger_template_error('{php}[/php} tags not allowed. Use SmartyBC to enable them', $compiler->lex->taglineno); | |
79 | } | |
ccd27f54 S |
80 | $ldel = preg_quote($compiler->smarty->left_delimiter, '#'); |
81 | $rdel = preg_quote($compiler->smarty->right_delimiter, '#'); | |
cd8826ea | 82 | preg_match("#^({$ldel}php\\s*)((.)*?)({$rdel})#", $_attr['code'], $match); |
ccd27f54 S |
83 | if (!empty($match[2])) { |
84 | if ('nocache' == trim($match[2])) { | |
85 | $compiler->tag_nocache = true; | |
86 | } else { | |
87 | $compiler->trigger_template_error("illegal value of option flag \"{$match[2]}\"", $compiler->lex->taglineno); | |
88 | } | |
89 | } | |
cd8826ea S |
90 | return preg_replace(array("#^{$ldel}\\s*php\\s*(.)*?{$rdel}#", |
91 | "#{$ldel}\\s*/\\s*php\\s*{$rdel}$#"), array('<?php ', '?>'), $_attr['code']); | |
ccd27f54 S |
92 | } |
93 | } | |
cd8826ea S |
94 | |
95 | /** | |
96 | * Lexer code for PHP tags | |
97 | * | |
98 | * This code has been moved from lexer here fo easier debugging and maintenance | |
99 | * | |
100 | * @param $lex | |
101 | */ | |
102 | public function parsePhp($lex) | |
103 | { | |
104 | $close = 0; | |
105 | $lex->taglineno = $lex->line; | |
106 | $closeTag = '?>'; | |
107 | if (strpos($lex->value, '<?xml') === 0) { | |
108 | $lex->phpType = 'xml'; | |
109 | } elseif (strpos($lex->value, '<?') === 0) { | |
110 | $lex->phpType = 'php'; | |
111 | } elseif (strpos($lex->value, '<%') === 0) { | |
112 | $lex->phpType = 'asp'; | |
113 | $closeTag = '%>'; | |
114 | } elseif (strpos($lex->value, '%>') === 0) { | |
115 | $lex->phpType = 'unmatched'; | |
116 | } elseif (strpos($lex->value, '?>') === 0) { | |
117 | $lex->phpType = 'unmatched'; | |
118 | } elseif (strpos($lex->value, '<s') === 0) { | |
119 | $lex->phpType = 'script'; | |
120 | $closeTag = '</script>'; | |
121 | } elseif (strpos($lex->value, $lex->smarty->left_delimiter) === 0) { | |
122 | if ($lex->isAutoLiteral()) { | |
123 | $lex->token = Smarty_Internal_Templateparser::TP_TEXT; | |
124 | return; | |
125 | } | |
126 | $closeTag = "{$lex->smarty->left_delimiter}/php{$lex->smarty->right_delimiter}"; | |
127 | if ($lex->value == $closeTag) { | |
128 | $lex->compiler->trigger_template_error("unexpected closing tag '{$closeTag}'"); | |
129 | } | |
130 | $lex->phpType = 'tag'; | |
131 | } | |
132 | if ($lex->phpType == 'unmatched') { | |
133 | return; | |
134 | } | |
135 | if (($lex->phpType == 'php' || $lex->phpType == 'asp') && ($lex->compiler->php_handling == Smarty::PHP_PASSTHRU || $lex->compiler->php_handling == Smarty::PHP_QUOTE)) { | |
136 | return; | |
137 | } | |
138 | $start = $lex->counter + strlen($lex->value); | |
139 | $body = true; | |
140 | if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) { | |
141 | $close = $match[0][1]; | |
142 | } else { | |
143 | $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'"); | |
144 | } | |
145 | while ($body) { | |
146 | if (preg_match('~([/][*])|([/][/][^\n]*)|(\'[^\'\\\\]*(?:\\.[^\'\\\\]*)*\')|("[^"\\\\]*(?:\\.[^"\\\\]*)*")~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) { | |
147 | $value = $match[0][0]; | |
148 | $from = $pos = $match[0][1]; | |
149 | if ($pos > $close) { | |
150 | $body = false; | |
151 | } else { | |
152 | $start = $pos + strlen($value); | |
153 | $phpCommentStart = $value == '/*'; | |
154 | if ($phpCommentStart) { | |
155 | $phpCommentEnd = preg_match('~([*][/])~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start); | |
156 | if ($phpCommentEnd) { | |
157 | $pos2 = $match[0][1]; | |
158 | $start = $pos2 + strlen($match[0][0]); | |
159 | } | |
160 | } | |
161 | while ($close > $pos && $close < $start) { | |
162 | if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $from)) { | |
163 | $close = $match[0][1]; | |
164 | $from = $close + strlen($match[0][0]); | |
165 | } else { | |
166 | $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'"); | |
167 | } | |
168 | } | |
169 | if ($phpCommentStart && (!$phpCommentEnd || $pos2 > $close)) { | |
170 | $lex->taglineno = $lex->line + substr_count(substr($lex->data, $lex->counter, $start), "\n"); | |
171 | $lex->compiler->trigger_template_error("missing PHP comment closing tag '*/'"); | |
172 | } | |
173 | } | |
174 | } else { | |
175 | $body = false; | |
176 | } | |
177 | } | |
178 | $lex->value = substr($lex->data, $lex->counter, $close + strlen($closeTag) - $lex->counter); | |
179 | } | |
180 | ||
181 | /* | |
182 | * Call back function for $php_handling = PHP_QUOTE | |
183 | * | |
184 | */ | |
185 | private function quote($match) | |
186 | { | |
187 | return htmlspecialchars($match[0], ENT_QUOTES); | |
188 | } | |
ccd27f54 | 189 | } |