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 121 $key = $this->get_key($template); 122 } 123 $this->template_data[ $this->index ][ $key ][ 'compile_time' ] += 124 microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_time' ]; 125 } 126 127 /** 128 * Start logging of render time 129 * 130 * @param \Smarty_Internal_Template $template 131 */ 132 public function start_render(Smarty_Internal_Template $template) 133 { 134 $key = $this->get_key($template); 135 $this->template_data[ $this->index ][ $key ][ 'start_time' ] = microtime(true); 136 } 137 138 /** 139 * End logging of compile time 140 * 141 * @param \Smarty_Internal_Template $template 142 */ 143 public function end_render(Smarty_Internal_Template $template) 144 { 145 $key = $this->get_key($template); 146 $this->template_data[ $this->index ][ $key ][ 'render_time' ] += 147 microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_time' ]; 148 } 149 150 /** 151 * Start logging of cache time 152 * 153 * @param \Smarty_Internal_Template $template cached template 154 */ 155 public function start_cache(Smarty_Internal_Template $template) 156 { 157 $key = $this->get_key($template); 158 $this->template_data[ $this->index ][ $key ][ 'start_time' ] = microtime(true); 159 } 160 161 /** 162 * End logging of cache time 163 * 164 * @param \Smarty_Internal_Template $template cached template 165 */ 166 public function end_cache(Smarty_Internal_Template $template) 167 { 168 $key = $this->get_key($template); 169 $this->template_data[ $this->index ][ $key ][ 'cache_time' ] += 170 microtime(true) - $this->template_data[ $this->index ][ $key ][ 'start_time' ]; 171 } 172 173 /** 174 * Register template object 175 * 176 * @param \Smarty_Internal_Template $template cached template 177 */ 178 public function register_template(Smarty_Internal_Template $template) 179 { 180 } 181 182 /** 183 * Register data object 184 * 185 * @param \Smarty_Data $data data object 186 */ 187 public static function register_data(Smarty_Data $data) 188 { 189 } 190 191 /** 192 * Opens a window for the Smarty Debugging Console and display the data 193 * 194 * @param Smarty_Internal_Template|Smarty $obj object to debug 195 * @param bool $full 196 */ 197 public function display_debug($obj, $full = false) 198 { 199 if (!$full) { 200 $this->offset ++; 201 $savedIndex = $this->index; 202 $this->index = 9999; 203 } 204 $smarty = $obj->_getSmartyObj(); 205 // create fresh instance of smarty for displaying the debug console 206 // to avoid problems if the application did overload the Smarty class 207 $debObj = new Smarty(); 208 // copy the working dirs from application 209 $debObj->setCompileDir($smarty->getCompileDir()); 210 // init properties by hand as user may have edited the original Smarty class 211 $debObj->setPluginsDir(is_dir(__DIR__ . '/../plugins') ? __DIR__ . '/../plugins' : $smarty->getPluginsDir()); 212 $debObj->force_compile = false; 213 $debObj->compile_check = true; 214 $debObj->left_delimiter = '{'; 215 $debObj->right_delimiter = '}'; 216 $debObj->security_policy = null; 217 $debObj->debugging = false; 218 $debObj->debugging_ctrl = 'NONE'; 219 $debObj->error_reporting = E_ALL & ~E_NOTICE; 220 $debObj->debug_tpl = isset($smarty->debug_tpl) ? $smarty->debug_tpl : 'file:' . __DIR__ . '/../debug.tpl'; 221 $debObj->registered_plugins = array(); 222 $debObj->registered_resources = array(); 223 $debObj->registered_filters = array(); 224 $debObj->autoload_filters = array(); 225 $debObj->default_modifiers = array(); 226 $debObj->escape_html = true; 227 $debObj->caching = false; 228 $debObj->compile_id = null; 229 $debObj->cache_id = null; 230 // prepare information of assigned variables 231 $ptr = $this->get_debug_vars($obj); 232 $_assigned_vars = $ptr->tpl_vars; 233 ksort($_assigned_vars); 234 $_config_vars = $ptr->config_vars; 235 ksort($_config_vars); 236 $debugging = $smarty->debugging; 237 238 $_template = new Smarty_Internal_Template($debObj->debug_tpl, $debObj); 239 if ($obj->_isTplObj()) { 240 $_template->assign('template_name', $obj->source->type . ':' . $obj->source->name); 241 } 242 if ($obj->_objType == 1 || $full) { 243 $_template->assign('template_data', $this->template_data[ $this->index ]); 244 } else { 245 $_template->assign('template_data', null); 246 } 247 $_template->assign('assigned_vars', $_assigned_vars); 248 $_template->assign('config_vars', $_config_vars); 249 $_template->assign('execution_time', microtime(true) - $smarty->start_time); 250 $_template->assign('display_mode', $debugging == 2 || !$full); 251 $_template->assign('offset', $this->offset * 50); 252 echo $_template->fetch(); 253 if (isset($full)) { 254 $this->index --; 255 } 256 if (!$full) { 257 $this->index = $savedIndex; 258 } 259 } 260 261 /** 262 * Recursively gets variables from all template/data scopes 263 * 264 * @param Smarty_Internal_Template|Smarty_Data $obj object to debug 265 * 266 * @return StdClass 267 */ 268 public function get_debug_vars($obj) 269 { 270 $config_vars = array(); 271 foreach ($obj->config_vars as $key => $var) { 272 $config_vars[ $key ][ 'value' ] = $var; 273 if ($obj->_isTplObj()) { 274 $config_vars[ $key ][ 'scope' ] = $obj->source->type . ':' . $obj->source->name; 275 } elseif ($obj->_isDataObj()) { 276 $tpl_vars[ $key ][ 'scope' ] = $obj->dataObjectName; 277 } else { 278 $config_vars[ $key ][ 'scope' ] = 'Smarty object'; 279 } 280 } 281 $tpl_vars = array(); 282 foreach ($obj->tpl_vars as $key => $var) { 283 foreach ($var as $varkey => $varvalue) { 284 if ($varkey == 'value') { 285 $tpl_vars[ $key ][ $varkey ] = $varvalue; 286 } else { 287 if ($varkey == 'nocache') { 288 if ($varvalue == true) { 289 $tpl_vars[ $key ][ $varkey ] = $varvalue; 290 } 291 } else { 292 if ($varkey != 'scope' || $varvalue !== 0) { 293 $tpl_vars[ $key ][ 'attributes' ][ $varkey ] = $varvalue; 294 } 295 } 296 } 297 } 298 if ($obj->_isTplObj()) { 299 $tpl_vars[ $key ][ 'scope' ] = $obj->source->type . ':' . $obj->source->name; 300 } elseif ($obj->_isDataObj()) { 301 $tpl_vars[ $key ][ 'scope' ] = $obj->dataObjectName; 302 } else { 303 $tpl_vars[ $key ][ 'scope' ] = 'Smarty object'; 304 } 305 } 306 307 if (isset($obj->parent)) { 308 $parent = $this->get_debug_vars($obj->parent); 309 foreach ($parent->tpl_vars as $name => $pvar) { 310 if (isset($tpl_vars[ $name ]) && $tpl_vars[ $name ][ 'value' ] === $pvar[ 'value' ]) { 311 $tpl_vars[ $name ][ 'scope' ] = $pvar[ 'scope' ]; 312 } 313 } 314 $tpl_vars = array_merge($parent->tpl_vars, $tpl_vars); 315 316 foreach ($parent->config_vars as $name => $pvar) { 317 if (isset($config_vars[ $name ]) && $config_vars[ $name ][ 'value' ] === $pvar[ 'value' ]) { 318 $config_vars[ $name ][ 'scope' ] = $pvar[ 'scope' ]; 319 } 320 } 321 $config_vars = array_merge($parent->config_vars, $config_vars); 322 } else { 323 foreach (Smarty::$global_tpl_vars as $key => $var) { 324 if (!array_key_exists($key, $tpl_vars)) { 325 foreach ($var as $varkey => $varvalue) { 326 if ($varkey == 'value') { 327 $tpl_vars[ $key ][ $varkey ] = $varvalue; 328 } else { 329 if ($varkey == 'nocache') { 330 if ($varvalue == true) { 331 $tpl_vars[ $key ][ $varkey ] = $varvalue; 332 } 333 } else { 334 if ($varkey != 'scope' || $varvalue !== 0) { 335 $tpl_vars[ $key ][ 'attributes' ][ $varkey ] = $varvalue; 336 } 337 } 338 } 339 } 340 $tpl_vars[ $key ][ 'scope' ] = 'Global'; 341 } 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 377 return $key; 378 } 379 } 380 381 /** 382 * Ignore template 383 * 384 * @param \Smarty_Internal_Template $template 385 */ 386 public function ignore(Smarty_Internal_Template $template) 387 { 388 // calculate Uid if not already done 389 if ($template->source->uid == '') { 390 $template->source->filepath; 391 } 392 $this->ignore_uid[ $template->source->uid ] = true; 393 } 394 395 /** 396 * handle 'URL' debugging mode 397 * 398 * @param Smarty $smarty 399 */ 400 public function debugUrl(Smarty $smarty) 401 { 402 if (isset($_SERVER[ 'QUERY_STRING' ])) { 403 $_query_string = $_SERVER[ 'QUERY_STRING' ]; 404 } else { 405 $_query_string = ''; 406 } 407 if (false !== strpos($_query_string, $smarty->smarty_debug_id)) { 408 if (false !== strpos($_query_string, $smarty->smarty_debug_id . '=on')) { 409 // enable debugging for this browser session 410 setcookie('SMARTY_DEBUG', true); 411 $smarty->debugging = true; 412 } elseif (false !== strpos($_query_string, $smarty->smarty_debug_id . '=off')) { 413 // disable debugging for this browser session 414 setcookie('SMARTY_DEBUG', false); 415 $smarty->debugging = false; 416 } else { 417 // enable debugging for this page 418 $smarty->debugging = true; 419 } 420 } else { 421 if (isset($_COOKIE[ 'SMARTY_DEBUG' ])) { 422 $smarty->debugging = true; 423 } 424 } 425 } 426} 427