Development

/branches/1.0/lib/debug/sfWebDebug.class.php

You must first sign up to be able to contribute.

root/branches/1.0/lib/debug/sfWebDebug.class.php

Revision 8090, 16.3 kB (checked in by fabien, 6 years ago)

fixed sfWebDebug 'cache information' link

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Rev Date
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * sfWebDebug creates debug information for easy debugging in the browser.
13  *
14  * @package    symfony
15  * @subpackage debug
16  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
17  * @version    SVN: $Id$
18  */
19 class sfWebDebug
20 {
21   protected
22     $log             = array(),
23     $short_log       = array(),
24     $max_priority    = 1000,
25     $types           = array(),
26     $last_time_log   = -1;
27
28   protected static
29     $instance        = null;
30
31   public function initialize()
32   {
33   }
34
35   /**
36    * Retrieves the singleton instance of this class.
37    *
38    * @return sfWebDebug A sfWebDebug implementation instance
39    */
40   public static function getInstance()
41   {
42     if (!isset(self::$instance))
43     {
44       $class = __CLASS__;
45       self::$instance = new $class();
46       self::$instance->initialize();
47     }
48
49     return self::$instance;
50   }
51
52   /**
53    * Registers javascripts and stylesheets needed for the web debug toolbar.
54    */
55   public function registerAssets()
56   {
57     $response = sfContext::getInstance()->getResponse();
58
59     // register our css and js
60     $response->addJavascript(sfConfig::get('sf_web_debug_web_dir').'/js/main');
61     $response->addStylesheet(sfConfig::get('sf_web_debug_web_dir').'/css/main');
62   }
63
64   /**
65    * Logs a short message to be displayed in the web debug toolbar.
66    *
67    * @param string The message string
68    */
69   public function logShortMessage($message)
70   {
71     $this->short_log[] = $message;
72   }
73
74   /**
75    * Logs a message to the web debug toolbar.
76    *
77    * @param array An array of parameter
78    *
79    * @see sfWebDebugLogger
80    */
81   public function log($logEntry)
82   {
83     // elapsed time
84     if ($this->last_time_log == -1)
85     {
86       $this->last_time_log = sfConfig::get('sf_timer_start');
87     }
88
89     $this->last_time_log = microtime(true);
90
91     // update max priority
92     if ($logEntry['priority'] < $this->max_priority)
93     {
94       $this->max_priority = $logEntry['priority'];
95     }
96
97     // update types
98     if (!isset($this->types[$logEntry['type']]))
99     {
100       $this->types[$logEntry['type']] = 1;
101     }
102     else
103     {
104       ++$this->types[$logEntry['type']];
105     }
106
107     $this->log[] = $logEntry;
108   }
109
110   /**
111    * Loads helpers needed for the web debug toolbar.
112    */
113   protected function loadHelpers()
114   {
115     sfLoader::loadHelpers(array('Helper', 'Url', 'Asset', 'Tag'));
116   }
117
118   /**
119    * Formats a log line.
120    *
121    * @param string The log line to format
122    *
123    * @return string The formatted log lin
124    */
125   protected function formatLogLine($log_line)
126   {
127     static $constants;
128
129     if (!$constants)
130     {
131       foreach (array('sf_app_dir', 'sf_root_dir', 'sf_symfony_lib_dir', 'sf_symfony_data_dir') as $constant)
132       {
133         $constants[realpath(sfConfig::get($constant)).DIRECTORY_SEPARATOR] = $constant.DIRECTORY_SEPARATOR;
134       }
135     }
136
137     // escape HTML
138     $log_line = htmlentities($log_line, ENT_QUOTES, sfConfig::get('sf_charset'));
139
140     // replace constants value with constant name
141     $log_line = str_replace(array_keys($constants), array_values($constants), $log_line);
142
143     $log_line = sfToolkit::pregtr($log_line, array('/&quot;(.+?)&quot;/s' => '"<span class="sfWebDebugLogInfo">\\1</span>"',
144                                                    '/^(.+?)\(\)\:/S'      => '<span class="sfWebDebugLogInfo">\\1()</span>:',
145                                                    '/line (\d+)$/'        => 'line <span class="sfWebDebugLogInfo">\\1</span>'));
146
147     // special formatting for SQL lines
148     $log_line = preg_replace('/\b(SELECT|FROM|AS|LIMIT|ASC|COUNT|DESC|WHERE|LEFT JOIN|INNER JOIN|RIGHT JOIN|ORDER BY|GROUP BY|IN|LIKE|DISTINCT|DELETE|INSERT|INTO|VALUES)\b/', '<span class="sfWebDebugLogInfo">\\1</span>', $log_line);
149
150     // remove username/password from DSN
151     if (strpos($log_line, 'DSN') !== false)
152     {
153       $log_line = preg_replace("/=&gt;\s+'?[^'\s,]+'?/", "=&gt; '****'", $log_line);
154     }
155
156     return $log_line;
157   }
158
159   /**
160    * Returns the web debug toolbar as HTML.
161    *
162    * @return string The web debug toolbar HTML
163    */
164   public function getResults()
165   {
166     if (!sfConfig::get('sf_web_debug'))
167     {
168       return '';
169     }
170
171     $this->loadHelpers();
172
173     $result = '';
174
175     // max priority
176     $max_priority = '';
177     if (sfConfig::get('sf_logging_enabled'))
178     {
179       $max_priority = $this->getPriority($this->max_priority);
180     }
181
182     $logs = '';
183     $sql_logs = array();
184     if (sfConfig::get('sf_logging_enabled'))
185     {
186       $logs = '<table class="sfWebDebugLogs">
187         <tr>
188           <th>#</th>
189           <th>type</th>
190           <th>message</th>
191         </tr>'."\n";
192       $line_nb = 0;
193       foreach ($this->log as $logEntry)
194       {
195         $log = $logEntry['message'];
196
197         $priority = $this->getPriority($logEntry['priority']);
198
199         if (strpos($type = $logEntry['type'], 'sf') === 0)
200         {
201           $type = substr($type, 2);
202         }
203
204         // xdebug information
205         $debug_info = '';
206         if ($logEntry['debugStack'])
207         {
208           $debug_info .= '&nbsp;<a href="#" onclick="sfWebDebugToggle(\'debug_'.$line_nb.'\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/toggle.gif').'</a><div class="sfWebDebugDebugInfo" id="debug_'.$line_nb.'" style="display:none">';
209           foreach ($logEntry['debugStack'] as $i => $log_line)
210           {
211             $debug_info .= '#'.$i.' &raquo; '.$this->formatLogLine($log_line).'<br/>';
212           }
213           $debug_info .= "</div>\n";
214         }
215
216         // format log
217         $log = $this->formatLogLine($log);
218
219         // sql queries log
220         if (preg_match('/execute(?:Query|Update).+?\:\s+(.+)$/', $log, $match))
221         {
222           $sql_logs[] .= $match[1];
223         }
224
225         ++$line_nb;
226         $logs .= sprintf("<tr class='sfWebDebugLogLine sfWebDebug%s %s'><td class=\"sfWebDebugLogNumber\">%s</td><td class=\"sfWebDebugLogType\">%s&nbsp;%s</td><td>%s%s</td></tr>\n",
227           ucfirst($priority),
228           $logEntry['type'],
229           $line_nb,
230           image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/'.$priority.'.png'),
231           $type,
232           $log,
233           $debug_info
234         );
235       }
236       $logs .= '</table>';
237
238       ksort($this->types);
239       $types = array();
240       foreach ($this->types as $type => $nb)
241       {
242         $types[] = '<a href="#" onclick="sfWebDebugToggleMessages(\''.$type.'\'); return false;">'.$type.'</a>';
243       }
244     }
245
246     // ignore cache link
247     $cacheLink = '';
248     if (sfConfig::get('sf_debug') && sfConfig::get('sf_cache'))
249     {
250       $self_url = $_SERVER['PHP_SELF'].((strpos($_SERVER['PHP_SELF'], '_sf_ignore_cache') === false) ? '?_sf_ignore_cache=1' : '');
251       $cacheLink = '<li><a href="'.$self_url.'" title="reload and ignore cache">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/reload.png').'</a></li>';
252     }
253
254     // logging information
255     $logLink = '';
256     if (sfConfig::get('sf_logging_enabled'))
257     {
258       $logLink = '<li><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugLog\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/comment.png').' logs &amp; msgs</a></li>';
259     }
260
261     // database information
262     $dbInfo = '';
263     $dbInfoDetails = '';
264     if ($sql_logs)
265     {
266       $dbInfo = '<li><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugDatabaseDetails\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/database.png').' '.count($sql_logs).'</a></li>';
267
268       $dbInfoDetails = '
269         <div id="sfWebDebugDatabaseLogs">
270         <ol><li>'.implode("</li>\n<li>", $sql_logs).'</li></ol>
271         </div>
272       ';
273     }
274
275     // memory used
276     $memoryInfo = '';
277     if (sfConfig::get('sf_debug') && function_exists('memory_get_usage'))
278     {
279       $total_memory = sprintf('%.1f', (memory_get_usage() / 1024));
280       $memoryInfo = '<li>'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/memory.png').' '.$total_memory.' KB</li>';
281     }
282
283     // total time elapsed
284     $timeInfo = '';
285     if (sfConfig::get('sf_debug'))
286     {
287       $total_time = (microtime(true) - sfConfig::get('sf_timer_start')) * 1000;
288       $total_time = sprintf(($total_time <= 1) ? '%.2f' : '%.0f', $total_time);
289       $timeInfo = '<li class="last"><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugTimeDetails\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/time.png').' '.$total_time.' ms</a></li>';
290     }
291
292     // timers
293     $timeInfoDetails = '<table class="sfWebDebugLogs" style="width: 300px"><tr><th>type</th><th>calls</th><th>time (ms)</th></tr>';
294     foreach (sfTimerManager::getTimers() as $name => $timer)
295     {
296       $timeInfoDetails .= sprintf('<tr><td class="sfWebDebugLogType">%s</td><td class="sfWebDebugLogNumber" style="text-align: right">%d</td><td style="text-align: right">%.2f</td></tr>', $name, $timer->getCalls(), $timer->getElapsedTime() * 1000);
297     }
298     $timeInfoDetails .= '</table>';
299
300     // short log messages
301     $short_messages = '';
302     if ($this->short_log)
303     {
304       $short_messages = '<ul id="sfWebDebugShortMessages"><li>&raquo;&nbsp;'.implode('</li><li>&raquo&nbsp;', $this->short_log).'</li></ul>';
305     }
306
307     // logs
308     $logInfo = '';
309     if (sfConfig::get('sf_logging_enabled'))
310     {
311       $logInfo .= $short_messages.'
312         <ul id="sfWebDebugLogMenu">
313           <li><a href="#" onclick="sfWebDebugToggleAllLogLines(true, \'sfWebDebugLogLine\'); return false;">[all]</a></li>
314           <li><a href="#" onclick="sfWebDebugToggleAllLogLines(false, \'sfWebDebugLogLine\'); return false;">[none]</a></li>
315           <li><a href="#" onclick="sfWebDebugShowOnlyLogLines(\'info\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/info.png').'</a></li>
316           <li><a href="#" onclick="sfWebDebugShowOnlyLogLines(\'warning\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/warning.png').'</a></li>
317           <li><a href="#" onclick="sfWebDebugShowOnlyLogLines(\'error\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/error.png').'</a></li>
318           <li>'.implode("</li>\n<li>", $types).'</li>
319         </ul>
320         <div id="sfWebDebugLogLines">'.$logs.'</div>
321       ';
322     }
323
324     $result .= '
325     <div id="sfWebDebug">
326       <div id="sfWebDebugBar" class="sfWebDebug'.ucfirst($max_priority).'">
327         <a href="#" onclick="sfWebDebugToggleMenu(); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/sf.png').'</a>
328         <ul id="sfWebDebugDetails" class="menu">
329           <li>'.file_get_contents(sfConfig::get('sf_symfony_lib_dir').'/VERSION').'</li>
330           <li><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugConfig\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/config.png').' vars &amp; config</a></li>
331           '.$cacheLink.'
332           '.$logLink.'
333           '.$dbInfo.'
334           '.$memoryInfo.'
335           '.$timeInfo.'
336         </ul>
337         <a href="#" onclick="document.getElementById(\'sfWebDebug\').style.display=\'none\'; return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/close.png').'</a>
338       </div>
339
340       <div id="sfWebDebugLog" class="sfWebDebugTop" style="display: none"><h1>Log and debug messages</h1>'.$logInfo.'</div>
341       <div id="sfWebDebugConfig" class="sfWebDebugTop" style="display: none"><h1>Configuration and request variables</h1>'.$this->getCurrentConfigAsHtml().'</div>
342       <div id="sfWebDebugDatabaseDetails" class="sfWebDebugTop" style="display: none"><h1>SQL queries</h1>'.$dbInfoDetails.'</div>
343       <div id="sfWebDebugTimeDetails" class="sfWebDebugTop" style="display: none"><h1>Timers</h1>'.$timeInfoDetails.'</div>
344
345       </div>
346     ';
347
348     return $result;
349   }
350
351   /**
352    * Returns the current configuration as HTML.
353    *
354    * @return string The current configuration as HTML
355    */
356   protected function getCurrentConfigAsHtml()
357   {
358     $config = array(
359       'debug'        => sfConfig::get('sf_debug')             ? 'on' : 'off',
360       'xdebug'       => (extension_loaded('xdebug'))          ? 'on' : 'off',
361       'logging'      => sfConfig::get('sf_logging_enabled')   ? 'on' : 'off',
362       'cache'        => sfConfig::get('sf_cache')             ? 'on' : 'off',
363       'eaccelerator' => (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) ? 'on' : 'off',
364       'apc'          => (extension_loaded('apc') && ini_get('apc.enabled')) ? 'on' : 'off',
365       'xcache'       => (extension_loaded('xcache') && ini_get('xcache.cacher')) ? 'on' : 'off',
366       'compression'  => sfConfig::get('sf_compressed')        ? 'on' : 'off',
367       'syck'         => (extension_loaded('syck'))            ? 'on' : 'off',
368     );
369
370     $result = '<ul id="sfWebDebugConfigSummary">';
371     foreach ($config as $key => $value)
372     {
373       $result .= '<li class="is'.$value.''.($key == 'syck' ? ' last' : '').'">'.$key.'</li>';
374     }
375     $result .= '</ul>';
376
377     $context = sfContext::getInstance();
378     $result .= $this->formatArrayAsHtml('request'sfDebug::requestAsArray($context->getRequest()));
379     $result .= $this->formatArrayAsHtml('response', sfDebug::responseAsArray($context->getResponse()));
380     $result .= $this->formatArrayAsHtml('settings', sfDebug::settingsAsArray());
381     $result .= $this->formatArrayAsHtml('globals'sfDebug::globalsAsArray());
382     $result .= $this->formatArrayAsHtml('php',      sfDebug::phpInfoAsArray());
383
384     return $result;
385   }
386
387   /**
388    * Converts an array to HTML.
389    *
390    * @param string The identifier to use
391    * @param array  The array of values
392    *
393    * @return string An HTML string
394    */
395   protected function formatArrayAsHtml($id, $values)
396   {
397     $id = ucfirst(strtolower($id));
398     $content = '
399     <h2>'.$id.' <a href="#" onclick="sfWebDebugToggle(\'sfWebDebug'.$id.'\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/toggle.gif').'</a></h2>
400     <div id="sfWebDebug'.$id.'" style="display: none"><pre>'.htmlentities(@sfYaml::dump($values), ENT_QUOTES, sfConfig::get('sf_charset')).'</pre></div>
401     ';
402
403     return $content;
404   }
405
406   /**
407    * Decorates a chunk of HTML with cache information.
408    *
409    * @param string  The internalUri representing the content
410    * @param string  The HTML content
411    * @param boolean true if the content is new in the cache, false otherwise
412    *
413    * @return string The decorated HTML string
414    */
415   public function decorateContentWithDebug($internalUri, $content, $new = false)
416   {
417     $context = sfContext::getInstance();
418
419     // don't decorate if not html or if content is null
420     if (!sfConfig::get('sf_web_debug') || !$content || false === strpos($context->getResponse()->getContentType(), 'html'))
421     {
422       return $content;
423     }
424
425     $cache = $context->getViewCacheManager();
426     $this->loadHelpers();
427
428     $bg_color      = $new ? '#9ff' : '#ff9';
429     $last_modified = $cache->lastModified($internalUri);
430     $id            = md5($internalUri);
431     $content = '
432       <div id="main_'.$id.'" class="sfWebDebugActionCache" style="border: 1px solid #f00">
433       <div id="sub_main_'.$id.'" class="sfWebDebugCache" style="background-color: '.$bg_color.'; border-right: 1px solid #f00; border-bottom: 1px solid #f00;">
434       <div style="height: 16px; padding: 2px"><a href="#" onclick="sfWebDebugToggle(\'sub_main_info_'.$id.'\'); return false;"><strong>cache information</strong></a>&nbsp;<a href="#" onclick="sfWebDebugToggle(\'sub_main_'.$id.'\'); document.getElementById(\'main_'.$id.'\').style.border = \'none\'; return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/close.png').'</a>&nbsp;</div>
435         <div style="padding: 2px; display: none" id="sub_main_info_'.$id.'">
436         [uri]&nbsp;'.htmlentities($internalUri, ENT_QUOTES, sfConfig::get('sf_charset')).'<br />
437         [life&nbsp;time]&nbsp;'.$cache->getLifeTime($internalUri).'&nbsp;seconds<br />
438         [last&nbsp;modified]&nbsp;'.(time() - $last_modified).'&nbsp;seconds<br />
439         &nbsp;<br />&nbsp;
440         </div>
441       </div><div>
442       '.$content.'
443       </div></div>
444     ';
445
446     return $content;
447   }
448
449   /**
450    * Converts a priority value to a string.
451    *
452    * @param integer The priority value
453    *
454    * @return string The priority as a string
455    */
456   protected function getPriority($value)
457   {
458     if ($value >= 6)
459     {
460       return 'info';
461     }
462     else if ($value >= 4)
463     {
464       return 'warning';
465     }
466     else
467     {
468       return 'error';
469     }
470   }
471 }
472
Note: See TracBrowser for help on using the browser.