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 */ 17class 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