debug-toolbar/classes/Kohana/Debugtoolbar.php

577 lines
12 KiB
PHP

<?php defined('SYSPATH') or die('No direct script access.');
/**
* Kohana v3 Debug Toolbar
*
* @package Debug Toolbar
* @author Aaron Forsander <http://grimhappy.com/>
* @author Ivan Brotkin (BIakaVeron) <BIakaVeron@gmail.com>
* @author Sergei Gladkovskiy <smgladkovskiy@gmail.com>
*/
abstract class Kohana_Debugtoolbar {
/**
* Queries container
*
* @var bool|array
*/
protected static $_queries = FALSE;
/**
* Benchmarks container
*
* @var bool|array
*/
protected static $_benchmarks = FALSE;
/**
* Custom tabs container
*
* @var array
*/
protected static $_custom_tabs = array();
protected static $_custom_sections = array();
/**
* Can we render toolbar?
*
* @var bool
*/
protected static $_enabled = TRUE;
/**
* Benchmark name
*
* @var string
*/
public static $benchmark_name = 'debug_toolbar';
/**
* Renders the Debug Toolbar
*
* @param bool $print return DT's template (FALSE, by default) or render it (TRUE)
*
* @static
* @return bool|string
*/
public static function render($print = FALSE)
{
if ( ! self::is_enabled())
{
return FALSE;
}
$token = Profiler::start('custom', self::$benchmark_name);
$template = new View('toolbar');
$config = Kohana::$config->load('debug_toolbar');
// Database panel
if ($config->panels['database'] === TRUE)
{
$queries = self::get_queries();
$template
->set('queries', $queries['data'])
->set('query_count', $queries['count'])
->set('total_time', $queries['time'])
->set('total_memory', $queries['memory']);
}
// Configs panel
if ($config->panels['configs'] === TRUE)
{
$template->set('configs', self::get_configs());
}
// Files panel
if ($config->panels['files'] === TRUE)
{
$template->set('files', self::get_files());
}
// Modules panel
if ($config->panels['modules'] === TRUE)
{
$template->set('modules', self::get_modules());
}
// Routes panel
if ($config->panels['routes'] === TRUE)
{
$template->set('routes', self::get_routes());
}
// Custom data
if ($config->panels['customs'] === TRUE)
{
$template->set('customs', self::get_customs());
$template->set('sections', self::get_custom_sections());
}
// FirePHP
if ($config->firephp_enabled === TRUE)
{
self::firephp();
}
Profiler::stop($token);
// Javascript for toolbar
$template->set('scripts', file_get_contents(Kohana::find_file('views', 'toolbar', 'js')));
// CSS for toolbar
if ($config->styles === TRUE)
{
$styles = file_get_contents(Kohana::find_file('views', 'toolbar', 'css'));
$template->set('styles', $styles);
}
// Benchmarks panel
if ($config->panels['benchmarks'] === TRUE)
{
$template->set('benchmarks', self::get_benchmarks());
}
$result = $template->render();
if ($print === TRUE)
{
echo $result;
}
else {
return $result;
}
}
/**
* Adds custom data to render in a separate tab
*
* @param string $tab_name
* @param mixed $data
*
* @return void
*/
public static function add_custom($tab_name, $data)
{
self::$_custom_tabs[$tab_name] = $data;
}
/**
* Register additional sections. Supports callbacks for title or content params
*
* @param mixed $title section title (string or callback)
* @param mixed $data section content (string or callback)
* @param string $logo @TODO not used
*/
public static function add_section($title, $data, $logo = NULL)
{
self::$_custom_sections[] = array($title, $data, $logo);
}
/**
* Get user vars
*
* @return array
*/
public static function get_customs()
{
$result = array();
foreach (self::$_custom_tabs as $tab => $data)
{
if (is_array($data) OR is_object($data) OR is_bool($data))
{
$data = Debug::dump($data);
}
$result[$tab] = $data;
}
return $result;
}
/**
* Get custom sections
*
* @return array
*/
public static function get_custom_sections()
{
$result = array();
foreach(self::$_custom_sections as $section)
{
list($title, $data, $logo) = $section;
if ( ! is_string($data) && is_callable($data))
{
$data = call_user_func($data);
}
$result[] = array(
'title' => ! is_string($title) && is_callable($title) ? call_user_func($title) : (string)$title,
'content' => is_string($data) ? $data : Debug::dump($data),
'logo' => $logo
);
}
return $result;
}
/**
* Retrieves query benchmarks from Database
*
* @return array
*/
public static function get_queries()
{
if (self::$_queries !== FALSE)
{
return self::$_queries;
}
$result = array();
$count = $time = $memory = 0;
$groups = Profiler::groups();
foreach (Database::$instances as $name => $db)
{
$group_name = 'database ('.strtolower($name).')';
$group = arr::get($groups, $group_name, FALSE);
if ($group)
{
$sub_time = $sub_memory = $sub_count = 0;
foreach ($group as $query => $tokens)
{
$sub_count += count($tokens);
foreach ($tokens as $token)
{
$total = Profiler::total($token);
$sub_time += $total[0];
$sub_memory += $total[1];
$result[$name][] = array(
'name' => $query,
'time' => $total[0],
'memory' => $total[1]
);
}
}
$count += $sub_count;
$time += $sub_time;
$memory += $sub_memory;
$result[$name]['total'] = array($sub_count, $sub_time, $sub_memory);
}
}
self::$_queries = array(
'count' => $count,
'time' => $time,
'memory' => $memory,
'data' => $result
);
return self::$_queries;
}
/**
* Creates a formatted array of all Benchmarks
*
* @return array formatted benchmarks
*/
public static function get_benchmarks()
{
if (Kohana::$profiling == FALSE)
{
return array();
}
if (self::$_benchmarks !== FALSE)
{
return self::$_benchmarks;
}
$groups = Profiler::groups();
$result = array();
foreach (array_keys($groups) as $group)
{
if (strpos($group, 'database (') === FALSE)
{
foreach ($groups[$group] as $name => $marks)
{
$stats = Profiler::stats($marks);
$result[$group][] = array
(
'name' => $name,
'count' => count($marks),
'total_time' => $stats['total']['time'],
'avg_time' => $stats['average']['time'],
'total_memory' => $stats['total']['memory'],
'avg_memory' => $stats['average']['memory'],
);
}
}
}
// add total stats
$total = Profiler::application();
$result['application'] = array
(
'count' => 1,
'total_time' => $total['current']['time'],
'avg_time' => $total['average']['time'],
'total_memory' => $total['current']['memory'],
'avg_memory' => $total['average']['memory'],
);
self::$_benchmarks = $result;
return $result;
}
/**
* Get list of included files
*
* @return array file currently included by php
*/
public static function get_files()
{
$files = (array)get_included_files();
sort($files);
return $files;
}
/**
* Get module list
*
* @return array module_name => module_path
*/
public static function get_modules()
{
return Kohana::modules();
}
/**
* Returns all application routes
*
* @return array
*/
public static function get_routes()
{
return Route::all();
}
/**
* Add toolbar data to FirePHP console
*
*/
private static function firephp()
{
$firephp = FirePHP::getInstance(TRUE);
$firephp->fb('KOHANA DEBUG TOOLBAR:');
// Globals
$globals = array(
'Post' => empty($_POST) ? array() : $_POST,
'Get' => empty($_GET) ? array() : $_GET,
'Cookie' => empty($_COOKIE) ? array() : $_COOKIE,
'Session' => empty($_SESSION) ? array() : $_SESSION
);
foreach ($globals as $name => $global)
{
$table = array();
$table[] = array($name, 'Value');
foreach ((array)$global as $key => $value)
{
if (is_object($value))
{
$value = get_class($value).' [object]';
}
$table[] = array($key, $value);
}
$message = "$name: ".count($global).' variables';
$firephp->fb(array($message, $table), FirePHP::TABLE);
}
// Database
$query_stats = self::get_queries();
$table = array();
$table[] = array(
'DB profile',
'SQL Statement',
'Time',
'Memory'
);
foreach ((array)$query_stats['data'] as $db => $queries)
{
unset($queries['total']);
foreach ($queries as $query)
{
$table[] = array(
$db,
str_replace("\n", ' ', $query['name']),
number_format($query['time'] * 1000, 3),
number_format($query['memory'] / 1024, 3),
);
}
}
$message = 'Queries: '.$query_stats['count'].' SQL queries took '.
number_format($query_stats['time'], 3).' seconds and '.$query_stats['memory'].' b';
$firephp->fb(array($message, $table), FirePHP::TABLE);
// Benchmarks
$groups = self::get_benchmarks();
// application benchmarks
$total = array_pop($groups);
$table = array();
$table[] = array(
'Group',
'Benchmark',
'Count',
'Time',
'Memory'
);
foreach ((array)$groups as $group => $benchmarks)
{
foreach ((array)$benchmarks as $name => $benchmark)
{
$table[] = array(
ucfirst($group),
ucwords($benchmark['name']),
number_format($benchmark['total_time'], 3).' s',
Text::bytes($benchmark['total_memory']),
);
}
}
$message = 'Application tooks '.number_format($total['total_time'], 3).' seconds and '.text::bytes($total['total_memory']).' memory';
$firephp->fb(array($message, $table), FirePHP::TABLE);
}
/**
* Collect (custom) configs
*
* @static
* @return array
*/
public static function get_configs()
{
$inc_paths = Kohana::include_paths();
// delete SYSPATH
array_pop($inc_paths);
$configs = array();
foreach ($inc_paths as $inc_path)
{
foreach ((array)glob($inc_path.'/config/*.php') as $filename)
{
$filename = pathinfo($filename, PATHINFO_FILENAME);
if (in_array($filename, (array)Kohana::$config->load('debug_toolbar.skip_configs'))) {
continue;
}
if ( ! isset($configs[$filename])) {
try {
$configs[$filename] = Kohana::$config->load($filename)->as_array();
}
catch (Exception $e)
{
$configs[$filename] = NULL;
}
}
}
}
ksort($configs);
return $configs;
}
/**
* Disable toolbar
* @static
*/
public static function disable()
{
self::$_enabled = FALSE;
}
/**
* Enable toolbar
* @static
*/
public static function enable()
{
self::$_enabled = TRUE;
}
/**
* Determines if all the conditions are correct to display the toolbar
* (pretty kludgy, I know)
*
* @static
* @return bool
*/
public static function is_enabled()
{
// disabled with Debugtoolbar::disable() call
if (self::$_enabled === FALSE) {
return FALSE;
}
$config = Kohana::$config->load('debug_toolbar');
// Auto render if secret key isset
if ($config->secret_key !== FALSE AND isset($_GET[$config->secret_key]))
{
return TRUE;
}
// Don't auto render when in PRODUCTION (this can obviously be
// overridden by the above secret key)
if (Kohana::$environment == Kohana::PRODUCTION)
{
return FALSE;
}
// Don't auto render toolbar for ajax requests
if (Request::initial() === NULL OR Request::initial()->is_ajax())
{
return FALSE;
}
// Don't auto render toolbar for cli requests
if (PHP_SAPI == 'cli')
{
return FALSE;
}
// Don't auto render toolbar if $_GET['debug'] = 'false'
if (isset($_GET['debug']) AND strtolower($_GET['debug']) == 'false')
{
return FALSE;
}
if ( ! empty($config->excluded_routes) && !is_null(Request::initial()->route()) && in_array(Route::name(Request::initial()->route()), $config->excluded_routes))
{
return FALSE;
}
return TRUE;
}
}