1: <?php
2:
3: /**
4: * Smarty Resource Data Object
5: * Meta Data Container for Template Files
6: *
7: * @package Smarty
8: * @subpackage TemplateResources
9: * @author Rodney Rehm
10: * @property string $content compiled content
11: */
12: class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
13: {
14: /**
15: * nocache hash
16: *
17: * @var string|null
18: */
19: public $nocache_hash = null;
20:
21: /**
22: * get a Compiled Object of this source
23: *
24: * @param Smarty_Internal_Template $_template template object
25: *
26: * @return Smarty_Template_Compiled compiled object
27: */
28: public static function load($_template)
29: {
30: $compiled = new Smarty_Template_Compiled();
31: if ($_template->source->handler->hasCompiledHandler) {
32: $_template->source->handler->populateCompiledFilepath($compiled, $_template);
33: } else {
34: $compiled->populateCompiledFilepath($_template);
35: }
36: return $compiled;
37: }
38:
39: /**
40: * populate Compiled Object with compiled filepath
41: *
42: * @param Smarty_Internal_Template $_template template object
43: **/
44: public function populateCompiledFilepath(Smarty_Internal_Template $_template)
45: {
46: $source = &$_template->source;
47: $smarty = &$_template->smarty;
48: $this->filepath = $smarty->getCompileDir();
49: if (isset($_template->compile_id)) {
50: $this->filepath .= preg_replace('![^\w]+!', '_', $_template->compile_id) .
51: ($smarty->use_sub_dirs ? DIRECTORY_SEPARATOR : '^');
52: }
53: // if use_sub_dirs, break file into directories
54: if ($smarty->use_sub_dirs) {
55: $this->filepath .= $source->uid[ 0 ] . $source->uid[ 1 ] . DIRECTORY_SEPARATOR . $source->uid[ 2 ] .
56: $source->uid[ 3 ] . DIRECTORY_SEPARATOR . $source->uid[ 4 ] . $source->uid[ 5 ] .
57: DIRECTORY_SEPARATOR;
58: }
59: $this->filepath .= $source->uid . '_';
60: if ($source->isConfig) {
61: $this->filepath .= (int)$smarty->config_read_hidden + (int)$smarty->config_booleanize * 2 +
62: (int)$smarty->config_overwrite * 4;
63: } else {
64: $this->filepath .= (int)$smarty->merge_compiled_includes + (int)$smarty->escape_html * 2 +
65: (($smarty->merge_compiled_includes && $source->type === 'extends') ?
66: (int)$smarty->extends_recursion * 4 : 0);
67: }
68: $this->filepath .= '.' . $source->type;
69: $basename = $source->handler->getBasename($source);
70: if (!empty($basename)) {
71: $this->filepath .= '.' . $basename;
72: }
73: if ($_template->caching) {
74: $this->filepath .= '.cache';
75: }
76: $this->filepath .= '.php';
77: $this->timestamp = $this->exists = is_file($this->filepath);
78: if ($this->exists) {
79: $this->timestamp = filemtime($this->filepath);
80: }
81: }
82:
83: /**
84: * render compiled template code
85: *
86: * @param Smarty_Internal_Template $_template
87: *
88: * @return string
89: * @throws Exception
90: */
91: public function render(Smarty_Internal_Template $_template)
92: {
93: // checks if template exists
94: if (!$_template->source->exists) {
95: $type = $_template->source->isConfig ? 'config' : 'template';
96: throw new SmartyException("Unable to load {$type} '{$_template->source->type}:{$_template->source->name}'");
97: }
98: if ($_template->smarty->debugging) {
99: if (!isset($_template->smarty->_debug)) {
100: $_template->smarty->_debug = new Smarty_Internal_Debug();
101: }
102: $_template->smarty->_debug->start_render($_template);
103: }
104: if (!$this->processed) {
105: $this->process($_template);
106: }
107: if (isset($_template->cached)) {
108: $_template->cached->file_dependency =
109: array_merge($_template->cached->file_dependency, $this->file_dependency);
110: }
111: if ($_template->source->handler->uncompiled) {
112: $_template->source->handler->renderUncompiled($_template->source, $_template);
113: } else {
114: $this->getRenderedTemplateCode($_template);
115: }
116: if ($_template->caching && $this->has_nocache_code) {
117: $_template->cached->hashes[ $this->nocache_hash ] = true;
118: }
119: if ($_template->smarty->debugging) {
120: $_template->smarty->_debug->end_render($_template);
121: }
122: }
123:
124: /**
125: * load compiled template or compile from source
126: *
127: * @param Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template
128: *
129: * @throws Exception
130: */
131: public function process(Smarty_Internal_Template $_smarty_tpl)
132: {
133: $source = &$_smarty_tpl->source;
134: $smarty = &$_smarty_tpl->smarty;
135: if ($source->handler->recompiled) {
136: $source->handler->process($_smarty_tpl);
137: } elseif (!$source->handler->uncompiled) {
138: if (!$this->exists || $smarty->force_compile
139: || ($_smarty_tpl->compile_check && $source->getTimeStamp() > $this->getTimeStamp())
140: ) {
141: $this->compileTemplateSource($_smarty_tpl);
142: $compileCheck = $_smarty_tpl->compile_check;
143: $_smarty_tpl->compile_check = Smarty::COMPILECHECK_OFF;
144: $this->loadCompiledTemplate($_smarty_tpl);
145: $_smarty_tpl->compile_check = $compileCheck;
146: } else {
147: $_smarty_tpl->mustCompile = true;
148: @include $this->filepath;
149: if ($_smarty_tpl->mustCompile) {
150: $this->compileTemplateSource($_smarty_tpl);
151: $compileCheck = $_smarty_tpl->compile_check;
152: $_smarty_tpl->compile_check = Smarty::COMPILECHECK_OFF;
153: $this->loadCompiledTemplate($_smarty_tpl);
154: $_smarty_tpl->compile_check = $compileCheck;
155: }
156: }
157: $_smarty_tpl->_subTemplateRegister();
158: $this->processed = true;
159: }
160: }
161:
162: /**
163: * compile template from source
164: *
165: * @param Smarty_Internal_Template $_template
166: *
167: * @throws Exception
168: */
169: public function compileTemplateSource(Smarty_Internal_Template $_template)
170: {
171: $this->file_dependency = array();
172: $this->includes = array();
173: $this->nocache_hash = null;
174: $this->unifunc = null;
175: // compile locking
176: if ($saved_timestamp = (!$_template->source->handler->recompiled && is_file($this->filepath))) {
177: $saved_timestamp = $this->getTimeStamp();
178: touch($this->filepath);
179: }
180: // compile locking
181: try {
182: // call compiler
183: $_template->loadCompiler();
184: $this->write($_template, $_template->compiler->compileTemplate($_template));
185: } catch (Exception $e) {
186: // restore old timestamp in case of error
187: if ($saved_timestamp && is_file($this->filepath)) {
188: touch($this->filepath, $saved_timestamp);
189: }
190: unset($_template->compiler);
191: throw $e;
192: }
193: // release compiler object to free memory
194: unset($_template->compiler);
195: }
196:
197: /**
198: * Write compiled code by handler
199: *
200: * @param Smarty_Internal_Template $_template template object
201: * @param string $code compiled code
202: *
203: * @return bool success
204: * @throws \SmartyException
205: */
206: public function write(Smarty_Internal_Template $_template, $code)
207: {
208: if (!$_template->source->handler->recompiled) {
209: if ($_template->smarty->ext->_writeFile->writeFile($this->filepath, $code, $_template->smarty) === true) {
210: $this->timestamp = $this->exists = is_file($this->filepath);
211: if ($this->exists) {
212: $this->timestamp = filemtime($this->filepath);
213: return true;
214: }
215: }
216: return false;
217: }
218: return true;
219: }
220:
221: /**
222: * Read compiled content from handler
223: *
224: * @param Smarty_Internal_Template $_template template object
225: *
226: * @return string content
227: */
228: public function read(Smarty_Internal_Template $_template)
229: {
230: if (!$_template->source->handler->recompiled) {
231: return file_get_contents($this->filepath);
232: }
233: return isset($this->content) ? $this->content : false;
234: }
235:
236: /**
237: * Load fresh compiled template by including the PHP file
238: * HHVM requires a work around because of a PHP incompatibility
239: *
240: * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template
241: */
242: private function loadCompiledTemplate(Smarty_Internal_Template $_smarty_tpl)
243: {
244: if (function_exists('opcache_invalidate')
245: && (!function_exists('ini_get') || strlen(ini_get("opcache.restrict_api")) < 1)
246: ) {
247: opcache_invalidate($this->filepath, true);
248: } elseif (function_exists('apc_compile_file')) {
249: apc_compile_file($this->filepath);
250: }
251: if (defined('HHVM_VERSION')) {
252: eval('?>' . file_get_contents($this->filepath));
253: } else {
254: include $this->filepath;
255: }
256: }
257: }
258: