First Local Commit - After Clean up.
Signed-off-by: Rick Hays <rhays@haysgang.com>
This commit is contained in:
500
system/Debug/Exceptions.php
Normal file
500
system/Debug/Exceptions.php
Normal file
@@ -0,0 +1,500 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug;
|
||||
|
||||
use CodeIgniter\API\ResponseTrait;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\HTTP\Response;
|
||||
use Config\Paths;
|
||||
use function error_reporting;
|
||||
use ErrorException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Exceptions manager
|
||||
*/
|
||||
class Exceptions
|
||||
{
|
||||
|
||||
use ResponseTrait;
|
||||
|
||||
/**
|
||||
* Nesting level of the output buffering mechanism
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $ob_level;
|
||||
|
||||
/**
|
||||
* The path to the directory containing the
|
||||
* cli and html error view directories.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $viewPath;
|
||||
|
||||
/**
|
||||
* Config for debug exceptions.
|
||||
*
|
||||
* @var \Config\Exceptions
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The incoming request.
|
||||
*
|
||||
* @var \CodeIgniter\HTTP\IncomingRequest
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* The outgoing response.
|
||||
*
|
||||
* @var \CodeIgniter\HTTP\Response
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Config\Exceptions $config
|
||||
* @param \CodeIgniter\HTTP\IncomingRequest $request
|
||||
* @param \CodeIgniter\HTTP\Response $response
|
||||
*/
|
||||
public function __construct(\Config\Exceptions $config, IncomingRequest $request, Response $response)
|
||||
{
|
||||
$this->ob_level = ob_get_level();
|
||||
|
||||
$this->viewPath = rtrim($config->errorViewPath, '/ ') . '/';
|
||||
|
||||
$this->config = $config;
|
||||
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Responsible for registering the error, exception and shutdown
|
||||
* handling of our application.
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
//Set the Exception Handler
|
||||
set_exception_handler([$this, 'exceptionHandler']);
|
||||
|
||||
// Set the Error Handler
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
|
||||
// Set the handler for shutdown to catch Parse errors
|
||||
// Do we need this in PHP7?
|
||||
register_shutdown_function([$this, 'shutdownHandler']);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Catches any uncaught errors and exceptions, including most Fatal errors
|
||||
* (Yay PHP7!). Will log the error, display it if display_errors is on,
|
||||
* and fire an event that allows custom actions to be taken at this point.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
*/
|
||||
public function exceptionHandler(Throwable $exception)
|
||||
{
|
||||
$codes = $this->determineCodes($exception);
|
||||
$statusCode = $codes[0];
|
||||
$exitCode = $codes[1];
|
||||
|
||||
// Log it
|
||||
if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes))
|
||||
{
|
||||
log_message('critical', $exception->getMessage() . "\n{trace}", [
|
||||
'trace' => $exception->getTraceAsString(),
|
||||
]);
|
||||
}
|
||||
|
||||
if (! is_cli())
|
||||
{
|
||||
$this->response->setStatusCode($statusCode);
|
||||
$header = "HTTP/{$this->request->getProtocolVersion()} {$this->response->getStatusCode()} {$this->response->getReason()}";
|
||||
header($header, true, $statusCode);
|
||||
|
||||
if (strpos($this->request->getHeaderLine('accept'), 'text/html') === false)
|
||||
{
|
||||
$this->respond(ENVIRONMENT === 'development' ? $this->collectVars($exception, $statusCode) : '', $statusCode)->send();
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
$this->render($exception, $statusCode);
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Even in PHP7, some errors make it through to the errorHandler, so
|
||||
* convert these to Exceptions and let the exception handler log it and
|
||||
* display it.
|
||||
*
|
||||
* This seems to be primarily when a user triggers it with trigger_error().
|
||||
*
|
||||
* @param integer $severity
|
||||
* @param string $message
|
||||
* @param string|null $file
|
||||
* @param integer|null $line
|
||||
* @param null $context
|
||||
*
|
||||
* @throws \ErrorException
|
||||
*/
|
||||
public function errorHandler(int $severity, string $message, string $file = null, int $line = null, $context = null)
|
||||
{
|
||||
if (! (error_reporting() & $severity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert it to an exception and pass it along.
|
||||
throw new ErrorException($message, 0, $severity, $file, $line);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks to see if any errors have happened during shutdown that
|
||||
* need to be caught and handle them.
|
||||
*/
|
||||
public function shutdownHandler()
|
||||
{
|
||||
$error = error_get_last();
|
||||
|
||||
// If we've got an error that hasn't been displayed, then convert
|
||||
// it to an Exception and use the Exception handler to display it
|
||||
// to the user.
|
||||
if (! is_null($error))
|
||||
{
|
||||
// Fatal Error?
|
||||
if (in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]))
|
||||
{
|
||||
$this->exceptionHandler(new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines the view to display based on the exception thrown,
|
||||
* whether an HTTP or CLI request, etc.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
* @param string $template_path
|
||||
*
|
||||
* @return string The path and filename of the view file to use
|
||||
*/
|
||||
protected function determineView(Throwable $exception, string $template_path): string
|
||||
{
|
||||
// Production environments should have a custom exception file.
|
||||
$view = 'production.php';
|
||||
$template_path = rtrim($template_path, '/ ') . '/';
|
||||
|
||||
if (str_ireplace(['off', 'none', 'no', 'false', 'null'], '', ini_get('display_errors')))
|
||||
{
|
||||
$view = 'error_exception.php';
|
||||
}
|
||||
|
||||
// 404 Errors
|
||||
if ($exception instanceof PageNotFoundException)
|
||||
{
|
||||
return 'error_404.php';
|
||||
}
|
||||
|
||||
// Allow for custom views based upon the status code
|
||||
else if (is_file($template_path . 'error_' . $exception->getCode() . '.php'))
|
||||
{
|
||||
return 'error_' . $exception->getCode() . '.php';
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Given an exception and status code will display the error to the client.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
* @param integer $statusCode
|
||||
*/
|
||||
protected function render(Throwable $exception, int $statusCode)
|
||||
{
|
||||
// Determine directory with views
|
||||
$path = $this->viewPath;
|
||||
if (empty($path))
|
||||
{
|
||||
$paths = new Paths();
|
||||
$path = $paths->viewDirectory . '/errors/';
|
||||
}
|
||||
|
||||
$path = is_cli() ? $path . 'cli/' : $path . 'html/';
|
||||
|
||||
// Determine the vew
|
||||
$view = $this->determineView($exception, $path);
|
||||
|
||||
// Prepare the vars
|
||||
$vars = $this->collectVars($exception, $statusCode);
|
||||
extract($vars);
|
||||
|
||||
// Render it
|
||||
if (ob_get_level() > $this->ob_level + 1)
|
||||
{
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
ob_start();
|
||||
include($path . $view);
|
||||
$buffer = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo $buffer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gathers the variables that will be made available to the view.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
* @param integer $statusCode
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function collectVars(Throwable $exception, int $statusCode): array
|
||||
{
|
||||
return [
|
||||
'title' => get_class($exception),
|
||||
'type' => get_class($exception),
|
||||
'code' => $statusCode,
|
||||
'message' => $exception->getMessage() ?? '(null)',
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'trace' => $exception->getTrace(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the HTTP status code and the exit status code for this request.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function determineCodes(Throwable $exception): array
|
||||
{
|
||||
$statusCode = abs($exception->getCode());
|
||||
|
||||
if ($statusCode < 100 || $statusCode > 599)
|
||||
{
|
||||
$exitStatus = $statusCode + EXIT__AUTO_MIN; // 9 is EXIT__AUTO_MIN
|
||||
if ($exitStatus > EXIT__AUTO_MAX) // 125 is EXIT__AUTO_MAX
|
||||
{
|
||||
$exitStatus = EXIT_ERROR; // EXIT_ERROR
|
||||
}
|
||||
$statusCode = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
$exitStatus = 1; // EXIT_ERROR
|
||||
}
|
||||
|
||||
return [
|
||||
$statusCode ?? 500,
|
||||
$exitStatus,
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------
|
||||
// Display Methods
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean Path
|
||||
*
|
||||
* This makes nicer looking paths for the error output.
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cleanPath(string $file): string
|
||||
{
|
||||
if (strpos($file, APPPATH) === 0)
|
||||
{
|
||||
$file = 'APPPATH/' . substr($file, strlen(APPPATH));
|
||||
}
|
||||
elseif (strpos($file, SYSTEMPATH) === 0)
|
||||
{
|
||||
$file = 'SYSTEMPATH/' . substr($file, strlen(SYSTEMPATH));
|
||||
}
|
||||
elseif (strpos($file, FCPATH) === 0)
|
||||
{
|
||||
$file = 'FCPATH/' . substr($file, strlen(FCPATH));
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Describes memory usage in real-world units. Intended for use
|
||||
* with memory_get_usage, etc.
|
||||
*
|
||||
* @param $bytes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function describeMemory(int $bytes): string
|
||||
{
|
||||
if ($bytes < 1024)
|
||||
{
|
||||
return $bytes . 'B';
|
||||
}
|
||||
else if ($bytes < 1048576)
|
||||
{
|
||||
return round($bytes / 1024, 2) . 'KB';
|
||||
}
|
||||
|
||||
return round($bytes / 1048576, 2) . 'MB';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a syntax-highlighted version of a PHP file.
|
||||
*
|
||||
* @param string $file
|
||||
* @param integer $lineNumber
|
||||
* @param integer $lines
|
||||
*
|
||||
* @return boolean|string
|
||||
*/
|
||||
public static function highlightFile(string $file, int $lineNumber, int $lines = 15)
|
||||
{
|
||||
if (empty($file) || ! is_readable($file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set our highlight colors:
|
||||
if (function_exists('ini_set'))
|
||||
{
|
||||
ini_set('highlight.comment', '#767a7e; font-style: italic');
|
||||
ini_set('highlight.default', '#c7c7c7');
|
||||
ini_set('highlight.html', '#06B');
|
||||
ini_set('highlight.keyword', '#f1ce61;');
|
||||
ini_set('highlight.string', '#869d6a');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$source = file_get_contents($file);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$source = str_replace(["\r\n", "\r"], "\n", $source);
|
||||
$source = explode("\n", highlight_string($source, true));
|
||||
$source = str_replace('<br />', "\n", $source[1]);
|
||||
|
||||
$source = explode("\n", str_replace("\r\n", "\n", $source));
|
||||
|
||||
// Get just the part to show
|
||||
$start = $lineNumber - (int) round($lines / 2);
|
||||
$start = $start < 0 ? 0 : $start;
|
||||
|
||||
// Get just the lines we need to display, while keeping line numbers...
|
||||
$source = array_splice($source, $start, $lines, true);
|
||||
|
||||
// Used to format the line number in the source
|
||||
$format = '% ' . strlen(sprintf('%s', $start + $lines)) . 'd';
|
||||
|
||||
$out = '';
|
||||
// Because the highlighting may have an uneven number
|
||||
// of open and close span tags on one line, we need
|
||||
// to ensure we can close them all to get the lines
|
||||
// showing correctly.
|
||||
$spans = 1;
|
||||
|
||||
foreach ($source as $n => $row)
|
||||
{
|
||||
$spans += substr_count($row, '<span') - substr_count($row, '</span');
|
||||
$row = str_replace(["\r", "\n"], ['', ''], $row);
|
||||
|
||||
if (($n + $start + 1) === $lineNumber)
|
||||
{
|
||||
preg_match_all('#<[^>]+>#', $row, $tags);
|
||||
$out .= sprintf("<span class='line highlight'><span class='number'>{$format}</span> %s\n</span>%s", $n + $start + 1, strip_tags($row), implode('', $tags[0])
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$out .= sprintf('<span class="line"><span class="number">' . $format . '</span> %s', $n + $start + 1, $row) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($spans > 0)
|
||||
{
|
||||
$out .= str_repeat('</span>', $spans);
|
||||
}
|
||||
|
||||
return '<pre><code>' . $out . '</code></pre>';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
179
system/Debug/Iterator.php
Normal file
179
system/Debug/Iterator.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug;
|
||||
|
||||
/**
|
||||
* Iterator for debugging.
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
|
||||
/**
|
||||
* Stores the tests that we are to run.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tests = [];
|
||||
|
||||
/**
|
||||
* Stores the results of each of the tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $results = [];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Adds a test to run.
|
||||
*
|
||||
* Tests are simply closures that the user can define any sequence of
|
||||
* things to happen during the test.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add(string $name, \Closure $closure)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
$this->tests[$name] = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Runs through all of the tests that have been added, recording
|
||||
* time to execute the desired number of iterations, and the approximate
|
||||
* memory usage used during those iterations.
|
||||
*
|
||||
* @param integer $iterations
|
||||
* @param boolean $output
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function run(int $iterations = 1000, bool $output = true)
|
||||
{
|
||||
foreach ($this->tests as $name => $test)
|
||||
{
|
||||
// clear memory before start
|
||||
gc_collect_cycles();
|
||||
|
||||
$start = microtime(true);
|
||||
$start_mem = $max_memory = memory_get_usage(true);
|
||||
|
||||
for ($i = 0; $i < $iterations; $i ++)
|
||||
{
|
||||
$result = $test();
|
||||
|
||||
$max_memory = max($max_memory, memory_get_usage(true));
|
||||
|
||||
unset($result);
|
||||
}
|
||||
|
||||
$this->results[$name] = [
|
||||
'time' => microtime(true) - $start,
|
||||
'memory' => $max_memory - $start_mem,
|
||||
'n' => $iterations,
|
||||
];
|
||||
}
|
||||
|
||||
if ($output)
|
||||
{
|
||||
return $this->getReport();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get results.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getReport(): string
|
||||
{
|
||||
if (empty($this->results))
|
||||
{
|
||||
return 'No results to display.';
|
||||
}
|
||||
|
||||
helper('number');
|
||||
|
||||
// Template
|
||||
$tpl = '<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Test</td>
|
||||
<td>Time</td>
|
||||
<td>Memory</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>';
|
||||
|
||||
$rows = '';
|
||||
|
||||
foreach ($this->results as $name => $result)
|
||||
{
|
||||
$memory = number_to_size($result['memory'], 4);
|
||||
|
||||
$rows .= "<tr>
|
||||
<td>{$name}</td>
|
||||
<td>" . number_format($result['time'], 4) . "</td>
|
||||
<td>{$memory}</td>
|
||||
</tr>";
|
||||
}
|
||||
|
||||
$tpl = str_replace('{rows}', $rows, $tpl);
|
||||
|
||||
return $tpl . '<br/>';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
}
|
||||
184
system/Debug/Timer.php
Normal file
184
system/Debug/Timer.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug;
|
||||
|
||||
/**
|
||||
* Class Timer
|
||||
*
|
||||
* Provides a simple way to measure the amount of time
|
||||
* that elapses between two points.
|
||||
*
|
||||
* NOTE: All methods are static since the class is intended
|
||||
* to measure throughout an entire application's life cycle.
|
||||
*
|
||||
* @package CodeIgniter\Benchmark
|
||||
*/
|
||||
class Timer
|
||||
{
|
||||
|
||||
/**
|
||||
* List of all timers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $timers = [];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Starts a timer running.
|
||||
*
|
||||
* Multiple calls can be made to this method so that several
|
||||
* execution points can be measured.
|
||||
*
|
||||
* @param string $name The name of this timer.
|
||||
* @param float $time Allows user to provide time.
|
||||
*
|
||||
* @return Timer
|
||||
*/
|
||||
public function start(string $name, float $time = null)
|
||||
{
|
||||
$this->timers[strtolower($name)] = [
|
||||
'start' => ! empty($time) ? $time : microtime(true),
|
||||
'end' => null,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Stops a running timer.
|
||||
*
|
||||
* If the timer is not stopped before the timers() method is called,
|
||||
* it will be automatically stopped at that point.
|
||||
*
|
||||
* @param string $name The name of this timer.
|
||||
*
|
||||
* @return Timer
|
||||
*/
|
||||
public function stop(string $name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
if (empty($this->timers[$name]))
|
||||
{
|
||||
throw new \RuntimeException('Cannot stop timer: invalid name given.');
|
||||
}
|
||||
|
||||
$this->timers[$name]['end'] = microtime(true);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the duration of a recorded timer.
|
||||
*
|
||||
* @param string $name The name of the timer.
|
||||
* @param integer $decimals Number of decimal places.
|
||||
*
|
||||
* @return null|float Returns null if timer exists by that name.
|
||||
* Returns a float representing the number of
|
||||
* seconds elapsed while that timer was running.
|
||||
*/
|
||||
public function getElapsedTime(string $name, int $decimals = 4)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
if (empty($this->timers[$name]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$timer = $this->timers[$name];
|
||||
|
||||
if (empty($timer['end']))
|
||||
{
|
||||
$timer['end'] = microtime(true);
|
||||
}
|
||||
|
||||
return (float) number_format($timer['end'] - $timer['start'], $decimals);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the array of timers, with the duration pre-calculated for you.
|
||||
*
|
||||
* @param integer $decimals Number of decimal places
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTimers(int $decimals = 4): array
|
||||
{
|
||||
$timers = $this->timers;
|
||||
|
||||
foreach ($timers as &$timer)
|
||||
{
|
||||
if (empty($timer['end']))
|
||||
{
|
||||
$timer['end'] = microtime(true);
|
||||
}
|
||||
|
||||
$timer['duration'] = (float) number_format($timer['end'] - $timer['start'], $decimals);
|
||||
}
|
||||
|
||||
return $timers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not a timer with the specified name exists.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return array_key_exists(strtolower($name), $this->timers);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
512
system/Debug/Toolbar.php
Normal file
512
system/Debug/Toolbar.php
Normal file
@@ -0,0 +1,512 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\History;
|
||||
use CodeIgniter\Format\JSONFormatter;
|
||||
use CodeIgniter\Format\XMLFormatter;
|
||||
use CodeIgniter\HTTP\DownloadResponse;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
|
||||
/**
|
||||
* Debug Toolbar
|
||||
*
|
||||
* Displays a toolbar with bits of stats to aid a developer in debugging.
|
||||
*
|
||||
* Inspiration: http://prophiler.fabfuel.de
|
||||
*
|
||||
* @package CodeIgniter\Debug
|
||||
*/
|
||||
class Toolbar
|
||||
{
|
||||
|
||||
/**
|
||||
* Toolbar configuration settings.
|
||||
*
|
||||
* @var BaseConfig
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Collectors to be used and displayed.
|
||||
*
|
||||
* @var \CodeIgniter\Debug\Toolbar\Collectors\BaseCollector[]
|
||||
*/
|
||||
protected $collectors = [];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param BaseConfig $config
|
||||
*/
|
||||
public function __construct(BaseConfig $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
foreach ($config->collectors as $collector)
|
||||
{
|
||||
if (! class_exists($collector))
|
||||
{
|
||||
log_message('critical', 'Toolbar collector does not exists(' . $collector . ').' .
|
||||
'please check $collectors in the Config\Toolbar.php file.');
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->collectors[] = new $collector();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns all the data required by Debug Bar
|
||||
*
|
||||
* @param float $startTime App start time
|
||||
* @param float $totalTime
|
||||
* @param \CodeIgniter\HTTP\RequestInterface $request
|
||||
* @param \CodeIgniter\HTTP\ResponseInterface $response
|
||||
*
|
||||
* @return string JSON encoded data
|
||||
*/
|
||||
public function run(float $startTime, float $totalTime, RequestInterface $request, ResponseInterface $response): string
|
||||
{
|
||||
// Data items used within the view.
|
||||
$data['url'] = current_url();
|
||||
$data['method'] = $request->getMethod(true);
|
||||
$data['isAJAX'] = $request->isAJAX();
|
||||
$data['startTime'] = $startTime;
|
||||
$data['totalTime'] = $totalTime * 1000;
|
||||
$data['totalMemory'] = number_format((memory_get_peak_usage()) / 1024 / 1024, 3);
|
||||
$data['segmentDuration'] = $this->roundTo($data['totalTime'] / 7, 5);
|
||||
$data['segmentCount'] = (int) ceil($data['totalTime'] / $data['segmentDuration']);
|
||||
$data['CI_VERSION'] = \CodeIgniter\CodeIgniter::CI_VERSION;
|
||||
$data['collectors'] = [];
|
||||
|
||||
foreach ($this->collectors as $collector)
|
||||
{
|
||||
$data['collectors'][] = $collector->getAsArray();
|
||||
}
|
||||
|
||||
foreach ($this->collectVarData() as $heading => $items)
|
||||
{
|
||||
$varData = [];
|
||||
|
||||
if (is_array($items))
|
||||
{
|
||||
foreach ($items as $key => $value)
|
||||
{
|
||||
$varData[esc($key)] = is_string($value) ? esc($value) : print_r($value, true);
|
||||
}
|
||||
}
|
||||
|
||||
$data['vars']['varData'][esc($heading)] = $varData;
|
||||
}
|
||||
|
||||
if (! empty($_SESSION))
|
||||
{
|
||||
foreach ($_SESSION as $key => $value)
|
||||
{
|
||||
// Replace the binary data with string to avoid json_encode failure.
|
||||
if (is_string($value) && preg_match('~[^\x20-\x7E\t\r\n]~', $value))
|
||||
{
|
||||
$value = 'binary data';
|
||||
}
|
||||
|
||||
$data['vars']['session'][esc($key)] = is_string($value) ? esc($value) : print_r($value, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($request->getGet() as $name => $value)
|
||||
{
|
||||
$data['vars']['get'][esc($name)] = is_array($value) ? esc(print_r($value, true)) : esc($value);
|
||||
}
|
||||
|
||||
foreach ($request->getPost() as $name => $value)
|
||||
{
|
||||
$data['vars']['post'][esc($name)] = is_array($value) ? esc(print_r($value, true)) : esc($value);
|
||||
}
|
||||
|
||||
foreach ($request->getHeaders() as $header => $value)
|
||||
{
|
||||
if (empty($value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_array($value))
|
||||
{
|
||||
$value = [$value];
|
||||
}
|
||||
|
||||
foreach ($value as $h)
|
||||
{
|
||||
$data['vars']['headers'][esc($h->getName())] = esc($h->getValueLine());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($request->getCookie() as $name => $value)
|
||||
{
|
||||
$data['vars']['cookies'][esc($name)] = esc($value);
|
||||
}
|
||||
|
||||
$data['vars']['request'] = ($request->isSecure() ? 'HTTPS' : 'HTTP') . '/' . $request->getProtocolVersion();
|
||||
|
||||
$data['vars']['response'] = [
|
||||
'statusCode' => $response->getStatusCode(),
|
||||
'reason' => esc($response->getReason()),
|
||||
'contentType' => esc($response->getHeaderLine('content-type')),
|
||||
];
|
||||
|
||||
$data['config'] = \CodeIgniter\Debug\Toolbar\Collectors\Config::display();
|
||||
|
||||
if ($response->CSP !== null)
|
||||
{
|
||||
$response->CSP->addImageSrc('data:');
|
||||
}
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Called within the view to display the timeline itself.
|
||||
*
|
||||
* @param array $collectors
|
||||
* @param float $startTime
|
||||
* @param integer $segmentCount
|
||||
* @param integer $segmentDuration
|
||||
* @param array $styles
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function renderTimeline(array $collectors, float $startTime, int $segmentCount, int $segmentDuration, array &$styles): string
|
||||
{
|
||||
$displayTime = $segmentCount * $segmentDuration;
|
||||
$rows = $this->collectTimelineData($collectors);
|
||||
$output = '';
|
||||
$styleCount = 0;
|
||||
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$output .= '<tr>';
|
||||
$output .= "<td>{$row['name']}</td>";
|
||||
$output .= "<td>{$row['component']}</td>";
|
||||
$output .= "<td class='debug-bar-alignRight'>" . number_format($row['duration'] * 1000, 2) . ' ms</td>';
|
||||
$output .= "<td class='debug-bar-noverflow' colspan='{$segmentCount}'>";
|
||||
|
||||
$offset = ((((float) $row['start'] - $startTime) * 1000) / $displayTime) * 100;
|
||||
$length = (((float) $row['duration'] * 1000) / $displayTime) * 100;
|
||||
|
||||
$styles['debug-bar-timeline-' . $styleCount] = "left: {$offset}%; width: {$length}%;";
|
||||
$output .= "<span class='timer debug-bar-timeline-{$styleCount}' title='" . number_format($length, 2) . "%'></span>";
|
||||
$output .= '</td>';
|
||||
$output .= '</tr>';
|
||||
|
||||
$styleCount ++;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a sorted array of timeline data arrays from the collectors.
|
||||
*
|
||||
* @param array $collectors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function collectTimelineData($collectors): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
// Collect it
|
||||
foreach ($collectors as $collector)
|
||||
{
|
||||
if (! $collector['hasTimelineData'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = array_merge($data, $collector['timelineData']);
|
||||
}
|
||||
|
||||
// Sort it
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns an array of data from all of the modules
|
||||
* that should be displayed in the 'Vars' tab.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function collectVarData(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->collectors as $collector)
|
||||
{
|
||||
if (! $collector->hasVarData())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = array_merge($data, $collector->getVarData());
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Rounds a number to the nearest incremental value.
|
||||
*
|
||||
* @param float $number
|
||||
* @param integer $increments
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
protected function roundTo(float $number, int $increments = 5): float
|
||||
{
|
||||
$increments = 1 / $increments;
|
||||
|
||||
return (ceil($number * $increments) / $increments);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prepare for debugging..
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @global type $app
|
||||
* @return type
|
||||
*/
|
||||
public function prepare(RequestInterface $request = null, ResponseInterface $response = null)
|
||||
{
|
||||
if (CI_DEBUG && ! is_cli())
|
||||
{
|
||||
global $app;
|
||||
|
||||
$request = $request ?? Services::request();
|
||||
$response = $response ?? Services::response();
|
||||
|
||||
// Disable the toolbar for downloads
|
||||
if ($response instanceof DownloadResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$toolbar = Services::toolbar(config(Toolbar::class));
|
||||
$stats = $app->getPerformanceStats();
|
||||
$data = $toolbar->run(
|
||||
$stats['startTime'],
|
||||
$stats['totalTime'],
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
|
||||
helper('filesystem');
|
||||
|
||||
// Updated to time() so we can get history
|
||||
$time = time();
|
||||
|
||||
if (! is_dir(WRITEPATH . 'debugbar'))
|
||||
{
|
||||
mkdir(WRITEPATH . 'debugbar', 0777);
|
||||
}
|
||||
|
||||
write_file(WRITEPATH . 'debugbar/' . 'debugbar_' . $time . '.json', $data, 'w+');
|
||||
|
||||
$format = $response->getHeaderLine('content-type');
|
||||
|
||||
// Non-HTML formats should not include the debugbar
|
||||
// then we send headers saying where to find the debug data
|
||||
// for this response
|
||||
if ($request->isAJAX() || strpos($format, 'html') === false)
|
||||
{
|
||||
$response->setHeader('Debugbar-Time', $time)
|
||||
->setHeader('Debugbar-Link', site_url("?debugbar_time={$time}"))
|
||||
->getBody();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$script = PHP_EOL
|
||||
. '<script type="text/javascript" {csp-script-nonce} id="debugbar_loader" '
|
||||
. 'data-time="' . $time . '" '
|
||||
. 'src="' . site_url() . '?debugbar"></script>'
|
||||
. '<script type="text/javascript" {csp-script-nonce} id="debugbar_dynamic_script"></script>'
|
||||
. '<style type="text/css" {csp-style-nonce} id="debugbar_dynamic_style"></style>'
|
||||
. PHP_EOL;
|
||||
|
||||
if (strpos($response->getBody(), '</body>') !== false)
|
||||
{
|
||||
$response->setBody(
|
||||
str_replace('</body>', $script . '</body>', $response->getBody())
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$response->appendBody($script);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Inject debug toolbar into the response.
|
||||
*/
|
||||
public function respond()
|
||||
{
|
||||
if (ENVIRONMENT === 'testing')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$request = Services::request();
|
||||
|
||||
// If the request contains '?debugbar then we're
|
||||
// simply returning the loading script
|
||||
if ($request->getGet('debugbar') !== null)
|
||||
{
|
||||
// Let the browser know that we are sending javascript
|
||||
header('Content-Type: application/javascript');
|
||||
|
||||
ob_start();
|
||||
include($this->config->viewsPath . 'toolbarloader.js.php');
|
||||
$output = ob_get_clean();
|
||||
|
||||
exit($output);
|
||||
}
|
||||
|
||||
// Otherwise, if it includes ?debugbar_time, then
|
||||
// we should return the entire debugbar.
|
||||
if ($request->getGet('debugbar_time'))
|
||||
{
|
||||
helper('security');
|
||||
|
||||
// Negotiate the content-type to format the output
|
||||
$format = $request->negotiate('media', [
|
||||
'text/html',
|
||||
'application/json',
|
||||
'application/xml',
|
||||
]);
|
||||
$format = explode('/', $format)[1];
|
||||
|
||||
$file = sanitize_filename('debugbar_' . $request->getGet('debugbar_time'));
|
||||
$filename = WRITEPATH . 'debugbar/' . $file . '.json';
|
||||
|
||||
// Show the toolbar
|
||||
if (is_file($filename))
|
||||
{
|
||||
$contents = $this->format(file_get_contents($filename), $format);
|
||||
exit($contents);
|
||||
}
|
||||
|
||||
// File was not written or do not exists
|
||||
http_response_code(404);
|
||||
exit; // Exit here is needed to avoid load the index page
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format output
|
||||
*
|
||||
* @param string $data JSON encoded Toolbar data
|
||||
* @param string $format html, json, xml
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function format(string $data, string $format = 'html'): string
|
||||
{
|
||||
$data = json_decode($data, true);
|
||||
|
||||
if ($this->config->maxHistory !== 0)
|
||||
{
|
||||
$history = new History();
|
||||
$history->setFiles(
|
||||
Services::request()->getGet('debugbar_time'),
|
||||
$this->config->maxHistory
|
||||
);
|
||||
|
||||
$data['collectors'][] = $history->getAsArray();
|
||||
}
|
||||
|
||||
$output = '';
|
||||
|
||||
switch ($format)
|
||||
{
|
||||
case 'html':
|
||||
$data['styles'] = [];
|
||||
extract($data);
|
||||
$parser = Services::parser($this->config->viewsPath, null, false);
|
||||
ob_start();
|
||||
include($this->config->viewsPath . 'toolbar.tpl.php');
|
||||
$output = ob_get_clean();
|
||||
break;
|
||||
case 'json':
|
||||
$formatter = new JSONFormatter();
|
||||
$output = $formatter->format($data);
|
||||
break;
|
||||
case 'xml':
|
||||
$formatter = new XMLFormatter;
|
||||
$output = $formatter->format($data);
|
||||
break;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
329
system/Debug/Toolbar/Collectors/BaseCollector.php
Normal file
329
system/Debug/Toolbar/Collectors/BaseCollector.php
Normal file
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
/**
|
||||
* Base Toolbar collector
|
||||
*/
|
||||
class BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* a label or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasLabel = false;
|
||||
|
||||
/**
|
||||
* Whether this collector has data that
|
||||
* should be shown in the Vars tab.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasVarData = false;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '';
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets the Collector's title.
|
||||
*
|
||||
* @param boolean $safe
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(bool $safe = false): string
|
||||
{
|
||||
if ($safe)
|
||||
{
|
||||
return str_replace(' ', '-', strtolower($this->title));
|
||||
}
|
||||
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns any information that should be shown next to the title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleDetails(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does this collector need it's own tab?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTabContent(): bool
|
||||
{
|
||||
return (bool) $this->hasTabContent;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does this collector have a label?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasLabel(): bool
|
||||
{
|
||||
return (bool) $this->hasLabel;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does this collector have information for the timeline?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTimelineData(): bool
|
||||
{
|
||||
return (bool) $this->hasTimeline;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Grabs the data for the timeline, properly formatted,
|
||||
* or returns an empty array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function timelineData(): array
|
||||
{
|
||||
if (! $this->hasTimeline)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->formatTimelineData();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does this Collector have data that should be shown in the
|
||||
* 'Vars' tab?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasVarData(): bool
|
||||
{
|
||||
return (bool) $this->hasVarData;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets a collection of data that should be shown in the 'Vars' tab.
|
||||
* The format is an array of sections, each with their own array
|
||||
* of key/value pairs:
|
||||
*
|
||||
* $data = [
|
||||
* 'section 1' => [
|
||||
* 'foo' => 'bar,
|
||||
* 'bar' => 'baz'
|
||||
* ],
|
||||
* 'section 2' => [
|
||||
* 'foo' => 'bar,
|
||||
* 'bar' => 'baz'
|
||||
* ],
|
||||
* ];
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getVarData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Child classes should implement this to return the timeline data
|
||||
* formatted for correct usage.
|
||||
*
|
||||
* Timeline data should be formatted into arrays that look like:
|
||||
*
|
||||
* [
|
||||
* 'name' => 'Database::Query',
|
||||
* 'component' => 'Database',
|
||||
* 'start' => 10 // milliseconds
|
||||
* 'duration' => 15 // milliseconds
|
||||
* ]
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function formatTimelineData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function display()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean Path
|
||||
*
|
||||
* This makes nicer looking paths for the error output.
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function cleanPath(string $file): string
|
||||
{
|
||||
if (strpos($file, APPPATH) === 0)
|
||||
{
|
||||
$file = 'APPPATH/' . substr($file, strlen(APPPATH));
|
||||
}
|
||||
elseif (strpos($file, SYSTEMPATH) === 0)
|
||||
{
|
||||
$file = 'SYSTEMPATH/' . substr($file, strlen(SYSTEMPATH));
|
||||
}
|
||||
elseif (strpos($file, FCPATH) === 0)
|
||||
{
|
||||
$file = 'FCPATH/' . substr($file, strlen(FCPATH));
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "badge" value for the button.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getBadgeValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this collector have any data collected?
|
||||
*
|
||||
* If not, then the toolbar button won't get shown.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML to display the icon. Should either
|
||||
* be SVG, or a base-64 encoded.
|
||||
*
|
||||
* Recommended dimensions are 24px x 24px
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return settings as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAsArray(): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->getTitle(),
|
||||
'titleSafe' => $this->getTitle(true),
|
||||
'titleDetails' => $this->getTitleDetails(),
|
||||
'display' => $this->display(),
|
||||
'badgeValue' => $this->getBadgeValue(),
|
||||
'isEmpty' => $this->isEmpty(),
|
||||
'hasTabContent' => $this->hasTabContent(),
|
||||
'hasLabel' => $this->hasLabel(),
|
||||
'icon' => $this->icon(),
|
||||
'hasTimelineData' => $this->hasTimelineData(),
|
||||
'timelineData' => $this->timelineData(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
71
system/Debug/Toolbar/Collectors/Config.php
Normal file
71
system/Debug/Toolbar/Collectors/Config.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use Config\App;
|
||||
use Config\Services;
|
||||
use CodeIgniter\CodeIgniter;
|
||||
|
||||
/**
|
||||
* Debug toolbar configuration
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
/**
|
||||
* Return toolbar config values as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function display(): array
|
||||
{
|
||||
$config = config(App::class);
|
||||
|
||||
return [
|
||||
'ciVersion' => CodeIgniter::CI_VERSION,
|
||||
'phpVersion' => phpversion(),
|
||||
'phpSAPI' => php_sapi_name(),
|
||||
'environment' => ENVIRONMENT,
|
||||
'baseURL' => $config->baseURL,
|
||||
'timezone' => app_timezone(),
|
||||
'locale' => Services::request()->getLocale(),
|
||||
'cspEnabled' => $config->CSPEnabled,
|
||||
];
|
||||
}
|
||||
}
|
||||
276
system/Debug/Toolbar/Collectors/Database.php
Normal file
276
system/Debug/Toolbar/Collectors/Database.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use CodeIgniter\Database\Query;
|
||||
|
||||
/**
|
||||
* Collector for the Database tab of the Debug Toolbar.
|
||||
*/
|
||||
class Database extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has timeline data.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = true;
|
||||
|
||||
/**
|
||||
* Whether this collector should display its own tab.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = true;
|
||||
|
||||
/**
|
||||
* Whether this collector has data for the Vars tab.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasVarData = false;
|
||||
|
||||
/**
|
||||
* The name used to reference this collector in the toolbar.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Database';
|
||||
|
||||
/**
|
||||
* Array of database connections.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $connections;
|
||||
|
||||
/**
|
||||
* The query instances that have been collected
|
||||
* through the DBQuery Event.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $queries = [];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->connections = \Config\Database::getConnections();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The static method used during Events to collect
|
||||
* data.
|
||||
*
|
||||
* @param \CodeIgniter\Database\Query $query
|
||||
*
|
||||
* @internal param $ array \CodeIgniter\Database\Query
|
||||
*/
|
||||
public static function collect(Query $query)
|
||||
{
|
||||
$config = config('Toolbar');
|
||||
|
||||
// Provide default in case it's not set
|
||||
$max = $config->maxQueries ?: 100;
|
||||
|
||||
if (count(static::$queries) < $max)
|
||||
{
|
||||
static::$queries[] = $query;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns timeline data formatted for the toolbar.
|
||||
*
|
||||
* @return array The formatted data or an empty array.
|
||||
*/
|
||||
protected function formatTimelineData(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->connections as $alias => $connection)
|
||||
{
|
||||
// Connection Time
|
||||
$data[] = [
|
||||
'name' => 'Connecting to Database: "' . $alias . '"',
|
||||
'component' => 'Database',
|
||||
'start' => $connection->getConnectStart(),
|
||||
'duration' => $connection->getConnectDuration(),
|
||||
];
|
||||
}
|
||||
|
||||
foreach (static::$queries as $query)
|
||||
{
|
||||
$data[] = [
|
||||
'name' => 'Query',
|
||||
'component' => 'Database',
|
||||
'start' => $query->getStartTime(true),
|
||||
'duration' => $query->getDuration(),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function display(): array
|
||||
{
|
||||
// Key words we want bolded
|
||||
$highlight = [
|
||||
'SELECT',
|
||||
'DISTINCT',
|
||||
'FROM',
|
||||
'WHERE',
|
||||
'AND',
|
||||
'LEFT JOIN',
|
||||
'ORDER BY',
|
||||
'GROUP BY',
|
||||
'LIMIT',
|
||||
'INSERT',
|
||||
'INTO',
|
||||
'VALUES',
|
||||
'UPDATE',
|
||||
'OR ',
|
||||
'HAVING',
|
||||
'OFFSET',
|
||||
'NOT IN',
|
||||
'IN',
|
||||
'LIKE',
|
||||
'NOT LIKE',
|
||||
'COUNT',
|
||||
'MAX',
|
||||
'MIN',
|
||||
'ON',
|
||||
'AS',
|
||||
'AVG',
|
||||
'SUM',
|
||||
'(',
|
||||
')',
|
||||
];
|
||||
|
||||
$data = [
|
||||
'queries' => [],
|
||||
];
|
||||
|
||||
foreach (static::$queries as $query)
|
||||
{
|
||||
$sql = $query->getQuery();
|
||||
|
||||
foreach ($highlight as $term)
|
||||
{
|
||||
$sql = str_replace($term, "<strong>{$term}</strong>", $sql);
|
||||
}
|
||||
|
||||
$data['queries'][] = [
|
||||
'duration' => ($query->getDuration(5) * 1000) . ' ms',
|
||||
'sql' => $sql,
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets the "badge" value for the button.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBadgeValue(): int
|
||||
{
|
||||
return count(static::$queries);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Information to be displayed next to the title.
|
||||
*
|
||||
* @return string The number of queries (in parentheses) or an empty string.
|
||||
*/
|
||||
public function getTitleDetails(): string
|
||||
{
|
||||
return '(' . count(static::$queries) . ' Queries across ' . ($countConnection = count($this->connections)) . ' Connection' .
|
||||
($countConnection > 1 ? 's' : '') . ')';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does this collector have any data collected?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return empty(static::$queries);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADMSURBVEhLY6A3YExLSwsA4nIycQDIDIhRWEBqamo/UNF/SjDQjF6ocZgAKPkRiFeEhoYyQ4WIBiA9QAuWAPEHqBAmgLqgHcolGQD1V4DMgHIxwbCxYD+QBqcKINseKo6eWrBioPrtQBq/BcgY5ht0cUIYbBg2AJKkRxCNWkDQgtFUNJwtABr+F6igE8olGQD114HMgHIxAVDyAhA/AlpSA8RYUwoeXAPVex5qHCbIyMgwBCkAuQJIY00huDBUz/mUlBQDqHGjgBjAwAAACexpph6oHSQAAAAASUVORK5CYII=';
|
||||
}
|
||||
|
||||
}
|
||||
187
system/Debug/Toolbar/Collectors/Events.php
Normal file
187
system/Debug/Toolbar/Collectors/Events.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use CodeIgniter\Config\Services;
|
||||
use CodeIgniter\View\RendererInterface;
|
||||
|
||||
/**
|
||||
* Views collector
|
||||
*/
|
||||
class Events extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = true;
|
||||
|
||||
/**
|
||||
* Whether this collector has data that
|
||||
* should be shown in the Vars tab.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasVarData = false;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Events';
|
||||
|
||||
/**
|
||||
* Instance of the Renderer service
|
||||
*
|
||||
* @var RendererInterface
|
||||
*/
|
||||
protected $viewer;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->viewer = Services::renderer(null, true);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Child classes should implement this to return the timeline data
|
||||
* formatted for correct usage.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function formatTimelineData(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
$rows = $this->viewer->getPerformanceData();
|
||||
|
||||
foreach ($rows as $name => $info)
|
||||
{
|
||||
$data[] = [
|
||||
'name' => 'View: ' . $info['view'],
|
||||
'component' => 'Views',
|
||||
'start' => $info['start'],
|
||||
'duration' => $info['end'] - $info['start'],
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function display(): array
|
||||
{
|
||||
$data = [
|
||||
'events' => [],
|
||||
];
|
||||
|
||||
foreach (\CodeIgniter\Events\Events::getPerformanceLogs() as $row)
|
||||
{
|
||||
$key = $row['event'];
|
||||
|
||||
if (! array_key_exists($key, $data['events']))
|
||||
{
|
||||
$data['events'][$key] = [
|
||||
'event' => $key,
|
||||
'duration' => number_format(($row['end'] - $row['start']) * 1000, 2),
|
||||
'count' => 1,
|
||||
];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['events'][$key]['duration'] += number_format(($row['end'] - $row['start']) * 1000, 2);
|
||||
$data['events'][$key]['count']++;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets the "badge" value for the button.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBadgeValue(): int
|
||||
{
|
||||
return count(\CodeIgniter\Events\Events::getPerformanceLogs());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEASURBVEhL7ZXNDcIwDIVTsRBH1uDQDdquUA6IM1xgCA6MwJUN2hk6AQzAz0vl0ETUxC5VT3zSU5w81/mRMGZysixbFEVR0jSKNt8geQU9aRpFmp/keX6AbjZ5oB74vsaN5lSzA4tLSjpBFxsjeSuRy4d2mDdQTWU7YLbXTNN05mKyovj5KL6B7q3hoy3KwdZxBlT+Ipz+jPHrBqOIynZgcZonoukb/0ckiTHqNvDXtXEAaygRbaB9FvUTjRUHsIYS0QaSp+Dw6wT4hiTmYHOcYZsdLQ2CbXa4ftuuYR4x9vYZgdb4vsFYUdmABMYeukK9/SUme3KMFQ77+Yfzh8eYF8+orDuDWU5LAAAAAElFTkSuQmCC';
|
||||
}
|
||||
}
|
||||
151
system/Debug/Toolbar/Collectors/Files.php
Normal file
151
system/Debug/Toolbar/Collectors/Files.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
/**
|
||||
* Files collector
|
||||
*/
|
||||
class Files extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = true;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Files';
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns any information that should be shown next to the title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleDetails(): string
|
||||
{
|
||||
return '( ' . (int) count(get_included_files()) . ' )';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function display(): array
|
||||
{
|
||||
$rawFiles = get_included_files();
|
||||
$coreFiles = [];
|
||||
$userFiles = [];
|
||||
|
||||
foreach ($rawFiles as $file)
|
||||
{
|
||||
$path = $this->cleanPath($file);
|
||||
|
||||
if (strpos($path, 'SYSTEMPATH') !== false)
|
||||
{
|
||||
$coreFiles[] = [
|
||||
'name' => basename($file),
|
||||
'path' => $path,
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$userFiles[] = [
|
||||
'name' => basename($file),
|
||||
'path' => $path,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
sort($userFiles);
|
||||
sort($coreFiles);
|
||||
|
||||
return [
|
||||
'coreFiles' => $coreFiles,
|
||||
'userFiles' => $userFiles,
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Displays the number of included files as a badge in the tab button.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBadgeValue(): int
|
||||
{
|
||||
return count(get_included_files());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGBSURBVEhL7ZQ9S8NQGIVTBQUncfMfCO4uLgoKbuKQOWg+OkXERRE1IAXrIHbVDrqIDuLiJgj+gro7S3dnpfq88b1FMTE3VZx64HBzzvvZWxKnj15QCcPwCD5HUfSWR+JtzgmtsUcQBEva5IIm9SwSu+95CAWbUuy67qBa32ByZEDpIaZYZSZMjjQuPcQUq8yEyYEb8FSerYeQVGbAFzJkX1PyQWLhgCz0BxTCekC1Wp0hsa6yokzhed4oje6Iz6rlJEkyIKfUEFtITVtQdAibn5rMyaYsMS+a5wTv8qeXMhcU16QZbKgl3hbs+L4/pnpdc87MElZgq10p5DxGdq8I7xrvUWUKvG3NbSK7ubngYzdJwSsF7TiOh9VOgfcEz1UayNe3JUPM1RWC5GXYgTfc75B4NBmXJnAtTfpABX0iPvEd9ezALwkplCFXcr9styiNOKc1RRZpaPM9tcqBwlWzGY1qPL9wjqRBgF5BH6j8HWh2S7MHlX8PrmbK+k/8PzjOOzx1D3i1pKTTAAAAAElFTkSuQmCC';
|
||||
}
|
||||
}
|
||||
183
system/Debug/Toolbar/Collectors/History.php
Normal file
183
system/Debug/Toolbar/Collectors/History.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
/**
|
||||
* History collector
|
||||
*/
|
||||
class History extends BaseCollector
|
||||
{
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = true;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* a label or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasLabel = true;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'History';
|
||||
|
||||
/**
|
||||
* @var array History files
|
||||
*/
|
||||
protected $files = [];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specify time limit & file count for debug history.
|
||||
*
|
||||
* @param integer $current Current history time
|
||||
* @param integer $limit Max history files
|
||||
*/
|
||||
public function setFiles(int $current, int $limit = 20)
|
||||
{
|
||||
$filenames = glob(WRITEPATH . 'debugbar/debugbar_*.json');
|
||||
|
||||
$files = [];
|
||||
$counter = 0;
|
||||
|
||||
foreach (array_reverse($filenames) as $filename)
|
||||
{
|
||||
$counter++;
|
||||
|
||||
// Oldest files will be deleted
|
||||
if ($limit >= 0 && $counter > $limit)
|
||||
{
|
||||
unlink($filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the contents of this specific history request
|
||||
$contents = file_get_contents($filename);
|
||||
|
||||
$contents = @json_decode($contents);
|
||||
if (json_last_error() === JSON_ERROR_NONE)
|
||||
{
|
||||
preg_match_all('/\d+/', $filename, $time);
|
||||
$time = (int)end($time[0]);
|
||||
|
||||
// Debugbar files shown in History Collector
|
||||
$files[] = [
|
||||
'time' => $time,
|
||||
'datetime' => date('Y-m-d H:i:s', $time),
|
||||
'active' => $time === $current,
|
||||
'status' => $contents->vars->response->statusCode,
|
||||
'method' => $contents->method,
|
||||
'url' => $contents->url,
|
||||
'isAJAX' => $contents->isAJAX ? 'Yes' : 'No',
|
||||
'contentType' => $contents->vars->response->contentType,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function display(): array
|
||||
{
|
||||
return ['files' => $this->files];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Displays the number of included files as a badge in the tab button.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBadgeValue(): int
|
||||
{
|
||||
return count($this->files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no history files.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return empty($this->files);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJySURBVEhL3ZU7aJNhGIVTpV6i4qCIgkIHxcXLErS4FBwUFNwiCKGhuTYJGaIgnRoo4qRu6iCiiIuIXXTTIkIpuqoFwaGgonUQlC5KafU5ycmNP0lTdPLA4fu+8573/a4/f6hXpFKpwUwmc9fDfweKbk+n07fgEv33TLSbtt/hvwNFT1PsG/zdTE0Gp+GFfD6/2fbVIxqNrqPIRbjg4t/hY8aztcngfDabHXbKyiiXy2vcrcPH8oDCry2FKDrA+Ar6L01E/ypyXzXaARjDGGcoeNxSDZXE0dHRA5VRE5LJ5CFy5jzJuOX2wHRHRnjbklZ6isQ3tIctBaAd4vlK3jLtkOVWqABBXd47jGHLmjTmSScttQV5J+SjfcUweFQEbsjAas5aqoCLXutJl7vtQsAzpRowYqkBinyCC8Vicb2lOih8zoldd0F8RD7qTFiqAnGrAy8stUAvi/hbqDM+YzkAFrLPdR5ZqoLXsd+Bh5YCIH7JniVdquUWxOPxDfboHhrI5XJ7HHhiqQXox+APe/Qk64+gGYVCYZs8cMpSFQj9JOoFzVqqo7k4HIvFYpscCoAjOmLffUsNUGRaQUwDlmofUa34ecsdgXdcXo4wbakBgiUFafXJV8A4DJ/2UrxUKm3E95H8RbjLcgOJRGILhnmCP+FBy5XvwN2uIPcy1AJvWgqC4xm2aU4Xb3lF4I+Tpyf8hRe5w3J7YLymSeA8Z3nSclv4WLRyFdfOjzrUFX0klJUEtZtntCNc+F69cz/FiDzEPtjzmcUMOr83kDQEX6pAJxJfpL3OX22n01YN7SZCoQnaSdoZ+Jz+PZihH3wt/xlCoT9M6nEtmRSPCQAAAABJRU5ErkJggg==';
|
||||
}
|
||||
}
|
||||
139
system/Debug/Toolbar/Collectors/Logs.php
Normal file
139
system/Debug/Toolbar/Collectors/Logs.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use CodeIgniter\Config\Services;
|
||||
|
||||
/**
|
||||
* Loags collector
|
||||
*/
|
||||
class Logs extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = true;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Logs';
|
||||
|
||||
/**
|
||||
* Our collected data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function display(): array
|
||||
{
|
||||
return [
|
||||
'logs' => $this->collectLogs(),
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does this collector actually have any data to display?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
$this->collectLogs();
|
||||
|
||||
return empty($this->data);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACYSURBVEhLYxgFJIHU1FSjtLS0i0D8AYj7gEKMEBkqAaAFF4D4ERCvAFrwH4gDoFIMKSkpFkB+OTEYqgUTACXfA/GqjIwMQyD9H2hRHlQKJFcBEiMGQ7VgAqCBvUgK32dmZspCpagGGNPT0/1BLqeF4bQHQJePpiIwhmrBBEADR1MRfgB0+WgqAmOoFkwANHA0FY0CUgEDAwCQ0PUpNB3kqwAAAABJRU5ErkJggg==';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Ensures the data has been collected.
|
||||
*/
|
||||
protected function collectLogs()
|
||||
{
|
||||
if (! is_null($this->data))
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
return $this->data = Services::logger(true)->logCache ?? [];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
181
system/Debug/Toolbar/Collectors/Routes.php
Normal file
181
system/Debug/Toolbar/Collectors/Routes.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use CodeIgniter\Config\Services;
|
||||
|
||||
/**
|
||||
* Routes collector
|
||||
*/
|
||||
class Routes extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = true;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Routes';
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the data of this collector to be formatted in the toolbar
|
||||
*
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function display(): array
|
||||
{
|
||||
$rawRoutes = Services::routes(true);
|
||||
$router = Services::router(null, null, true);
|
||||
|
||||
/*
|
||||
* Matched Route
|
||||
*/
|
||||
$route = $router->getMatchedRoute();
|
||||
|
||||
// Get our parameters
|
||||
// Closure routes
|
||||
if (is_callable($router->controllerName()))
|
||||
{
|
||||
$method = new \ReflectionFunction($router->controllerName());
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$method = new \ReflectionMethod($router->controllerName(), $router->methodName());
|
||||
}
|
||||
catch (\ReflectionException $e)
|
||||
{
|
||||
// If we're here, the method doesn't exist
|
||||
// and is likely calculated in _remap.
|
||||
$method = new \ReflectionMethod($router->controllerName(), '_remap');
|
||||
}
|
||||
}
|
||||
|
||||
$rawParams = $method->getParameters();
|
||||
|
||||
$params = [];
|
||||
foreach ($rawParams as $key => $param)
|
||||
{
|
||||
$params[] = [
|
||||
'name' => $param->getName(),
|
||||
'value' => $router->params()[$key] ??
|
||||
'<empty> | default: ' . var_export($param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, true),
|
||||
];
|
||||
}
|
||||
|
||||
$matchedRoute = [
|
||||
[
|
||||
'directory' => $router->directory(),
|
||||
'controller' => $router->controllerName(),
|
||||
'method' => $router->methodName(),
|
||||
'paramCount' => count($router->params()),
|
||||
'truePCount' => count($params),
|
||||
'params' => $params ?? [],
|
||||
],
|
||||
];
|
||||
|
||||
/*
|
||||
* Defined Routes
|
||||
*/
|
||||
$rawRoutes = $rawRoutes->getRoutes();
|
||||
$routes = [];
|
||||
|
||||
foreach ($rawRoutes as $from => $to)
|
||||
{
|
||||
$routes[] = [
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'matchedRoute' => $matchedRoute,
|
||||
'routes' => $routes,
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a count of all the routes in the system.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBadgeValue(): int
|
||||
{
|
||||
$rawRoutes = Services::routes(true);
|
||||
|
||||
return count($rawRoutes->getRoutes());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFDSURBVEhL7ZRNSsNQFIUjVXSiOFEcuQIHDpzpxC0IGYeE/BEInbWlCHEDLsSiuANdhKDjgm6ggtSJ+l25ldrmmTwIgtgDh/t37r1J+16cX0dRFMtpmu5pWAkrvYjjOB7AETzStBFW+inxu3KUJMmhludQpoflS1zXban4LYqiO224h6VLTHr8Z+z8EpIHFF9gG78nDVmW7UgTHKjsCyY98QP+pcq+g8Ku2s8G8X3f3/I8b038WZTp+bO38zxfFd+I6YY6sNUvFlSDk9CRhiAI1jX1I9Cfw7GG1UB8LAuwbU0ZwQnbRDeEN5qqBxZMLtE1ti9LtbREnMIuOXnyIf5rGIb7Wq8HmlZgwYBH7ORTcKH5E4mpjeGt9fBZcHE2GCQ3Vt7oTNPNg+FXLHnSsHkw/FR+Gg2bB8Ptzrst/v6C/wrH+QB+duli6MYJdQAAAABJRU5ErkJggg==';
|
||||
}
|
||||
}
|
||||
107
system/Debug/Toolbar/Collectors/Timers.php
Normal file
107
system/Debug/Toolbar/Collectors/Timers.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use CodeIgniter\Config\Services;
|
||||
|
||||
/**
|
||||
* Timers collector
|
||||
*/
|
||||
class Timers extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = true;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = false;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Timers';
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Child classes should implement this to return the timeline data
|
||||
* formatted for correct usage.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function formatTimelineData(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
$benchmark = Services::timer(true);
|
||||
$rows = $benchmark->getTimers(6);
|
||||
|
||||
foreach ($rows as $name => $info)
|
||||
{
|
||||
if ($name === 'total_execution')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[] = [
|
||||
'name' => ucwords(str_replace('_', ' ', $name)),
|
||||
'component' => 'Timer',
|
||||
'start' => $info['start'],
|
||||
'duration' => $info['end'] - $info['start'],
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
192
system/Debug/Toolbar/Collectors/Views.php
Normal file
192
system/Debug/Toolbar/Collectors/Views.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug\Toolbar\Collectors;
|
||||
|
||||
use CodeIgniter\Config\Services;
|
||||
use CodeIgniter\View\RendererInterface;
|
||||
|
||||
/**
|
||||
* Views collector
|
||||
*/
|
||||
class Views extends BaseCollector
|
||||
{
|
||||
|
||||
/**
|
||||
* Whether this collector has data that can
|
||||
* be displayed in the Timeline.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTimeline = true;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* content in a tab or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasTabContent = false;
|
||||
|
||||
/**
|
||||
* Whether this collector needs to display
|
||||
* a label or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasLabel = true;
|
||||
|
||||
/**
|
||||
* Whether this collector has data that
|
||||
* should be shown in the Vars tab.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasVarData = true;
|
||||
|
||||
/**
|
||||
* The 'title' of this Collector.
|
||||
* Used to name things in the toolbar HTML.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = 'Views';
|
||||
|
||||
/**
|
||||
* Instance of the Renderer service
|
||||
*
|
||||
* @var RendererInterface
|
||||
*/
|
||||
protected $viewer;
|
||||
|
||||
/**
|
||||
* Views counter
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $views = [];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->viewer = Services::renderer();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Child classes should implement this to return the timeline data
|
||||
* formatted for correct usage.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function formatTimelineData(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
$rows = $this->viewer->getPerformanceData();
|
||||
|
||||
foreach ($rows as $name => $info)
|
||||
{
|
||||
$data[] = [
|
||||
'name' => 'View: ' . $info['view'],
|
||||
'component' => 'Views',
|
||||
'start' => $info['start'],
|
||||
'duration' => $info['end'] - $info['start'],
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets a collection of data that should be shown in the 'Vars' tab.
|
||||
* The format is an array of sections, each with their own array
|
||||
* of key/value pairs:
|
||||
*
|
||||
* $data = [
|
||||
* 'section 1' => [
|
||||
* 'foo' => 'bar,
|
||||
* 'bar' => 'baz'
|
||||
* ],
|
||||
* 'section 2' => [
|
||||
* 'foo' => 'bar,
|
||||
* 'bar' => 'baz'
|
||||
* ],
|
||||
* ];
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getVarData(): array
|
||||
{
|
||||
return [
|
||||
'View Data' => $this->viewer->getData(),
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a count of all views.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBadgeValue(): int
|
||||
{
|
||||
return count($this->viewer->getPerformanceData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the icon.
|
||||
*
|
||||
* Icon from https://icons8.com - 1em package
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADeSURBVEhL7ZSxDcIwEEWNYA0YgGmgyAaJLTcUaaBzQQEVjMEabBQxAdw53zTHiThEovGTfnE/9rsoRUxhKLOmaa6Uh7X2+UvguLCzVxN1XW9x4EYHzik033Hp3X0LO+DaQG8MDQcuq6qao4qkHuMgQggLvkPLjqh00ZgFDBacMJYFkuwFlH1mshdkZ5JPJERA9JpI6xNCBESvibQ+IURA9JpI6xNCBESvibQ+IURA9DTsuHTOrVFFxixgB/eUFlU8uKJ0eDBFOu/9EvoeKnlJS2/08Tc8NOwQ8sIfMeYFjqKDjdU2sp4AAAAASUVORK5CYII=';
|
||||
}
|
||||
}
|
||||
48
system/Debug/Toolbar/Views/_config.tpl
Normal file
48
system/Debug/Toolbar/Views/_config.tpl
Normal file
@@ -0,0 +1,48 @@
|
||||
<p class="debug-bar-alignRight">
|
||||
<a href="https://codeigniter4.github.io/CodeIgniter4/index.html" target="_blank" >Read the CodeIgniter docs...</a>
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>CodeIgniter Version:</td>
|
||||
<td>{ ciVersion }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PHP Version:</td>
|
||||
<td>{ phpVersion }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PHP SAPI:</td>
|
||||
<td>{ phpSAPI }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Environment:</td>
|
||||
<td>{ environment }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Base URL:</td>
|
||||
<td>
|
||||
{ if $baseURL == '' }
|
||||
<div class="warning">
|
||||
The $baseURL should always be set manually to prevent possible URL personification from external parties.
|
||||
</div>
|
||||
{ else }
|
||||
{ baseURL }
|
||||
{ endif }
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TimeZone:</td>
|
||||
<td>{ timezone }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Locale:</td>
|
||||
<td>{ locale }</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Content Security Policy Enabled:</td>
|
||||
<td>{ if $cspEnabled } Yes { else } No { endif }</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
16
system/Debug/Toolbar/Views/_database.tpl
Normal file
16
system/Debug/Toolbar/Views/_database.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="debug-bar-width6r">Time</th>
|
||||
<th>Query String</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{queries}
|
||||
<tr>
|
||||
<td class="narrow">{duration}</td>
|
||||
<td>{! sql !}</td>
|
||||
</tr>
|
||||
{/queries}
|
||||
</tbody>
|
||||
</table>
|
||||
18
system/Debug/Toolbar/Views/_events.tpl
Normal file
18
system/Debug/Toolbar/Views/_events.tpl
Normal file
@@ -0,0 +1,18 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="debug-bar-width6r">Time</th>
|
||||
<th>Event Name</th>
|
||||
<th>Times Called</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{events}
|
||||
<tr>
|
||||
<td class="narrow">{ duration } ms</td>
|
||||
<td>{event}</td>
|
||||
<td>{count}</td>
|
||||
</tr>
|
||||
{/events}
|
||||
</tbody>
|
||||
</table>
|
||||
16
system/Debug/Toolbar/Views/_files.tpl
Normal file
16
system/Debug/Toolbar/Views/_files.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
<table>
|
||||
<tbody>
|
||||
{userFiles}
|
||||
<tr>
|
||||
<td>{name}</td>
|
||||
<td>{path}</td>
|
||||
</tr>
|
||||
{/userFiles}
|
||||
{coreFiles}
|
||||
<tr class="muted">
|
||||
<td class="debug-bar-width20e">{name}</td>
|
||||
<td>{path}</td>
|
||||
</tr>
|
||||
{/coreFiles}
|
||||
</tbody>
|
||||
</table>
|
||||
28
system/Debug/Toolbar/Views/_history.tpl
Normal file
28
system/Debug/Toolbar/Views/_history.tpl
Normal file
@@ -0,0 +1,28 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Action</th>
|
||||
<th>Datetime</th>
|
||||
<th>Status</th>
|
||||
<th>Method</th>
|
||||
<th>URL</th>
|
||||
<th>Content-Type</th>
|
||||
<th>Is AJAX?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{files}
|
||||
<tr data-active="{active}">
|
||||
<td class="debug-bar-width70p">
|
||||
<button class="ci-history-load" data-time="{time}">Load</button>
|
||||
</td>
|
||||
<td class="debug-bar-width140p">{datetime}</td>
|
||||
<td>{status}</td>
|
||||
<td>{method}</td>
|
||||
<td>{url}</td>
|
||||
<td>{contentType}</td>
|
||||
<td>{isAJAX}</td>
|
||||
</tr>
|
||||
{/files}
|
||||
</tbody>
|
||||
</table>
|
||||
20
system/Debug/Toolbar/Views/_logs.tpl
Normal file
20
system/Debug/Toolbar/Views/_logs.tpl
Normal file
@@ -0,0 +1,20 @@
|
||||
{ if $logs == [] }
|
||||
<p>Nothing was logged. If you were expecting logged items, ensure that LoggerConfig file has the correct threshold set.</p>
|
||||
{ else }
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Severity</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{logs}
|
||||
<tr>
|
||||
<td>{level}</td>
|
||||
<td>{msg}</td>
|
||||
</tr>
|
||||
{/logs}
|
||||
</tbody>
|
||||
</table>
|
||||
{ endif }
|
||||
44
system/Debug/Toolbar/Views/_routes.tpl
Normal file
44
system/Debug/Toolbar/Views/_routes.tpl
Normal file
@@ -0,0 +1,44 @@
|
||||
<h3>Matched Route</h3>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
{matchedRoute}
|
||||
<tr>
|
||||
<td>Directory:</td>
|
||||
<td>{directory}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Controller:</td>
|
||||
<td>{controller}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Method:</td>
|
||||
<td>{method}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Params:</td>
|
||||
<td>{paramCount} / {truePCount}</td>
|
||||
</tr>
|
||||
{params}
|
||||
<tr class="route-params-item">
|
||||
<td>{name}</td>
|
||||
<td>{value}</td>
|
||||
</tr>
|
||||
{/params}
|
||||
{/matchedRoute}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h3>Defined Routes</h3>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
{routes}
|
||||
<tr>
|
||||
<td>{from}</td>
|
||||
<td>{to}</td>
|
||||
</tr>
|
||||
{/routes}
|
||||
</tbody>
|
||||
</table>
|
||||
403
system/Debug/Toolbar/Views/toolbar.css
Normal file
403
system/Debug/Toolbar/Views/toolbar.css
Normal file
@@ -0,0 +1,403 @@
|
||||
#debug-icon {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
margin: 0px;
|
||||
z-index: 10000;
|
||||
box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1);
|
||||
clear: both;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#debug-icon a svg {
|
||||
margin: 4px;
|
||||
max-width: 26px;
|
||||
max-height: 26px;
|
||||
}
|
||||
|
||||
#debug-bar a:active, #debug-bar a:link, #debug-bar a:visited {
|
||||
color: #dd4814;
|
||||
}
|
||||
|
||||
#debug-bar {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 36px;
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 36px;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
#debug-bar h1,
|
||||
#debug-bar h2,
|
||||
#debug-bar h3 {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
#debug-bar p {
|
||||
font-size: 12px;
|
||||
margin: 0 0 10px 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#debug-bar a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#debug-bar a:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #4e4a4a;
|
||||
}
|
||||
|
||||
#debug-bar .muted,
|
||||
#debug-bar .muted td {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#debug-bar .toolbar {
|
||||
display: block;
|
||||
background: inherit;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 0 12px 0 12px; /* give room for OS X scrollbar */
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
#debug-bar #toolbar-position > a {
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
#debug-icon.fixed-top,
|
||||
#debug-bar.fixed-top {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
#debug-icon.fixed-top,
|
||||
#debug-bar.fixed-top .toolbar {
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#debug-bar h1 {
|
||||
font-size: 16px;
|
||||
line-height: 36px;
|
||||
font-weight: 500;
|
||||
margin: 0 16px 0 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#debug-bar-link {
|
||||
padding: 6px;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 10px;
|
||||
font-size: 16px;
|
||||
line-height: 36px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
#debug-bar h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#debug-bar h2 span {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#debug-bar h3 {
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
font-weight: 200;
|
||||
margin-left: 10pt;
|
||||
}
|
||||
|
||||
#debug-bar span.ci-label {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
#debug-bar span.ci-label img {
|
||||
display: inline-block;
|
||||
margin: 6px 3px 6px 0;
|
||||
float: left;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
#debug-bar span.ci-label .badge {
|
||||
display: inline-block;
|
||||
padding: 3px 6px;
|
||||
font-size: 75%;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: 10rem;
|
||||
background-color: #5bc0de;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
#debug-bar span.ci-label .badge.active {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
#debug-bar button {
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#debug-bar button:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
#debug-bar tr[data-active="1"] {
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
|
||||
#debug-bar tr[data-active="1"]:hover {
|
||||
background-color: #a7d499;
|
||||
}
|
||||
|
||||
#debug-bar tr.current {
|
||||
background-color: #FDC894;
|
||||
}
|
||||
|
||||
#debug-bar tr.current:hover {
|
||||
background-color: #DD4814;
|
||||
}
|
||||
|
||||
#debug-bar table strong {
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
#debug-bar .ci-label {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#debug-bar .ci-label:hover {
|
||||
background-color: #eaeaea;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#debug-bar .ci-label a {
|
||||
display: block;
|
||||
padding: 0 10px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
#debug-bar .ci-label.active {
|
||||
background-color: #eaeaea;
|
||||
border-color: #bbb;
|
||||
}
|
||||
|
||||
#debug-bar .tab {
|
||||
display: none;
|
||||
background: inherit;
|
||||
padding: 1em 2em;
|
||||
border: solid #ddd;
|
||||
border-width: 1px 0;
|
||||
position: fixed;
|
||||
bottom: 35px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 -3px 10px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
max-height: 62%;
|
||||
}
|
||||
|
||||
#debug-bar.fixed-top .tab {
|
||||
top: 36px;
|
||||
bottom: auto;
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#debug-bar table {
|
||||
margin: 0 0 10px 20px;
|
||||
font-size: 0.9rem;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#debug-bar td,
|
||||
#debug-bar th {
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#debug-bar tr {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#debug-bar td {
|
||||
border: none;
|
||||
padding: 0 10px 0 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#debug-bar th {
|
||||
padding-bottom: 0.7em;
|
||||
}
|
||||
|
||||
#debug-bar tr td:first-child {
|
||||
max-width: 20%;
|
||||
}
|
||||
|
||||
#debug-bar tr td:first-child.narrow {
|
||||
width: 7em;
|
||||
}
|
||||
|
||||
#debug-bar tr:hover {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
#debug-bar table.timeline {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#debug-bar table.timeline th {
|
||||
font-size: 0.7em;
|
||||
font-weight: 200;
|
||||
text-align: left;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#debug-bar table.timeline td,
|
||||
#debug-bar table.timeline th {
|
||||
border-left: 1px solid #ddd;
|
||||
padding: 0 1em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#debug-bar table.timeline tr td:first-child,
|
||||
#debug-bar table.timeline tr th:first-child {
|
||||
border-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#debug-bar table.timeline td {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#debug-bar table.timeline .timer {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
top: 40%;
|
||||
border-radius: 4px;
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
#debug-bar .route-params,
|
||||
#debug-bar .route-params-item {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#debug-bar .route-params-item td:first-child {
|
||||
padding-left: 1em;
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.debug-view.show-view {
|
||||
border: 1px solid #dd4814;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.debug-view-path {
|
||||
background-color: #fdc894;
|
||||
color: #000;
|
||||
padding: 2px;
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
min-height: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.show-view .debug-view-path {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 748px) {
|
||||
.hide-sm {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
simple styles to replace inline styles
|
||||
*/
|
||||
.debug-bar-width30 {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.debug-bar-width10 {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.debug-bar-width70p {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.debug-bar-width140p {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.debug-bar-width20e {
|
||||
width: 20em;
|
||||
}
|
||||
|
||||
.debug-bar-width6r {
|
||||
width: 6rem;
|
||||
}
|
||||
|
||||
.debug-bar-ndisplay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-bar-alignRight {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.debug-bar-alignLeft {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.debug-bar-noverflow {
|
||||
overflow: hidden;
|
||||
}
|
||||
551
system/Debug/Toolbar/Views/toolbar.js
Normal file
551
system/Debug/Toolbar/Views/toolbar.js
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* Functionality for the CodeIgniter Debug Toolbar.
|
||||
*/
|
||||
|
||||
var ciDebugBar = {
|
||||
|
||||
toolbar : null,
|
||||
icon : null,
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
init : function () {
|
||||
this.toolbar = document.getElementById('debug-bar');
|
||||
this.icon = document.getElementById('debug-icon');
|
||||
|
||||
ciDebugBar.createListeners();
|
||||
ciDebugBar.setToolbarState();
|
||||
ciDebugBar.setToolbarPosition();
|
||||
ciDebugBar.toggleViewsHints();
|
||||
|
||||
document.getElementById('debug-bar-link').addEventListener('click', ciDebugBar.toggleToolbar, true);
|
||||
document.getElementById('debug-icon-link').addEventListener('click', ciDebugBar.toggleToolbar, true);
|
||||
|
||||
// Allows to highlight the row of the current history request
|
||||
var btn = document.querySelector('button[data-time="' + localStorage.getItem('debugbar-time') + '"]');
|
||||
ciDebugBar.addClass(btn.parentNode.parentNode, 'current');
|
||||
|
||||
historyLoad = document.getElementsByClassName('ci-history-load');
|
||||
|
||||
for (var i = 0; i < historyLoad.length; i++)
|
||||
{
|
||||
historyLoad[i].addEventListener('click', function () {
|
||||
loadDoc(this.getAttribute('data-time'));
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Display the active Tab on page load
|
||||
var tab = ciDebugBar.readCookie('debug-bar-tab');
|
||||
if (document.getElementById(tab))
|
||||
{
|
||||
var el = document.getElementById(tab);
|
||||
el.style.display = 'block';
|
||||
ciDebugBar.addClass(el, 'active');
|
||||
tab = document.querySelector('[data-tab=' + tab + ']');
|
||||
if (tab)
|
||||
{
|
||||
ciDebugBar.addClass(tab.parentNode, 'active');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
createListeners : function () {
|
||||
var buttons = [].slice.call(document.querySelectorAll('#debug-bar .ci-label a'));
|
||||
|
||||
for (var i = 0; i < buttons.length; i++)
|
||||
{
|
||||
buttons[i].addEventListener('click', ciDebugBar.showTab, true);
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
showTab: function () {
|
||||
// Get the target tab, if any
|
||||
var tab = document.getElementById(this.getAttribute('data-tab'));
|
||||
|
||||
// If the label have not a tab stops here
|
||||
if (! tab)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove debug-bar-tab cookie
|
||||
ciDebugBar.createCookie('debug-bar-tab', '', -1);
|
||||
|
||||
// Check our current state.
|
||||
var state = tab.style.display;
|
||||
|
||||
// Hide all tabs
|
||||
var tabs = document.querySelectorAll('#debug-bar .tab');
|
||||
|
||||
for (var i = 0; i < tabs.length; i++)
|
||||
{
|
||||
tabs[i].style.display = 'none';
|
||||
}
|
||||
|
||||
// Mark all labels as inactive
|
||||
var labels = document.querySelectorAll('#debug-bar .ci-label');
|
||||
|
||||
for (var i = 0; i < labels.length; i++)
|
||||
{
|
||||
ciDebugBar.removeClass(labels[i], 'active');
|
||||
}
|
||||
|
||||
// Show/hide the selected tab
|
||||
if (state != 'block')
|
||||
{
|
||||
tab.style.display = 'block';
|
||||
ciDebugBar.addClass(this.parentNode, 'active');
|
||||
// Create debug-bar-tab cookie to persistent state
|
||||
ciDebugBar.createCookie('debug-bar-tab', this.getAttribute('data-tab'), 365);
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
addClass : function (el, className) {
|
||||
if (el.classList)
|
||||
{
|
||||
el.classList.add(className);
|
||||
}
|
||||
else
|
||||
{
|
||||
el.className += ' ' + className;
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
removeClass : function (el, className) {
|
||||
if (el.classList)
|
||||
{
|
||||
el.classList.remove(className);
|
||||
}
|
||||
else
|
||||
{
|
||||
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Toggle display of a data table
|
||||
*
|
||||
* @param obj
|
||||
*/
|
||||
toggleDataTable : function (obj) {
|
||||
if (typeof obj == 'string')
|
||||
{
|
||||
obj = document.getElementById(obj + '_table');
|
||||
}
|
||||
|
||||
if (obj)
|
||||
{
|
||||
obj.style.display = obj.style.display == 'none' ? 'block' : 'none';
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Toggle tool bar from full to icon and icon to full
|
||||
*/
|
||||
toggleToolbar : function () {
|
||||
var open = ciDebugBar.toolbar.style.display != 'none';
|
||||
|
||||
ciDebugBar.icon.style.display = open == true ? 'inline-block' : 'none';
|
||||
ciDebugBar.toolbar.style.display = open == false ? 'inline-block' : 'none';
|
||||
|
||||
// Remember it for other page loads on this site
|
||||
ciDebugBar.createCookie('debug-bar-state', '', -1);
|
||||
ciDebugBar.createCookie('debug-bar-state', open == true ? 'minimized' : 'open' , 365);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets the initial state of the toolbar (open or minimized) when
|
||||
* the page is first loaded to allow it to remember the state between refreshes.
|
||||
*/
|
||||
setToolbarState: function () {
|
||||
var open = ciDebugBar.readCookie('debug-bar-state');
|
||||
|
||||
ciDebugBar.icon.style.display = open != 'open' ? 'inline-block' : 'none';
|
||||
ciDebugBar.toolbar.style.display = open == 'open' ? 'inline-block' : 'none';
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
toggleViewsHints: function () {
|
||||
// Avoid toggle hints on history requests that are not the initial
|
||||
if (localStorage.getItem('debugbar-time') != localStorage.getItem('debugbar-time-new'))
|
||||
{
|
||||
var a = document.querySelector('a[data-tab="ci-views"]');
|
||||
a.href = '#';
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeList = []; // [ Element, NewElement( 1 )/OldElement( 0 ) ]
|
||||
var sortedComments = [];
|
||||
var comments = [];
|
||||
|
||||
var getComments = function () {
|
||||
var nodes = [];
|
||||
var result = [];
|
||||
var xpathResults = document.evaluate( "//comment()[starts-with(., ' DEBUG-VIEW')]", document, null, XPathResult.ANY_TYPE, null);
|
||||
var nextNode = xpathResults.iterateNext();
|
||||
while ( nextNode )
|
||||
{
|
||||
nodes.push( nextNode );
|
||||
nextNode = xpathResults.iterateNext();
|
||||
}
|
||||
|
||||
// sort comment by opening and closing tags
|
||||
for (var i = 0; i < nodes.length; ++i)
|
||||
{
|
||||
// get file path + name to use as key
|
||||
var path = nodes[i].nodeValue.substring( 18, nodes[i].nodeValue.length - 1 );
|
||||
|
||||
if ( nodes[i].nodeValue[12] === 'S' ) // simple check for start comment
|
||||
{
|
||||
// create new entry
|
||||
result[path] = [ nodes[i], null ];
|
||||
}
|
||||
else if (result[path])
|
||||
{
|
||||
// add to existing entry
|
||||
result[path][1] = nodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// find node that has TargetNode as parentNode
|
||||
var getParentNode = function ( node, targetNode ) {
|
||||
if ( node.parentNode === null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( node.parentNode !== targetNode )
|
||||
{
|
||||
return getParentNode( node.parentNode, targetNode );
|
||||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// define invalid & outer ( also invalid ) elements
|
||||
const INVALID_ELEMENTS = [ 'NOSCRIPT', 'SCRIPT', 'STYLE' ];
|
||||
const OUTER_ELEMENTS = [ 'HTML', 'BODY', 'HEAD' ];
|
||||
|
||||
var getValidElementInner = function ( node, reverse ) {
|
||||
// handle invalid tags
|
||||
if ( OUTER_ELEMENTS.indexOf( node.nodeName ) !== -1 )
|
||||
{
|
||||
for (var i = 0; i < document.body.children.length; ++i)
|
||||
{
|
||||
var index = reverse ? document.body.children.length - ( i + 1 ) : i;
|
||||
var element = document.body.children[index];
|
||||
|
||||
// skip invalid tags
|
||||
if ( INVALID_ELEMENTS.indexOf( element.nodeName ) !== -1 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return [ element, reverse ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// get to next valid element
|
||||
while ( node !== null && INVALID_ELEMENTS.indexOf( node.nodeName ) !== -1 )
|
||||
{
|
||||
node = reverse ? node.previousElementSibling : node.nextElementSibling;
|
||||
}
|
||||
|
||||
// return non array if we couldnt find something
|
||||
if ( node === null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return [ node, reverse ];
|
||||
};
|
||||
|
||||
// get next valid element ( to be safe to add divs )
|
||||
// @return [ element, skip element ] or null if we couldnt find a valid place
|
||||
var getValidElement = function ( nodeElement ) {
|
||||
if (nodeElement)
|
||||
{
|
||||
if ( nodeElement.nextElementSibling !== null )
|
||||
{
|
||||
return getValidElementInner( nodeElement.nextElementSibling, false )
|
||||
|| getValidElementInner( nodeElement.previousElementSibling, true );
|
||||
}
|
||||
if ( nodeElement.previousElementSibling !== null )
|
||||
{
|
||||
return getValidElementInner( nodeElement.previousElementSibling, true );
|
||||
}
|
||||
}
|
||||
|
||||
// something went wrong! -> element is not in DOM
|
||||
return null;
|
||||
};
|
||||
|
||||
function showHints()
|
||||
{
|
||||
// Had AJAX? Reset view blocks
|
||||
sortedComments = getComments();
|
||||
|
||||
for (var key in sortedComments)
|
||||
{
|
||||
var startElement = getValidElement( sortedComments[key][0] );
|
||||
var endElement = getValidElement( sortedComments[key][1] );
|
||||
|
||||
// skip if we couldnt get a valid element
|
||||
if ( startElement === null || endElement === null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// find element which has same parent as startelement
|
||||
var jointParent = getParentNode( endElement[0], startElement[0].parentNode );
|
||||
if ( jointParent === null )
|
||||
{
|
||||
// find element which has same parent as endelement
|
||||
jointParent = getParentNode( startElement[0], endElement[0].parentNode );
|
||||
if ( jointParent === null )
|
||||
{
|
||||
// both tries failed
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
startElement[0] = jointParent;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
endElement[0] = jointParent;
|
||||
}
|
||||
|
||||
var debugDiv = document.createElement( 'div' ); // holder
|
||||
var debugPath = document.createElement( 'div' ); // path
|
||||
var childArray = startElement[0].parentNode.childNodes; // target child array
|
||||
var parent = startElement[0].parentNode;
|
||||
var start, end;
|
||||
|
||||
// setup container
|
||||
debugDiv.classList.add( 'debug-view' );
|
||||
debugDiv.classList.add( 'show-view' );
|
||||
debugPath.classList.add( 'debug-view-path' );
|
||||
debugPath.innerText = key;
|
||||
debugDiv.appendChild( debugPath );
|
||||
|
||||
// calc distance between them
|
||||
// start
|
||||
for (var i = 0; i < childArray.length; ++i)
|
||||
{
|
||||
// check for comment ( start & end ) -> if its before valid start element
|
||||
if ( childArray[i] === sortedComments[key][1] ||
|
||||
childArray[i] === sortedComments[key][0] ||
|
||||
childArray[i] === startElement[0] )
|
||||
{
|
||||
start = i;
|
||||
if ( childArray[i] === sortedComments[key][0] )
|
||||
{
|
||||
start++; // increase to skip the start comment
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// adjust if we want to skip the start element
|
||||
if ( startElement[1] )
|
||||
{
|
||||
start++;
|
||||
}
|
||||
|
||||
// end
|
||||
for (var i = start; i < childArray.length; ++i)
|
||||
{
|
||||
if ( childArray[i] === endElement[0] )
|
||||
{
|
||||
end = i;
|
||||
// dont break to check for end comment after end valid element
|
||||
}
|
||||
else if ( childArray[i] === sortedComments[key][1] )
|
||||
{
|
||||
// if we found the end comment, we can break
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// move elements
|
||||
var number = end - start;
|
||||
if ( endElement[1] )
|
||||
{
|
||||
number++;
|
||||
}
|
||||
for (var i = 0; i < number; ++i)
|
||||
{
|
||||
if ( INVALID_ELEMENTS.indexOf( childArray[start] ) !== -1 )
|
||||
{
|
||||
// skip invalid childs that can cause problems if moved
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
debugDiv.appendChild( childArray[start] );
|
||||
}
|
||||
|
||||
// add container to DOM
|
||||
nodeList.push( parent.insertBefore( debugDiv, childArray[start] ) );
|
||||
}
|
||||
|
||||
ciDebugBar.createCookie('debug-view', 'show', 365);
|
||||
ciDebugBar.addClass(btn, 'active');
|
||||
}
|
||||
|
||||
function hideHints()
|
||||
{
|
||||
for (var i = 0; i < nodeList.length; ++i)
|
||||
{
|
||||
var index;
|
||||
|
||||
// find index
|
||||
for (var j = 0; j < nodeList[i].parentNode.childNodes.length; ++j)
|
||||
{
|
||||
if ( nodeList[i].parentNode.childNodes[j] === nodeList[i] )
|
||||
{
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// move child back
|
||||
while ( nodeList[i].childNodes.length !== 1 )
|
||||
{
|
||||
nodeList[i].parentNode.insertBefore( nodeList[i].childNodes[1], nodeList[i].parentNode.childNodes[index].nextSibling );
|
||||
index++;
|
||||
}
|
||||
|
||||
nodeList[i].parentNode.removeChild( nodeList[i] );
|
||||
}
|
||||
nodeList.length = 0;
|
||||
|
||||
ciDebugBar.createCookie('debug-view', '', -1);
|
||||
ciDebugBar.removeClass(btn, 'active');
|
||||
}
|
||||
|
||||
var btn = document.querySelector('[data-tab=ci-views]');
|
||||
|
||||
// If the Views Collector is inactive stops here
|
||||
if (! btn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
btn.parentNode.onclick = function () {
|
||||
if (ciDebugBar.readCookie('debug-view'))
|
||||
{
|
||||
hideHints();
|
||||
}
|
||||
else
|
||||
{
|
||||
showHints();
|
||||
}
|
||||
};
|
||||
|
||||
// Determine Hints state on page load
|
||||
if (ciDebugBar.readCookie('debug-view'))
|
||||
{
|
||||
showHints();
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
setToolbarPosition: function () {
|
||||
var btnPosition = document.getElementById('toolbar-position');
|
||||
|
||||
if (ciDebugBar.readCookie('debug-bar-position') === 'top')
|
||||
{
|
||||
ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top');
|
||||
ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top');
|
||||
}
|
||||
|
||||
btnPosition.addEventListener('click', function () {
|
||||
var position = ciDebugBar.readCookie('debug-bar-position');
|
||||
|
||||
ciDebugBar.createCookie('debug-bar-position', '', -1);
|
||||
|
||||
if (!position || position === 'bottom')
|
||||
{
|
||||
ciDebugBar.createCookie('debug-bar-position', 'top', 365);
|
||||
ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top');
|
||||
ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top');
|
||||
}
|
||||
else
|
||||
{
|
||||
ciDebugBar.createCookie('debug-bar-position', 'bottom', 365);
|
||||
ciDebugBar.removeClass(ciDebugBar.icon, 'fixed-top');
|
||||
ciDebugBar.removeClass(ciDebugBar.toolbar, 'fixed-top');
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Helper to create a cookie.
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @param days
|
||||
*/
|
||||
createCookie : function (name,value,days) {
|
||||
if (days)
|
||||
{
|
||||
var date = new Date();
|
||||
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
|
||||
var expires = "; expires=" + date.toGMTString();
|
||||
}
|
||||
else
|
||||
{
|
||||
var expires = "";
|
||||
}
|
||||
|
||||
document.cookie = name + "=" + value + expires + "; path=/";
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
readCookie : function (name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
|
||||
for (var i = 0; i < ca.length; i++)
|
||||
{
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ')
|
||||
{
|
||||
c = c.substring(1,c.length);
|
||||
}
|
||||
if (c.indexOf(nameEQ) == 0)
|
||||
{
|
||||
return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
306
system/Debug/Toolbar/Views/toolbar.tpl.php
Normal file
306
system/Debug/Toolbar/Views/toolbar.tpl.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
/**
|
||||
* @var \CodeIgniter\Debug\Toolbar $this
|
||||
* @var int $totalTime
|
||||
* @var int $totalMemory
|
||||
* @var string $url
|
||||
* @var string $method
|
||||
* @var bool $isAJAX
|
||||
* @var int $startTime
|
||||
* @var int $totalTime
|
||||
* @var int $totalMemory
|
||||
* @var float $segmentDuration
|
||||
* @var int $segmentCount
|
||||
* @var string $CI_VERSION
|
||||
* @var array $collectors
|
||||
* @var array $vars
|
||||
* @var array $styles
|
||||
* @var \CodeIgniter\View\Parser $parser
|
||||
*/
|
||||
|
||||
?>
|
||||
<style type="text/css">
|
||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . '/toolbar.css')) ?>
|
||||
</style>
|
||||
|
||||
<script id="toolbar_js" type="text/javascript">
|
||||
<?= file_get_contents(__DIR__ . '/toolbar.js') ?>
|
||||
</script>
|
||||
<div id="debug-icon" class="debug-bar-ndisplay">
|
||||
<a id="debug-icon-link" href="javascript:void(0)">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="155.000000px" height="200.000000px" viewBox="0 0 155.000000 200.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)" fill="#dd4814" stroke="none">
|
||||
<path d="M737 1963 c22 -79 -7 -185 -78 -290 -18 -26 -107 -122 -197 -213
|
||||
-239 -240 -336 -371 -403 -544 -79 -206 -78 -408 5 -582 64 -134 212 -264 361
|
||||
-314 l60 -20 -30 22 c-210 152 -229 387 -48 588 25 27 48 50 51 50 4 0 7 -27
|
||||
7 -61 0 -57 2 -62 37 -95 30 -27 46 -34 78 -34 56 0 99 24 116 65 29 69 16
|
||||
120 -50 205 -105 134 -117 233 -43 347 l31 48 7 -47 c13 -82 58 -129 250 -258
|
||||
209 -141 306 -261 328 -405 11 -72 -1 -161 -31 -218 -27 -53 -112 -143 -165
|
||||
-174 -24 -14 -43 -26 -43 -28 0 -2 24 4 53 14 241 83 427 271 482 486 19 76
|
||||
19 202 -1 285 -35 152 -146 305 -299 412 l-70 49 -6 -33 c-8 -48 -26 -76 -59
|
||||
-93 -45 -23 -103 -19 -138 10 -67 57 -78 146 -37 305 30 116 32 206 5 291 -27
|
||||
89 -104 206 -162 247 -17 13 -18 12 -11 -15z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div id="debug-bar">
|
||||
<div class="toolbar">
|
||||
<span id="toolbar-position"><a href="javascript: void(0)">↕</a></span>
|
||||
<span class="ci-label">
|
||||
<a href="javascript: void(0)" data-tab="ci-timeline">
|
||||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAD7SURBVEhLY6ArSEtLK09NTbWHcvGC9PR0BaDaQiAdUl9fzwQVxg+AFvwHamqHcnGCpKQkeaDa9yD1UD09UCn8AKaBWJySkmIApFehi0ONwwRQBceBLurAh4FqFoHUAtkrgPgREN+ByYEw1DhMANVEMIhAYQ5U1wtU/wmILwLZRlAp/IBYC8gGw88CaFj3A/FnIL4ETDXGUCnyANSC/UC6HIpnQMXAqQXIvo0khxNDjcMEQEmU9AzDuNI7Lgw1DhOAJIEuhQcRKMcC+e+QNHdDpcgD6BaAANSSQqBcENFlDi6AzQKqgkFlwWhxjVI8o2OgmkFaXI8CTMDAAAAxd1O4FzLMaAAAAABJRU5ErkJggg==">
|
||||
<span class="hide-sm"><?= $totalTime ?> ms <?= $totalMemory ?> MB</span>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<?php foreach ($collectors as $c) : ?>
|
||||
<?php if (! $c['isEmpty'] && ($c['hasTabContent'] || $c['hasLabel'])) : ?>
|
||||
<span class="ci-label">
|
||||
<a href="javascript: void(0)" data-tab="ci-<?= $c['titleSafe'] ?>">
|
||||
<img src="<?= $c['icon'] ?>">
|
||||
<span class="hide-sm">
|
||||
<?= $c['title'] ?>
|
||||
<?php if (! is_null($c['badgeValue'])) : ?>
|
||||
<span class="badge"><?= $c['badgeValue'] ?></span>
|
||||
<?php endif ?>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<span class="ci-label">
|
||||
<a href="javascript: void(0)" data-tab="ci-vars">
|
||||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACLSURBVEhLYxgFJIHU1NSraWlp/6H4T0pKSjRUijoAyXAwBlrYDpViAFpmARQrJwZDtWACoCROC4D8CnR5XBiqBRMADfyNprgRKkUdAApzoCUdUNwE5MtApYYIALp6NBWBMVQLJgAaOJqK8AOgq+mSio6DggjEBtLUT0UwQ5HZIADkj6aiUTAggIEBANAEDa/lkCRlAAAAAElFTkSuQmCC">
|
||||
<span class="hide-sm">Vars</span>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<h1>
|
||||
<span class="ci-label">
|
||||
<a href="javascript: void(0)" data-tab="ci-config">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="18.60px" height="24.0px" viewBox="0 0 18.60 28.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,28.000000) scale(0.010000,-0.010000)" fill="#dd4814" stroke="none">
|
||||
<path d="M737 1963 c22 -79 -7 -185 -78 -290 -18 -26 -107 -122 -197 -213
|
||||
-239 -240 -336 -371 -403 -544 -79 -206 -78 -408 5 -582 64 -134 212 -264 361
|
||||
-314 l60 -20 -30 22 c-210 152 -229 387 -48 588 25 27 48 50 51 50 4 0 7 -27
|
||||
7 -61 0 -57 2 -62 37 -95 30 -27 46 -34 78 -34 56 0 99 24 116 65 29 69 16
|
||||
120 -50 205 -105 134 -117 233 -43 347 l31 48 7 -47 c13 -82 58 -129 250 -258
|
||||
209 -141 306 -261 328 -405 11 -72 -1 -161 -31 -218 -27 -53 -112 -143 -165
|
||||
-174 -24 -14 -43 -26 -43 -28 0 -2 24 4 53 14 241 83 427 271 482 486 19 76
|
||||
19 202 -1 285 -35 152 -146 305 -299 412 l-70 49 -6 -33 c-8 -48 -26 -76 -59
|
||||
-93 -45 -23 -103 -19 -138 10 -67 57 -78 146 -37 305 30 116 32 206 5 291 -27
|
||||
89 -104 206 -162 247 -17 13 -18 12 -11 -15z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<?= $CI_VERSION ?>
|
||||
</a>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<!-- Open/Close Toggle -->
|
||||
<a id="debug-bar-link" href="javascript:void(0)" title="Open/Close">
|
||||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEPSURBVEhL7ZVLDoJAEEThRuoGDwSEG+jCuFU34s3AK3APP1VDDSGMqI1xx0s6M/2rnlHEaMZElmWrPM+vsDvsYbQ7+us0TReSC2EBrEHxCevRYuppYLXkQpC8sVCuGfTvqSE3hFdFwUGuGfRvqSE35NUAfKZrbQNQm2jrMA+gOK+M+FmhDsRL5voHMA8gFGecq0JOXLWlQg7E7AMIxZnjOiZOEJ82gFCcedUE4gS56QP8yf8ywItz7e+RituKlkkDBoIOH4Nd4HZD4NsGYJ/Abn1xEVOcuZ8f0zc/tHiYmzTAwscBvDIK/veyQ9K/rnewjdF26q0kF1IUxZIFPAVW98x/a+qp8L2M/+HMhETRE6S8TxpZ7KGXAAAAAElFTkSuQmCC">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Timeline -->
|
||||
<div id="ci-timeline" class="tab">
|
||||
<table class="timeline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="debug-bar-width30">NAME</th>
|
||||
<th class="debug-bar-width10">COMPONENT</th>
|
||||
<th class="debug-bar-width10">DURATION</th>
|
||||
<?php for ($i = 0; $i < $segmentCount; $i++) : ?>
|
||||
<th><?= $i * $segmentDuration ?> ms</th>
|
||||
<?php endfor ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?= $this->renderTimeline($collectors, $startTime, $segmentCount, $segmentDuration,
|
||||
$styles) ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Collector-provided Tabs -->
|
||||
<?php foreach ($collectors as $c) : ?>
|
||||
<?php if (! $c['isEmpty']) : ?>
|
||||
<?php if ($c['hasTabContent']) : ?>
|
||||
<div id="ci-<?= $c['titleSafe'] ?>" class="tab">
|
||||
<h2><?= $c['title'] ?> <span><?= $c['titleDetails'] ?></span></h2>
|
||||
|
||||
<?= is_string($c['display']) ? $c['display'] : $parser->setData($c['display'])->render("_{$c['titleSafe']}.tpl") ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<!-- In & Out -->
|
||||
<div id="ci-vars" class="tab">
|
||||
|
||||
<!-- VarData from Collectors -->
|
||||
<?php if (isset($vars['varData'])) : ?>
|
||||
<?php foreach ($vars['varData'] as $heading => $items) : ?>
|
||||
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('<?= strtolower(str_replace(' ',
|
||||
'-', $heading)) ?>'); return false;">
|
||||
<h2><?= $heading ?></h2>
|
||||
</a>
|
||||
|
||||
<?php if (is_array($items)) : ?>
|
||||
|
||||
<table id="<?= strtolower(str_replace(' ', '-', $heading . '_table')) ?>">
|
||||
<tbody>
|
||||
<?php foreach ($items as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $key ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="muted">No data to display.</p>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Session -->
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('session'); return false;">
|
||||
<h2>Session User Data</h2>
|
||||
</a>
|
||||
|
||||
<?php if (isset($vars['session'])) : ?>
|
||||
<?php if (! empty($vars['session'])) : ?>
|
||||
<table id="session_table">
|
||||
<tbody>
|
||||
<?php foreach ($vars['session'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $key ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else : ?>
|
||||
<p class="muted">No data to display.</p>
|
||||
<?php endif ?>
|
||||
<?php else : ?>
|
||||
<p class="muted">Session doesn't seem to be active.</p>
|
||||
<?php endif ?>
|
||||
|
||||
<h2>Request <span>( <?= $vars['request'] ?> )</span></h2>
|
||||
|
||||
<?php if (isset($vars['get']) && $get = $vars['get']) : ?>
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('get'); return false;">
|
||||
<h3>$_GET</h3>
|
||||
</a>
|
||||
|
||||
<table id="get_table">
|
||||
<tbody>
|
||||
<?php foreach ($get as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $name ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($vars['post']) && $post = $vars['post']) : ?>
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('post'); return false;">
|
||||
<h3>$_POST</h3>
|
||||
</a>
|
||||
|
||||
<table id="post_table">
|
||||
<tbody>
|
||||
<?php foreach ($post as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $name ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($vars['headers']) && $headers = $vars['headers']) : ?>
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('request_headers'); return false;">
|
||||
<h3>Headers</h3>
|
||||
</a>
|
||||
|
||||
<table id="request_headers_table">
|
||||
<tbody>
|
||||
<?php foreach ($headers as $header => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $header ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($vars['cookies']) && $cookies = $vars['cookies']) : ?>
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('cookie'); return false;">
|
||||
<h3>Cookies</h3>
|
||||
</a>
|
||||
|
||||
<table id="cookie_table">
|
||||
<tbody>
|
||||
<?php foreach ($cookies as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $name ?></td>
|
||||
<td><?= is_array($value) ? print_r($value, true) : $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
|
||||
<h2>Response
|
||||
<span>( <?= $vars['response']['statusCode'] . ' - ' . $vars['response']['reason'] ?> )</span>
|
||||
</h2>
|
||||
|
||||
<?php if (isset($vars['headers']) && $headers = $vars['headers']) : ?>
|
||||
<a href="javascript:void(0)" onclick="ciDebugBar.toggleDataTable('response_headers'); return false;">
|
||||
<h3>Headers</h3>
|
||||
</a>
|
||||
|
||||
<table id="response_headers_table">
|
||||
<tbody>
|
||||
<?php foreach ($headers as $header => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $header ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Config Values -->
|
||||
<div id="ci-config" class="tab">
|
||||
<h2>System Configuration</h2>
|
||||
|
||||
<?= $parser->setData($config)->render('_config.tpl') ?>
|
||||
</div>
|
||||
</div>
|
||||
<style type="text/css">
|
||||
<?php foreach($styles as $name => $style) : ?>
|
||||
.<?= $name ?> {
|
||||
<?= $style ?>
|
||||
}
|
||||
|
||||
<?php endforeach ?>
|
||||
</style>
|
||||
88
system/Debug/Toolbar/Views/toolbarloader.js.php
Normal file
88
system/Debug/Toolbar/Views/toolbarloader.js.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php if (ENVIRONMENT !== 'testing') : ?>
|
||||
document.addEventListener('DOMContentLoaded', loadDoc, false);
|
||||
|
||||
function loadDoc(time) {
|
||||
if (isNaN(time)) {
|
||||
time = document.getElementById("debugbar_loader").getAttribute("data-time");
|
||||
localStorage.setItem('debugbar-time', time);
|
||||
}
|
||||
|
||||
localStorage.setItem('debugbar-time-new', time);
|
||||
|
||||
var url = "<?= rtrim(site_url(), '/') ?>";
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
var toolbar = document.getElementById("toolbarContainer");
|
||||
if (!toolbar) {
|
||||
toolbar = document.createElement('div');
|
||||
toolbar.setAttribute('id', 'toolbarContainer');
|
||||
document.body.appendChild(toolbar);
|
||||
}
|
||||
|
||||
// copy for easier manipulation
|
||||
let responseText = this.responseText;
|
||||
|
||||
// get csp blocked parts
|
||||
// the style block is the first and starts at 0
|
||||
{
|
||||
let PosBeg = responseText.indexOf( '>', responseText.indexOf( '<style' ) ) + 1;
|
||||
let PosEnd = responseText.indexOf( '</style>', PosBeg );
|
||||
document.getElementById( 'debugbar_dynamic_style' ).innerHTML = responseText.substr( PosBeg, PosEnd - PosBeg );
|
||||
responseText = responseText.substr( PosEnd + 8 );
|
||||
}
|
||||
// the script block starts right after style blocks ended
|
||||
{
|
||||
let PosBeg = responseText.indexOf( '>', responseText.indexOf( '<script' ) ) + 1;
|
||||
let PosEnd = responseText.indexOf( '</script>' );
|
||||
document.getElementById( 'debugbar_dynamic_script' ).innerHTML = responseText.substr( PosBeg, PosEnd - PosBeg );
|
||||
responseText = responseText.substr( PosEnd + 9 );
|
||||
}
|
||||
// check for last style block
|
||||
{
|
||||
let PosBeg = responseText.indexOf( '>', responseText.lastIndexOf( '<style' ) ) + 1;
|
||||
let PosEnd = responseText.indexOf( '</style>', PosBeg );
|
||||
document.getElementById( 'debugbar_dynamic_style' ).innerHTML += responseText.substr( PosBeg, PosEnd - PosBeg );
|
||||
responseText = responseText.substr( 0, PosBeg + 8 );
|
||||
}
|
||||
|
||||
toolbar.innerHTML = responseText;
|
||||
if (typeof ciDebugBar === 'object') {
|
||||
ciDebugBar.init();
|
||||
}
|
||||
} else if (this.readyState === 4 && this.status === 404) {
|
||||
console.log('CodeIgniter DebugBar: File "WRITEPATH/debugbar/debugbar_' + time + '" not found.');
|
||||
}
|
||||
};
|
||||
|
||||
xhttp.open("GET", url + "/?debugbar_time=" + time, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
// Track all AJAX requests
|
||||
if (window.ActiveXObject) {
|
||||
var oldXHR = new ActiveXObject('Microsoft.XMLHTTP');
|
||||
} else {
|
||||
var oldXHR = window.XMLHttpRequest;
|
||||
}
|
||||
|
||||
function newXHR() {
|
||||
var realXHR = new oldXHR();
|
||||
realXHR.addEventListener("readystatechange", function() {
|
||||
// Only success responses and URLs that do not contains "debugbar_time" are tracked
|
||||
if (realXHR.readyState === 4 && realXHR.status.toString()[0] === '2' && realXHR.responseURL.indexOf('debugbar_time') === -1) {
|
||||
var debugbarTime = realXHR.getResponseHeader('Debugbar-Time');
|
||||
if (debugbarTime) {
|
||||
var h2 = document.querySelector('#ci-history > h2');
|
||||
h2.innerHTML = 'History <small>You have new debug data.</small> <button onclick="loadDoc(' + debugbarTime + ')">Update</button>';
|
||||
var badge = document.querySelector('a[data-tab="ci-history"] > span > .badge');
|
||||
badge.className += ' active';
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
return realXHR;
|
||||
}
|
||||
|
||||
window.XMLHttpRequest = newXHR;
|
||||
<?php endif; ?>
|
||||
Reference in New Issue
Block a user