1: <?php
2: /**
3: * Smarty Internal Plugin Debug
4: * Class to collect data for the Smarty Debugging Console
5: *
6: * @package Smarty
7: * @subpackage Debug
8: * @author Uwe Tews
9: */
10:
11: /**
12: * Smarty Internal Plugin Debug Class
13: *
14: * @package Smarty
15: * @subpackage Debug
16: */
17: class Smarty_Internal_Debug extends Smarty_Internal_Data
18: {
19: /**
20: * template data
21: *
22: * @var array
23: */
24: public $template_data = array();
25:
26: /**
27: * List of uid's which shall be ignored
28: *
29: * @var array
30: */
31: public $ignore_uid = array();
32:
33: /**
34: * Index of display() and fetch() calls
35: *
36: * @var int
37: */
38: public $index = 0;
39:
40: /**
41: * Counter for window offset
42: *
43: * @var int
44: */
45: public $offset = 0;
46:
47: /**
48: * Start logging template
49: *
50: * @param \Smarty_Internal_Template $template template
51: * @param null $mode true: display false: fetch null: subtemplate
52: */
53: public function start_template(Smarty_Internal_Template $template, $mode = null)
54: {
55: if (isset($mode) && !$template->_isSubTpl()) {
56: $this->index++;
57: $this->offset++;
58: $this->template_data[ $this->index ] = null;
59: }
60: $key = $this->get_key($template);
61: $this->template_data[ $this->index ][ $key ][ 'start_template_time' ] = microtime(true);
62: }
63:
64: /**
65: * End logging of cache time
66: *
67: * @param \Smarty_Internal_Template $template cached template
68: */
69: public function end_template(Smarty_Internal_Template $template)
70: {
71: $key = $this->get_key($template);
72: $this->template_data[ $this->index ][ $key ][ 'total_time' ] +=
73: microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_template_time' ];
74: //$this->template_data[$this->index][$key]['properties'] = $template->properties;
75: }
76:
77: /**
78: * Start logging of compile time
79: *
80: * @param \Smarty_Internal_Template $template
81: */
82: public function start_compile(Smarty_Internal_Template $template)
83: {
84: static $_is_stringy = array('string' => true, 'eval' => true);
85: if (!empty($template->compiler->trace_uid)) {
86: $key = $template->compiler->trace_uid;
87: if (!isset($this->template_data[ $this->index ][ $key ])) {
88: if (isset($_is_stringy[ $template->source->type ])) {
89: $this->template_data[ $this->index ][ $key ][ 'name' ] =
90: '\'' . substr($template->source->name, 0, 25) . '...\'';
91: } else {
92: $this->template_data[ $this->index ][ $key ][ 'name' ] = $template->source->filepath;
93: }
94: $this->template_data[ $this->index ][ $key ][ 'compile_time' ] = 0;
95: $this->template_data[ $this->index ][ $key ][ 'render_time' ] = 0;
96: $this->template_data[ $this->index ][ $key ][ 'cache_time' ] = 0;
97: }
98: } else {
99: if (isset($this->ignore_uid[ $template->source->uid ])) {
100: return;
101: }
102: $key = $this->get_key($template);
103: }
104: $this->template_data[ $this->index ][ $key ][ 'start_time' ] = microtime(true);
105: }
106:
107: /**
108: * End logging of compile time
109: *
110: * @param \Smarty_Internal_Template $template
111: */
112: public function end_compile(Smarty_Internal_Template $template)
113: {
114: if (!empty($template->compiler->trace_uid)) {
115: $key = $template->compiler->trace_uid;
116: } else {
117: if (isset($this->ignore_uid[ $template->source->uid ])) {
118: return;
119: }
120: $key = $this->get_key($template);
121: }
122: $this->template_data[ $this->index ][ $key ][ 'compile_time' ] +=
123: microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_time' ];
124: }
125:
126: /**
127: * Start logging of render time
128: *
129: * @param \Smarty_Internal_Template $template
130: */
131: public function start_render(Smarty_Internal_Template $template)
132: {
133: $key = $this->get_key($template);
134: $this->template_data[ $this->index ][ $key ][ 'start_time' ] = microtime(true);
135: }
136:
137: /**
138: * End logging of compile time
139: *
140: * @param \Smarty_Internal_Template $template
141: */
142: public function end_render(Smarty_Internal_Template $template)
143: {
144: $key = $this->get_key($template);
145: $this->template_data[ $this->index ][ $key ][ 'render_time' ] +=
146: microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_time' ];
147: }
148:
149: /**
150: * Start logging of cache time
151: *
152: * @param \Smarty_Internal_Template $template cached template
153: */
154: public function start_cache(Smarty_Internal_Template $template)
155: {
156: $key = $this->get_key($template);
157: $this->template_data[ $this->index ][ $key ][ 'start_time' ] = microtime(true);
158: }
159:
160: /**
161: * End logging of cache time
162: *
163: * @param \Smarty_Internal_Template $template cached template
164: */
165: public function end_cache(Smarty_Internal_Template $template)
166: {
167: $key = $this->get_key($template);
168: $this->template_data[ $this->index ][ $key ][ 'cache_time' ] +=
169: microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_time' ];
170: }
171:
172: /**
173: * Register template object
174: *
175: * @param \Smarty_Internal_Template $template cached template
176: */
177: public function register_template(Smarty_Internal_Template $template)
178: {
179: }
180:
181: /**
182: * Register data object
183: *
184: * @param \Smarty_Data $data data object
185: */
186: public static function register_data(Smarty_Data $data)
187: {
188: }
189:
190: /**
191: * Opens a window for the Smarty Debugging Console and display the data
192: *
193: * @param Smarty_Internal_Template|Smarty $obj object to debug
194: * @param bool $full
195: *
196: * @throws \Exception
197: * @throws \SmartyException
198: */
199: public function display_debug($obj, $full = false)
200: {
201: if (!$full) {
202: $this->offset++;
203: $savedIndex = $this->index;
204: $this->index = 9999;
205: }
206: $smarty = $obj->_getSmartyObj();
207: // create fresh instance of smarty for displaying the debug console
208: // to avoid problems if the application did overload the Smarty class
209: $debObj = new Smarty();
210: // copy the working dirs from application
211: $debObj->setCompileDir($smarty->getCompileDir());
212: // init properties by hand as user may have edited the original Smarty class
213: $debObj->setPluginsDir(is_dir(dirname(__FILE__) . '/../plugins') ? dirname(__FILE__) .
214: '/../plugins' : $smarty->getPluginsDir());
215: $debObj->force_compile = false;
216: $debObj->compile_check = Smarty::COMPILECHECK_ON;
217: $debObj->left_delimiter = '{';
218: $debObj->right_delimiter = '}';
219: $debObj->security_policy = null;
220: $debObj->debugging = false;
221: $debObj->debugging_ctrl = 'NONE';
222: $debObj->error_reporting = E_ALL & ~E_NOTICE;
223: $debObj->debug_tpl =
224: isset($smarty->debug_tpl) ? $smarty->debug_tpl : 'file:' . dirname(__FILE__) . '/../debug.tpl';
225: $debObj->registered_plugins = array();
226: $debObj->registered_resources = array();
227: $debObj->registered_filters = array();
228: $debObj->autoload_filters = array();
229: $debObj->default_modifiers = array();
230: $debObj->escape_html = true;
231: $debObj->caching = Smarty::CACHING_OFF;
232: $debObj->compile_id = null;
233: $debObj->cache_id = null;
234: // prepare information of assigned variables
235: $ptr = $this->get_debug_vars($obj);
236: $_assigned_vars = $ptr->tpl_vars;
237: ksort($_assigned_vars);
238: $_config_vars = $ptr->config_vars;
239: ksort($_config_vars);
240: $debugging = $smarty->debugging;
241: $_template = new Smarty_Internal_Template($debObj->debug_tpl, $debObj);
242: if ($obj->_isTplObj()) {
243: $_template->assign('template_name', $obj->source->type . ':' . $obj->source->name);
244: }
245: if ($obj->_objType === 1 || $full) {
246: $_template->assign('template_data', $this->template_data[ $this->index ]);
247: } else {
248: $_template->assign('template_data', null);
249: }
250: $_template->assign('assigned_vars', $_assigned_vars);
251: $_template->assign('config_vars', $_config_vars);
252: $_template->assign('execution_time', microtime(true) - $smarty->start_time);
253: $_template->assign('display_mode', $debugging === 2 || !$full);
254: $_template->assign('offset', $this->offset * 50);
255: echo $_template->fetch();
256: if (isset($full)) {
257: $this->index--;
258: }
259: if (!$full) {
260: $this->index = $savedIndex;
261: }
262: }
263:
264: /**
265: * Recursively gets variables from all template/data scopes
266: *
267: * @param Smarty_Internal_Template|Smarty_Data $obj object to debug
268: *
269: * @return StdClass
270: */
271: public function get_debug_vars($obj)
272: {
273: $config_vars = array();
274: foreach ($obj->config_vars as $key => $var) {
275: $config_vars[ $key ][ 'value' ] = $var;
276: if ($obj->_isTplObj()) {
277: $config_vars[ $key ][ 'scope' ] = $obj->source->type . ':' . $obj->source->name;
278: } elseif ($obj->_isDataObj()) {
279: $tpl_vars[ $key ][ 'scope' ] = $obj->dataObjectName;
280: } else {
281: $config_vars[ $key ][ 'scope' ] = 'Smarty object';
282: }
283: }
284: $tpl_vars = array();
285: foreach ($obj->tpl_vars as $key => $var) {
286: foreach ($var as $varkey => $varvalue) {
287: if ($varkey === 'value') {
288: $tpl_vars[ $key ][ $varkey ] = $varvalue;
289: } else {
290: if ($varkey === 'nocache') {
291: if ($varvalue === true) {
292: $tpl_vars[ $key ][ $varkey ] = $varvalue;
293: }
294: } else {
295: if ($varkey !== 'scope' || $varvalue !== 0) {
296: $tpl_vars[ $key ][ 'attributes' ][ $varkey ] = $varvalue;
297: }
298: }
299: }
300: }
301: if ($obj->_isTplObj()) {
302: $tpl_vars[ $key ][ 'scope' ] = $obj->source->type . ':' . $obj->source->name;
303: } elseif ($obj->_isDataObj()) {
304: $tpl_vars[ $key ][ 'scope' ] = $obj->dataObjectName;
305: } else {
306: $tpl_vars[ $key ][ 'scope' ] = 'Smarty object';
307: }
308: }
309: if (isset($obj->parent)) {
310: $parent = $this->get_debug_vars($obj->parent);
311: foreach ($parent->tpl_vars as $name => $pvar) {
312: if (isset($tpl_vars[ $name ]) && $tpl_vars[ $name ][ 'value' ] === $pvar[ 'value' ]) {
313: $tpl_vars[ $name ][ 'scope' ] = $pvar[ 'scope' ];
314: }
315: }
316: $tpl_vars = array_merge($parent->tpl_vars, $tpl_vars);
317: foreach ($parent->config_vars as $name => $pvar) {
318: if (isset($config_vars[ $name ]) && $config_vars[ $name ][ 'value' ] === $pvar[ 'value' ]) {
319: $config_vars[ $name ][ 'scope' ] = $pvar[ 'scope' ];
320: }
321: }
322: $config_vars = array_merge($parent->config_vars, $config_vars);
323: } else {
324: foreach (Smarty::$global_tpl_vars as $key => $var) {
325: if (!array_key_exists($key, $tpl_vars)) {
326: foreach ($var as $varkey => $varvalue) {
327: if ($varkey === 'value') {
328: $tpl_vars[ $key ][ $varkey ] = $varvalue;
329: } else {
330: if ($varkey === 'nocache') {
331: if ($varvalue === true) {
332: $tpl_vars[ $key ][ $varkey ] = $varvalue;
333: }
334: } else {
335: if ($varkey !== 'scope' || $varvalue !== 0) {
336: $tpl_vars[ $key ][ 'attributes' ][ $varkey ] = $varvalue;
337: }
338: }
339: }
340: }
341: $tpl_vars[ $key ][ 'scope' ] = 'Global';
342: }
343: }
344: }
345: return (object)array('tpl_vars' => $tpl_vars, 'config_vars' => $config_vars);
346: }
347:
348: /**
349: * Return key into $template_data for template
350: *
351: * @param \Smarty_Internal_Template $template template object
352: *
353: * @return string key into $template_data
354: */
355: private function get_key(Smarty_Internal_Template $template)
356: {
357: static $_is_stringy = array('string' => true, 'eval' => true);
358: // calculate Uid if not already done
359: if ($template->source->uid === '') {
360: $template->source->filepath;
361: }
362: $key = $template->source->uid;
363: if (isset($this->template_data[ $this->index ][ $key ])) {
364: return $key;
365: } else {
366: if (isset($_is_stringy[ $template->source->type ])) {
367: $this->template_data[ $this->index ][ $key ][ 'name' ] =
368: '\'' . substr($template->source->name, 0, 25) . '...\'';
369: } else {
370: $this->template_data[ $this->index ][ $key ][ 'name' ] = $template->source->filepath;
371: }
372: $this->template_data[ $this->index ][ $key ][ 'compile_time' ] = 0;
373: $this->template_data[ $this->index ][ $key ][ 'render_time' ] = 0;
374: $this->template_data[ $this->index ][ $key ][ 'cache_time' ] = 0;
375: $this->template_data[ $this->index ][ $key ][ 'total_time' ] = 0;
376: return $key;
377: }
378: }
379:
380: /**
381: * Ignore template
382: *
383: * @param \Smarty_Internal_Template $template
384: */
385: public function ignore(Smarty_Internal_Template $template)
386: {
387: // calculate Uid if not already done
388: if ($template->source->uid === '') {
389: $template->source->filepath;
390: }
391: $this->ignore_uid[ $template->source->uid ] = true;
392: }
393:
394: /**
395: * handle 'URL' debugging mode
396: *
397: * @param Smarty $smarty
398: */
399: public function debugUrl(Smarty $smarty)
400: {
401: if (isset($_SERVER[ 'QUERY_STRING' ])) {
402: $_query_string = $_SERVER[ 'QUERY_STRING' ];
403: } else {
404: $_query_string = '';
405: }
406: if (false !== strpos($_query_string, $smarty->smarty_debug_id)) {
407: if (false !== strpos($_query_string, $smarty->smarty_debug_id . '=on')) {
408: // enable debugging for this browser session
409: setcookie('SMARTY_DEBUG', true);
410: $smarty->debugging = true;
411: } elseif (false !== strpos($_query_string, $smarty->smarty_debug_id . '=off')) {
412: // disable debugging for this browser session
413: setcookie('SMARTY_DEBUG', false);
414: $smarty->debugging = false;
415: } else {
416: // enable debugging for this page
417: $smarty->debugging = true;
418: }
419: } else {
420: if (isset($_COOKIE[ 'SMARTY_DEBUG' ])) {
421: $smarty->debugging = true;
422: }
423: }
424: }
425: }
426: