uawdijnntqw1x1x1
IP : 216.73.217.102
Hostname : webm003.cluster107.gra.hosting.ovh.net
Kernel : Linux webm003.cluster107.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
OS : Linux
PATH:
/
home
/
opticamezl
/
www
/
newok
/
libraries
/
..
/
libraries
/
..
/
modules
/
..
/
api
/
..
/
cli
/
..
/
language
/
..
/
debug.tar
/
/
src/AbstractDataCollector.php000064400000004532151721517170012263 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug; use DebugBar\DataCollector\DataCollector; use DebugBar\DataCollector\Renderable; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * AbstractDataCollector * * @since 4.0.0 */ abstract class AbstractDataCollector extends DataCollector implements Renderable { /** * Parameters. * * @var Registry * @since 4.0.0 */ protected $params; /** * The default formatter. * * @var DataFormatter * @since 4.0.0 */ private static $defaultDataFormatter; /** * AbstractDataCollector constructor. * * @param Registry $params Parameters. * * @since 4.0.0 */ public function __construct(Registry $params) { $this->params = $params; } /** * Get a data formatter. * * @since 4.0.0 * @return DataFormatter */ public function getDataFormatter(): DataFormatter { if ($this->dataFormater === null) { $this->dataFormater = self::getDefaultDataFormatter(); } return $this->dataFormater; } /** * Returns the default data formatter * * @since 4.0.0 * @return DataFormatter */ public static function getDefaultDataFormatter(): DataFormatter { if (self::$defaultDataFormatter === null) { self::$defaultDataFormatter = new DataFormatter(); } return self::$defaultDataFormatter; } /** * Strip the Joomla! root path. * * @param string $path The path. * * @return string * * @since 4.0.0 */ public function formatPath($path): string { return $this->getDataFormatter()->formatPath($path); } /** * Format a string from back trace. * * @param array $call The array to format * * @return string * * @since 4.0.0 */ public function formatCallerInfo(array $call): string { return $this->getDataFormatter()->formatCallerInfo($call); } } src/Extension/Debug.php000064400000056202151721517170011062 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.debug * * @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\Extension; use DebugBar\DataCollector\MessagesCollector; use DebugBar\DebugBar; use DebugBar\OpenHandler; use Joomla\Application\ApplicationEvents; use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Document\HtmlDocument; use Joomla\CMS\Log\Log; use Joomla\CMS\Log\LogEntry; use Joomla\CMS\Log\Logger\InMemoryLogger; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Profiler\Profiler; use Joomla\CMS\Session\Session; use Joomla\CMS\Uri\Uri; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\DatabaseInterface; use Joomla\Database\Event\ConnectionEvent; use Joomla\Event\DispatcherInterface; use Joomla\Event\Event; use Joomla\Event\Priority; use Joomla\Event\SubscriberInterface; use Joomla\Plugin\System\Debug\DataCollector\InfoCollector; use Joomla\Plugin\System\Debug\DataCollector\LanguageErrorsCollector; use Joomla\Plugin\System\Debug\DataCollector\LanguageFilesCollector; use Joomla\Plugin\System\Debug\DataCollector\LanguageStringsCollector; use Joomla\Plugin\System\Debug\DataCollector\MemoryCollector; use Joomla\Plugin\System\Debug\DataCollector\ProfileCollector; use Joomla\Plugin\System\Debug\DataCollector\QueryCollector; use Joomla\Plugin\System\Debug\DataCollector\RequestDataCollector; use Joomla\Plugin\System\Debug\DataCollector\SessionCollector; use Joomla\Plugin\System\Debug\DataCollector\UserCollector; use Joomla\Plugin\System\Debug\JavascriptRenderer; use Joomla\Plugin\System\Debug\JoomlaHttpDriver; use Joomla\Plugin\System\Debug\Storage\FileStorage; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Joomla! Debug plugin. * * @since 1.5 */ final class Debug extends CMSPlugin implements SubscriberInterface { use DatabaseAwareTrait; /** * List of protected keys that will be redacted in multiple data collected * * @since 4.2.4 */ public const PROTECTED_COLLECTOR_KEYS = "/password|passwd|pwd|secret|token|server_auth|_pass|smtppass|otpKey|otep/i"; /** * True if debug lang is on. * * @var boolean * @since 3.0 */ private $debugLang; /** * Holds log entries handled by the plugin. * * @var LogEntry[] * @since 3.1 */ private $logEntries = []; /** * Holds all SHOW PROFILE FOR QUERY n, indexed by n-1. * * @var array * @since 3.1.2 */ private $sqlShowProfileEach = []; /** * Holds all EXPLAIN EXTENDED for all queries. * * @var array * @since 3.1.2 */ private $explains = []; /** * @var DebugBar * @since 4.0.0 */ private $debugBar; /** * The query monitor. * * @var \Joomla\Database\Monitor\DebugMonitor * @since 4.0.0 */ private $queryMonitor; /** * AJAX marker * * @var bool * @since 4.0.0 */ protected $isAjax = false; /** * Whether displaying a logs is enabled * * @var bool * @since 4.0.0 */ protected $showLogs = false; /** * The time spent in onAfterDisconnect() * * @var float * @since 4.4.0 */ protected $timeInOnAfterDisconnect = 0; /** * @return array * * @since 4.1.3 */ public static function getSubscribedEvents(): array { return [ 'onBeforeCompileHead' => 'onBeforeCompileHead', 'onAjaxDebug' => 'onAjaxDebug', 'onBeforeRespond' => 'onBeforeRespond', 'onAfterRespond' => [ 'onAfterRespond', Priority::MIN, ], ApplicationEvents::AFTER_RESPOND => [ 'onAfterRespond', Priority::MIN, ], 'onAfterDisconnect' => 'onAfterDisconnect', ]; } /** * @param DispatcherInterface $dispatcher The object to observe -- event dispatcher. * @param array $config An optional associative array of configuration settings. * @param CMSApplicationInterface $app The app * @param DatabaseInterface $db The db * * @since 1.5 */ public function __construct(DispatcherInterface $dispatcher, $config, CMSApplicationInterface $app, DatabaseInterface $db) { parent::__construct($dispatcher, $config); $this->setApplication($app); $this->setDatabase($db); $this->debugLang = $this->getApplication()->get('debug_lang'); // Skip the plugin if debug is off if (!$this->debugLang && !$this->getApplication()->get('debug')) { return; } $this->getApplication()->set('gzip', false); ob_start(); ob_implicit_flush(false); /** @var \Joomla\Database\Monitor\DebugMonitor */ $this->queryMonitor = $this->getDatabase()->getMonitor(); if (!$this->params->get('queries', 1)) { // Remove the database driver monitor $this->getDatabase()->setMonitor(null); } $this->debugBar = new DebugBar(); // Check whether we want to track the request history for future use. if ($this->params->get('track_request_history', false)) { $storagePath = JPATH_CACHE . '/plg_system_debug_' . $this->getApplication()->getName(); $this->debugBar->setStorage(new FileStorage($storagePath)); } $this->debugBar->setHttpDriver(new JoomlaHttpDriver($this->getApplication())); $this->isAjax = $this->getApplication()->getInput()->get('option') === 'com_ajax' && $this->getApplication()->getInput()->get('plugin') === 'debug' && $this->getApplication()->getInput()->get('group') === 'system'; $this->showLogs = (bool) $this->params->get('logs', true); // Log deprecated class aliases if ($this->showLogs && $this->getApplication()->get('log_deprecated')) { foreach (\JLoader::getDeprecatedAliases() as $deprecation) { Log::add( sprintf( '%1$s has been aliased to %2$s and the former class name is deprecated. The alias will be removed in %3$s.', $deprecation['old'], $deprecation['new'], $deprecation['version'] ), Log::WARNING, 'deprecation-notes' ); } } } /** * Add an assets for debugger. * * @return void * * @since 4.0.0 */ public function onBeforeCompileHead() { // Only if debugging or language debug is enabled. if ((JDEBUG || $this->debugLang) && $this->isAuthorisedDisplayDebug() && $this->getApplication()->getDocument() instanceof HtmlDocument) { // Use our own jQuery and fontawesome instead of the debug bar shipped version $assetManager = $this->getApplication()->getDocument()->getWebAssetManager(); $assetManager->registerAndUseStyle( 'plg.system.debug', 'plg_system_debug/debug.css', [], [], ['fontawesome'] ); $assetManager->registerAndUseScript( 'plg.system.debug', 'plg_system_debug/debug.min.js', [], ['defer' => true], ['jquery'] ); } // Disable asset media version if needed. if (JDEBUG && (int) $this->params->get('refresh_assets', 1) === 0) { $this->getApplication()->getDocument()->setMediaVersion(''); } } /** * Show the debug info. * * @return void * * @since 1.6 */ public function onAfterRespond() { $endTime = microtime(true) - $this->timeInOnAfterDisconnect; $endMemory = memory_get_peak_usage(false); // Do not collect data if debugging or language debug is not enabled. if ((!JDEBUG && !$this->debugLang) || $this->isAjax) { return; } // User has to be authorised to see the debug information. if (!$this->isAuthorisedDisplayDebug()) { return; } // Load language. $this->loadLanguage(); $this->debugBar->addCollector(new InfoCollector($this->params, $this->debugBar->getCurrentRequestId())); $this->debugBar->addCollector(new UserCollector()); if (JDEBUG) { if ($this->params->get('memory', 1)) { $this->debugBar->addCollector(new MemoryCollector($this->params, $endMemory)); } if ($this->params->get('request', 1)) { $this->debugBar->addCollector(new RequestDataCollector()); } if ($this->params->get('session', 1)) { $this->debugBar->addCollector(new SessionCollector($this->params, true)); } if ($this->params->get('profile', 1)) { $this->debugBar->addCollector((new ProfileCollector($this->params))->setRequestEndTime($endTime)); } if ($this->params->get('queries', 1)) { // Remember session form token for possible future usage. $formToken = Session::getFormToken(); // Close session to collect possible session-related queries. $this->getApplication()->getSession()->close(); // Call $db->disconnect() here to trigger the onAfterDisconnect() method here in this class! $this->getDatabase()->disconnect(); $this->debugBar->addCollector(new QueryCollector($this->params, $this->queryMonitor, $this->sqlShowProfileEach, $this->explains)); } if ($this->showLogs) { $this->collectLogs(); } } if ($this->debugLang) { $this->debugBar->addCollector(new LanguageFilesCollector($this->params)); $this->debugBar->addCollector(new LanguageStringsCollector($this->params)); $this->debugBar->addCollector(new LanguageErrorsCollector($this->params)); } // Only render for HTML output. if (!($this->getApplication()->getDocument() instanceof HtmlDocument)) { $this->debugBar->stackData(); return; } $debugBarRenderer = new JavascriptRenderer($this->debugBar, Uri::root(true) . '/media/vendor/debugbar/'); $openHandlerUrl = Uri::base(true) . '/index.php?option=com_ajax&plugin=debug&group=system&format=raw&action=openhandler'; $openHandlerUrl .= '&' . ($formToken ?? Session::getFormToken()) . '=1'; $debugBarRenderer->setOpenHandlerUrl($openHandlerUrl); /** * @todo disable highlightjs from the DebugBar, import it through NPM * and deliver it through Joomla's API * Also every DebugBar script and stylesheet needs to use Joomla's API * $debugBarRenderer->disableVendor('highlightjs'); */ // Capture output. $contents = ob_get_contents(); if ($contents) { ob_end_clean(); } // No debug for Safari and Chrome redirection. if ( strpos($contents, '<html><head><meta http-equiv="refresh" content="0;') === 0 && strpos(strtolower($_SERVER['HTTP_USER_AGENT'] ?? ''), 'webkit') !== false ) { $this->debugBar->stackData(); echo $contents; return; } echo str_replace('</body>', $debugBarRenderer->renderHead() . $debugBarRenderer->render() . '</body>', $contents); } /** * AJAX handler * * @param Event $event * * @return void * * @since 4.0.0 */ public function onAjaxDebug($event) { // Do not render if debugging or language debug is not enabled. if (!JDEBUG && !$this->debugLang) { return; } // User has to be authorised to see the debug information. if (!$this->isAuthorisedDisplayDebug() || !Session::checkToken('request')) { return; } switch ($this->getApplication()->getInput()->get('action')) { case 'openhandler': $result = $event['result'] ?: []; $handler = new OpenHandler($this->debugBar); $result[] = $handler->handle($this->getApplication()->getInput()->request->getArray(), false, false); $event['result'] = $result; break; } } /** * Method to check if the current user is allowed to see the debug information or not. * * @return boolean True if access is allowed. * * @since 3.0 */ private function isAuthorisedDisplayDebug(): bool { static $result; if ($result !== null) { return $result; } // If the user is not allowed to view the output then end here. $filterGroups = (array) $this->params->get('filter_groups', []); if (!empty($filterGroups)) { $userGroups = $this->getApplication()->getIdentity()->get('groups'); if (!array_intersect($filterGroups, $userGroups)) { $result = false; return false; } } $result = true; return true; } /** * Disconnect handler for database to collect profiling and explain information. * * @param ConnectionEvent $event Event object * * @return void * * @since 4.0.0 */ public function onAfterDisconnect(ConnectionEvent $event) { if (!JDEBUG) { return; } $startTime = microtime(true); $db = $event->getDriver(); // Remove the monitor to avoid monitoring the following queries $db->setMonitor(null); if ($this->params->get('query_profiles') && $db->getServerType() === 'mysql') { try { // Check if profiling is enabled. $db->setQuery("SHOW VARIABLES LIKE 'have_profiling'"); $hasProfiling = $db->loadResult(); if ($hasProfiling) { // Run a SHOW PROFILE query. $db->setQuery('SHOW PROFILES'); $sqlShowProfiles = $db->loadAssocList(); if ($sqlShowProfiles) { foreach ($sqlShowProfiles as $qn) { // Run SHOW PROFILE FOR QUERY for each query where a profile is available (max 100). $db->setQuery('SHOW PROFILE FOR QUERY ' . (int) $qn['Query_ID']); $this->sqlShowProfileEach[$qn['Query_ID'] - 1] = $db->loadAssocList(); } } } else { $this->sqlShowProfileEach[0] = [['Error' => 'MySql have_profiling = off']]; } } catch (\Exception $e) { $this->sqlShowProfileEach[0] = [['Error' => $e->getMessage()]]; } } if ($this->params->get('query_explains') && in_array($db->getServerType(), ['mysql', 'postgresql'], true)) { $logs = $this->queryMonitor->getLogs(); $boundParams = $this->queryMonitor->getBoundParams(); foreach ($logs as $k => $query) { $dbVersion56 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '5.6', '>='); $dbVersion80 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '8.0', '>='); if ($dbVersion80) { $dbVersion56 = false; } if ((stripos($query, 'select') === 0) || ($dbVersion56 && ((stripos($query, 'delete') === 0) || (stripos($query, 'update') === 0)))) { try { $queryInstance = $db->getQuery(true); $queryInstance->setQuery('EXPLAIN ' . ($dbVersion56 ? 'EXTENDED ' : '') . $query); if ($boundParams[$k]) { foreach ($boundParams[$k] as $key => $obj) { $queryInstance->bind($key, $obj->value, $obj->dataType, $obj->length, $obj->driverOptions); } } $this->explains[$k] = $db->setQuery($queryInstance)->loadAssocList(); } catch (\Exception $e) { $this->explains[$k] = [['error' => $e->getMessage()]]; } } } } $this->timeInOnAfterDisconnect = microtime(true) - $startTime; } /** * Store log messages so they can be displayed later. * This function is passed log entries by JLogLoggerCallback. * * @param LogEntry $entry A log entry. * * @return void * * @since 3.1 * * @deprecated 4.3 will be removed in 6.0 * Use \Joomla\CMS\Log\Log::add(LogEntry $entry) instead */ public function logger(LogEntry $entry) { if (!$this->showLogs) { return; } $this->logEntries[] = $entry; } /** * Collect log messages. * * @return void * * @since 4.0.0 */ private function collectLogs() { $loggerOptions = ['group' => 'default']; $logger = new InMemoryLogger($loggerOptions); $logEntries = $logger->getCollectedEntries(); if (!$this->logEntries && !$logEntries) { return; } if ($this->logEntries) { $logEntries = array_merge($logEntries, $this->logEntries); } $logDeprecated = $this->getApplication()->get('log_deprecated', 0); $logDeprecatedCore = $this->params->get('log-deprecated-core', 0); $this->debugBar->addCollector(new MessagesCollector('log')); if ($logDeprecated) { $this->debugBar->addCollector(new MessagesCollector('deprecated')); $this->debugBar->addCollector(new MessagesCollector('deprecation-notes')); } if ($logDeprecatedCore) { $this->debugBar->addCollector(new MessagesCollector('deprecated-core')); } foreach ($logEntries as $entry) { switch ($entry->category) { case 'deprecation-notes': if ($logDeprecated) { $this->debugBar[$entry->category]->addMessage($entry->message); } break; case 'deprecated': if (!$logDeprecated && !$logDeprecatedCore) { break; } $file = ''; $line = ''; // Find the caller, skip Log methods and trigger_error function foreach ($entry->callStack as $stackEntry) { if ( !empty($stackEntry['class']) && ($stackEntry['class'] === 'Joomla\CMS\Log\LogEntry' || $stackEntry['class'] === 'Joomla\CMS\Log\Log') ) { continue; } if ( empty($stackEntry['class']) && !empty($stackEntry['function']) && $stackEntry['function'] === 'trigger_error' ) { continue; } $file = $stackEntry['file'] ?? ''; $line = $stackEntry['line'] ?? ''; break; } $category = $entry->category; $relative = $file ? str_replace(JPATH_ROOT, '', $file) : ''; if ($relative && 0 === strpos($relative, '/libraries/src')) { if (!$logDeprecatedCore) { break; } $category .= '-core'; } elseif (!$logDeprecated) { break; } $message = [ 'message' => $entry->message, 'caller' => $file . ':' . $line, // @todo 'stack' => $entry->callStack; ]; $this->debugBar[$category]->addMessage($message, 'warning'); break; case 'databasequery': // Should be collected by its own collector break; default: switch ($entry->priority) { case Log::EMERGENCY: case Log::ALERT: case Log::CRITICAL: case Log::ERROR: $level = 'error'; break; case Log::WARNING: $level = 'warning'; break; default: $level = 'info'; } $this->debugBar['log']->addMessage($entry->category . ' - ' . $entry->message, $level); break; } } } /** * Add server timing headers when profile is activated. * * @return void * * @since 4.1.0 */ public function onBeforeRespond(): void { if (!JDEBUG || !$this->params->get('profile', 1)) { return; } $metrics = ''; $moduleTime = 0; $accessTime = 0; foreach (Profiler::getInstance('Application')->getMarks() as $index => $mark) { // Ignore the before mark as the after one contains the timing of the action if (stripos($mark->label, 'before') !== false) { continue; } // Collect the module render time if (strpos($mark->label, 'mod_') !== false) { $moduleTime += $mark->time; continue; } // Collect the access render time if (strpos($mark->label, 'Access:') !== false) { $accessTime += $mark->time; continue; } $desc = str_ireplace('after', '', $mark->label); $name = preg_replace('/[^\da-z]/i', '', $desc); $metrics .= sprintf('%s;dur=%f;desc="%s", ', $index . $name, $mark->time, $desc); // Do not create too large headers, some web servers don't love them if (strlen($metrics) > 3000) { $metrics .= 'System;dur=0;desc="Data truncated to 3000 characters", '; break; } } // Add the module entry $metrics .= 'Modules;dur=' . $moduleTime . ';desc="Modules", '; // Add the access entry $metrics .= 'Access;dur=' . $accessTime . ';desc="Access"'; $this->getApplication()->setHeader('Server-Timing', $metrics); } } src/Storage/FileStorage.php000064400000011776151721517170011677 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\Storage; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\User\UserFactoryInterface; use Joomla\Filesystem\File; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Stores collected data into files * * @since 4.0.0 */ class FileStorage extends \DebugBar\Storage\FileStorage { /** * Saves collected data * * @param string $id The log id * @param string $data The log data * * @return void * * @since 4.0.0 */ public function save($id, $data) { if (!file_exists($this->dirname)) { Folder::create($this->dirname); } $dataStr = '<?php die(); ?>#(^-^)#' . json_encode($data); File::write($this->makeFilename($id), $dataStr); } /** * Returns collected data with the specified id * * @param string $id The log id * * @return array * * @since 4.0.0 */ public function get($id) { $dataStr = file_get_contents($this->makeFilename($id)); $dataStr = str_replace('<?php die(); ?>#(^-^)#', '', $dataStr); return json_decode($dataStr, true) ?: []; } /** * Returns a metadata about collected data * * @param array $filters Filtering options * @param integer $max The limit, items per page * @param integer $offset The offset * * @return array * * @since 4.0.0 */ public function find(array $filters = [], $max = 20, $offset = 0) { // Loop through all .php files and remember the modified time and id. $files = []; foreach (new \DirectoryIterator($this->dirname) as $file) { if ($file->getExtension() == 'php') { $files[] = [ 'time' => $file->getMTime(), 'id' => $file->getBasename('.php'), ]; } } // Sort the files, newest first usort( $files, function ($a, $b) { if ($a['time'] === $b['time']) { return 0; } return $a['time'] < $b['time'] ? 1 : -1; } ); // Load the metadata and filter the results. $results = []; $i = 0; foreach ($files as $file) { // When filter is empty, skip loading the offset if ($i++ < $offset && empty($filters)) { $results[] = null; continue; } $data = $this->get($file['id']); if (!$this->isSecureToReturnData($data)) { continue; } $meta = $data['__meta']; unset($data); if ($this->filter($meta, $filters)) { $results[] = $meta; } if (\count($results) >= ($max + $offset)) { break; } } return \array_slice($results, $offset, $max); } /** * Get a full path to the file * * @param string $id The log id * * @return string * * @since 4.0.0 */ public function makeFilename($id) { return $this->dirname . basename($id) . '.php'; } /** * Check if the user is allowed to view the request. Users can only see their own requests. * * @param array $data The data item to process * * @return boolean * * @since 4.2.4 */ private function isSecureToReturnData($data): bool { /** * We only started this collector in Joomla 4.2.4 - any older files we have to assume are insecure. */ if (!array_key_exists('juser', $data)) { return false; } $currentUser = Factory::getUser(); $currentUserId = $currentUser->id; $currentUserSuperAdmin = $currentUser->authorise('core.admin'); /** * Guests aren't allowed to look at other requests because there's no guarantee it's the same guest. Potentially * in the future this could be refined to check the session ID to show some requests. But it's unlikely we want * guests to be using the debug bar anyhow */ if ($currentUserId === 0) { return false; } /** @var \Joomla\CMS\User\User $user */ $user = Factory::getContainer()->get(UserFactoryInterface::class) ->loadUserById($data['juser']['user_id']); // Super users are allowed to look at other users requests. Otherwise users can only see their own requests. if ($currentUserSuperAdmin || $user->id === $currentUserId) { return true; } return false; } } src/DataFormatter.php000064400000005072151721517170010614 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug; use DebugBar\DataFormatter\DataFormatter as DebugBarDataFormatter; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * DataFormatter * * @since 4.0.0 */ class DataFormatter extends DebugBarDataFormatter { /** * Strip the root path. * * @param string $path The path. * @param string $replacement The replacement * * @return string * * @since 4.0.0 */ public function formatPath($path, $replacement = ''): string { return str_replace(JPATH_ROOT, $replacement, $path); } /** * Format a string from back trace. * * @param array $call The array to format * * @return string * * @since 4.0.0 */ public function formatCallerInfo(array $call): string { $string = ''; if (isset($call['class'])) { // If entry has Class/Method print it. $string .= htmlspecialchars($call['class'] . $call['type'] . $call['function']) . '()'; } elseif (isset($call['args'][0]) && \is_array($call['args'][0])) { $string .= htmlspecialchars($call['function']) . ' ('; foreach ($call['args'][0] as $arg) { // Check if the arguments can be used as string if (\is_object($arg) && !method_exists($arg, '__toString')) { $arg = \get_class($arg); } // Keep only the size of array if (\is_array($arg)) { $arg = 'Array(count=' . \count($arg) . ')'; } $string .= htmlspecialchars($arg) . ', '; } $string = rtrim($string, ', ') . ')'; } elseif (isset($call['args'][0])) { $string .= htmlspecialchars($call['function']) . '('; if (is_scalar($call['args'][0])) { $string .= $call['args'][0]; } elseif (\is_object($call['args'][0])) { $string .= \get_class($call['args'][0]); } else { $string .= gettype($call['args'][0]); } $string .= ')'; } else { // It's a function. $string .= htmlspecialchars($call['function']) . '()'; } return $string; } } src/DataCollector/RequestDataCollector.php000064400000003573151721517170014674 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use Joomla\Plugin\System\Debug\Extension\Debug; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Collects info about the request content while redacting potentially secret content * * @since 4.2.4 */ class RequestDataCollector extends \DebugBar\DataCollector\RequestDataCollector { /** * Called by the DebugBar when data needs to be collected * * @since 4.2.4 * * @return array */ public function collect() { $vars = ['_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER']; $returnData = []; foreach ($vars as $var) { if (isset($GLOBALS[$var])) { $key = "$" . $var; $data = $GLOBALS[$var]; // Replace Joomla session data from session data, it will be collected by SessionCollector if ($var === '_SESSION' && !empty($data['joomla'])) { $data['joomla'] = '***redacted***'; } array_walk_recursive($data, static function (&$value, $key) { if (!preg_match(Debug::PROTECTED_COLLECTOR_KEYS, $key)) { return; } $value = '***redacted***'; }); if ($this->isHtmlVarDumperUsed()) { $returnData[$key] = $this->getVarDumper()->renderVar($data); } else { $returnData[$key] = $this->getDataFormatter()->formatVar($data); } } } return $returnData; } } src/DataCollector/UserCollector.php000064400000002574151721517170013370 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DataCollector\DataCollectorInterface; use Joomla\CMS\Factory; use Joomla\CMS\User\UserFactoryInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * User collector that stores the user id of the person making the request allowing us to filter on it after storage * * @since 4.2.4 */ class UserCollector implements DataCollectorInterface { /** * Collector name. * * @var string * @since 4.2.4 */ private $name = 'juser'; /** * Called by the DebugBar when data needs to be collected * * @since 4.2.4 * * @return array Collected data */ public function collect() { $user = Factory::getApplication()->getIdentity() ?: Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById(0); return ['user_id' => $user->id]; } /** * Returns the unique name of the collector * * @since 4.2.4 * * @return string */ public function getName() { return $this->name; } } src/DataCollector/ProfileCollector.php000064400000020540151721517170014043 0ustar00<?php /** * This file is part of the DebugBar package. * * @copyright (c) 2013 Maxime Bouroumeau-Fuseau * @license For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DebugBarException; use Joomla\CMS\Profiler\Profiler; use Joomla\Plugin\System\Debug\AbstractDataCollector; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Collects info about the request duration as well as providing * a way to log duration of any operations * * @since version */ class ProfileCollector extends AbstractDataCollector { /** * Request start time. * * @var float * @since 4.0.0 */ protected $requestStartTime; /** * Request end time. * * @var float * @since 4.0.0 */ protected $requestEndTime; /** * Started measures. * * @var array * @since 4.0.0 */ protected $startedMeasures = []; /** * Measures. * * @var array * @since 4.0.0 */ protected $measures = []; /** * Constructor. * * @param Registry $params Parameters. * * @since 4.0.0 */ public function __construct(Registry $params) { if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { $this->requestStartTime = $_SERVER['REQUEST_TIME_FLOAT']; } else { $this->requestStartTime = microtime(true); } parent::__construct($params); } /** * Starts a measure. * * @param string $name Internal name, used to stop the measure * @param string|null $label Public name * @param string|null $collector The source of the collector * * @return void * * @since 4.0.0 */ public function startMeasure($name, $label = null, $collector = null) { $start = microtime(true); $this->startedMeasures[$name] = [ 'label' => $label ?: $name, 'start' => $start, 'collector' => $collector, ]; } /** * Check a measure exists * * @param string $name Group name. * * @return bool * * @since 4.0.0 */ public function hasStartedMeasure($name): bool { return isset($this->startedMeasures[$name]); } /** * Stops a measure. * * @param string $name Measurement name. * @param array $params Parameters * * @return void * * @since 4.0.0 * * @throws DebugBarException */ public function stopMeasure($name, array $params = []) { $end = microtime(true); if (!$this->hasStartedMeasure($name)) { throw new DebugBarException("Failed stopping measure '$name' because it hasn't been started"); } $this->addMeasure($this->startedMeasures[$name]['label'], $this->startedMeasures[$name]['start'], $end, $params, $this->startedMeasures[$name]['collector']); unset($this->startedMeasures[$name]); } /** * Adds a measure * * @param string $label A label. * @param float $start Start of request. * @param float $end End of request. * @param array $params Parameters. * @param string|null $collector A collector. * * @return void * * @since 4.0.0 */ public function addMeasure($label, $start, $end, array $params = [], $collector = null) { $this->measures[] = [ 'label' => $label, 'start' => $start, 'relative_start' => $start - $this->requestStartTime, 'end' => $end, 'relative_end' => $end - $this->requestEndTime, 'duration' => $end - $start, 'duration_str' => $this->getDataFormatter()->formatDuration($end - $start), 'params' => $params, 'collector' => $collector, ]; } /** * Utility function to measure the execution of a Closure * * @param string $label A label. * @param \Closure $closure A closure. * @param string|null $collector A collector. * * @return void * * @since 4.0.0 */ public function measure($label, \Closure $closure, $collector = null) { $name = spl_object_hash($closure); $this->startMeasure($name, $label, $collector); $result = $closure(); $params = \is_array($result) ? $result : []; $this->stopMeasure($name, $params); } /** * Returns an array of all measures * * @return array * * @since 4.0.0 */ public function getMeasures(): array { return $this->measures; } /** * Returns the request start time * * @return float * * @since 4.0.0 */ public function getRequestStartTime(): float { return $this->requestStartTime; } /** * Returns the request end time * * @return float * * @since 4.0.0 */ public function getRequestEndTime(): float { return $this->requestEndTime; } /** * Returns the duration of a request * * @return float * * @since 4.0.0 */ public function getRequestDuration(): float { if ($this->requestEndTime !== null) { return $this->requestEndTime - $this->requestStartTime; } return microtime(true) - $this->requestStartTime; } /** * Sets request end time. * * @param float $time Request end time. * * @return $this * * @since 4.4.0 */ public function setRequestEndTime($time): self { $this->requestEndTime = $time; return $this; } /** * Called by the DebugBar when data needs to be collected * * @return array Collected data * * @since 4.0.0 */ public function collect(): array { $this->requestEndTime = $this->requestEndTime ?? microtime(true); $start = $this->requestStartTime; $marks = Profiler::getInstance('Application')->getMarks(); foreach ($marks as $mark) { $mem = $this->getDataFormatter()->formatBytes(abs($mark->memory) * 1048576); $label = $mark->label . " ($mem)"; $end = $start + $mark->time / 1000; $this->addMeasure($label, $start, $end); $start = $end; } foreach (array_keys($this->startedMeasures) as $name) { $this->stopMeasure($name); } usort( $this->measures, function ($a, $b) { if ($a['start'] === $b['start']) { return 0; } return $a['start'] < $b['start'] ? -1 : 1; } ); return [ 'start' => $this->requestStartTime, 'end' => $this->requestEndTime, 'duration' => $this->getRequestDuration(), 'duration_str' => $this->getDataFormatter()->formatDuration($this->getRequestDuration()), 'measures' => array_values($this->measures), 'rawMarks' => $marks, ]; } /** * Returns the unique name of the collector * * @return string * * @since 4.0.0 */ public function getName(): string { return 'profile'; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @return array * * @since 4.0.0 */ public function getWidgets(): array { return [ 'profileTime' => [ 'icon' => 'clock-o', 'tooltip' => 'Request Duration', 'map' => 'profile.duration_str', 'default' => "'0ms'", ], 'profile' => [ 'icon' => 'clock-o', 'widget' => 'PhpDebugBar.Widgets.TimelineWidget', 'map' => 'profile', 'default' => '{}', ], ]; } } src/DataCollector/LanguageFilesCollector.php000064400000006030151721517170015147 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DataCollector\AssetProvider; use Joomla\CMS\Factory; use Joomla\CMS\Uri\Uri; use Joomla\Plugin\System\Debug\AbstractDataCollector; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * LanguageFilesDataCollector * * @since 4.0.0 */ class LanguageFilesCollector extends AbstractDataCollector implements AssetProvider { /** * Collector name. * * @var string * @since 4.0.0 */ private $name = 'languageFiles'; /** * The count. * * @var integer * @since 4.0.0 */ private $count = 0; /** * Called by the DebugBar when data needs to be collected * * @since 4.0.0 * * @return array Collected data */ public function collect(): array { $paths = Factory::getLanguage()->getPaths(); $loaded = []; foreach ($paths as $extension => $files) { $loaded[$extension] = []; foreach ($files as $file => $status) { $loaded[$extension][$file] = $status; if ($status) { $this->count++; } } } return [ 'loaded' => $loaded, 'xdebugLink' => $this->getXdebugLinkTemplate(), 'jroot' => JPATH_ROOT, 'count' => $this->count, ]; } /** * Returns the unique name of the collector * * @since 4.0.0 * * @return string */ public function getName(): string { return $this->name; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @since 4.0.0 * * @return array */ public function getWidgets(): array { return [ 'loaded' => [ 'icon' => 'language', 'widget' => 'PhpDebugBar.Widgets.languageFilesWidget', 'map' => $this->name, 'default' => '[]', ], 'loaded:badge' => [ 'map' => $this->name . '.count', 'default' => 'null', ], ]; } /** * Returns an array with the following keys: * - base_path * - base_url * - css: an array of filenames * - js: an array of filenames * * @since 4.0.0 * @return array */ public function getAssets(): array { return [ 'js' => Uri::root(true) . '/media/plg_system_debug/widgets/languageFiles/widget.min.js', 'css' => Uri::root(true) . '/media/plg_system_debug/widgets/languageFiles/widget.min.css', ]; } } src/DataCollector/QueryCollector.php000064400000016123151721517170013552 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DataCollector\AssetProvider; use Joomla\CMS\Uri\Uri; use Joomla\Database\Monitor\DebugMonitor; use Joomla\Plugin\System\Debug\AbstractDataCollector; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * QueryDataCollector * * @since 4.0.0 */ class QueryCollector extends AbstractDataCollector implements AssetProvider { /** * Collector name. * * @var string * @since 4.0.0 */ private $name = 'queries'; /** * The query monitor. * * @var DebugMonitor * @since 4.0.0 */ private $queryMonitor; /** * Profile data. * * @var array * @since 4.0.0 */ private $profiles; /** * Explain data. * * @var array * @since 4.0.0 */ private $explains; /** * Accumulated Duration. * * @var integer * @since 4.0.0 */ private $accumulatedDuration = 0; /** * Accumulated Memory. * * @var integer * @since 4.0.0 */ private $accumulatedMemory = 0; /** * Constructor. * * @param Registry $params Parameters. * @param DebugMonitor $queryMonitor Query monitor. * @param array $profiles Profile data. * @param array $explains Explain data * * @since 4.0.0 */ public function __construct(Registry $params, DebugMonitor $queryMonitor, array $profiles, array $explains) { $this->queryMonitor = $queryMonitor; parent::__construct($params); $this->profiles = $profiles; $this->explains = $explains; } /** * Called by the DebugBar when data needs to be collected * * @since 4.0.0 * * @return array Collected data */ public function collect(): array { $statements = $this->getStatements(); return [ 'data' => [ 'statements' => $statements, 'nb_statements' => \count($statements), 'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($this->accumulatedDuration), 'memory_usage_str' => $this->getDataFormatter()->formatBytes($this->accumulatedMemory), 'xdebug_link' => $this->getXdebugLinkTemplate(), 'root_path' => JPATH_ROOT, ], 'count' => \count($this->queryMonitor->getLogs()), ]; } /** * Returns the unique name of the collector * * @since 4.0.0 * * @return string */ public function getName(): string { return $this->name; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @since 4.0.0 * * @return array */ public function getWidgets(): array { return [ 'queries' => [ 'icon' => 'database', 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget', 'map' => $this->name . '.data', 'default' => '[]', ], 'queries:badge' => [ 'map' => $this->name . '.count', 'default' => 'null', ], ]; } /** * Assets for the collector. * * @since 4.0.0 * * @return array */ public function getAssets(): array { return [ 'css' => Uri::root(true) . '/media/plg_system_debug/widgets/sqlqueries/widget.min.css', 'js' => Uri::root(true) . '/media/plg_system_debug/widgets/sqlqueries/widget.min.js', ]; } /** * Prepare the executed statements data. * * @since 4.0.0 * * @return array */ private function getStatements(): array { $statements = []; $logs = $this->queryMonitor->getLogs(); $boundParams = $this->queryMonitor->getBoundParams(); $timings = $this->queryMonitor->getTimings(); $memoryLogs = $this->queryMonitor->getMemoryLogs(); $stacks = $this->queryMonitor->getCallStacks(); $collectStacks = $this->params->get('query_traces'); foreach ($logs as $id => $item) { $queryTime = 0; $queryMemory = 0; if ($timings && isset($timings[$id * 2 + 1])) { // Compute the query time. $queryTime = ($timings[$id * 2 + 1] - $timings[$id * 2]); $this->accumulatedDuration += $queryTime; } if ($memoryLogs && isset($memoryLogs[$id * 2 + 1])) { // Compute the query memory usage. $queryMemory = ($memoryLogs[$id * 2 + 1] - $memoryLogs[$id * 2]); $this->accumulatedMemory += $queryMemory; } $trace = []; $callerLocation = ''; if (isset($stacks[$id])) { $cnt = 0; foreach ($stacks[$id] as $i => $stack) { $class = $stack['class'] ?? ''; $file = $stack['file'] ?? ''; $line = $stack['line'] ?? ''; $caller = $this->formatCallerInfo($stack); $location = $file && $line ? "$file:$line" : 'same'; $isCaller = 0; if (\Joomla\Database\DatabaseDriver::class === $class && false === strpos($file, 'DatabaseDriver.php')) { $callerLocation = $location; $isCaller = 1; } if ($collectStacks) { $trace[] = [\count($stacks[$id]) - $cnt, $isCaller, $caller, $file, $line]; } $cnt++; } } $explain = $this->explains[$id] ?? []; $explainColumns = []; // Extract column labels for Explain table if ($explain) { $explainColumns = array_keys(reset($explain)); } $statements[] = [ 'sql' => $item, 'params' => $boundParams[$id] ?? [], 'duration_str' => $this->getDataFormatter()->formatDuration($queryTime), 'memory_str' => $this->getDataFormatter()->formatBytes($queryMemory), 'caller' => $callerLocation, 'callstack' => $trace, 'explain' => $explain, 'explain_col' => $explainColumns, 'profile' => $this->profiles[$id] ?? [], ]; } return $statements; } } src/DataCollector/MemoryCollector.php000064400000006334151721517170013720 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use Joomla\Plugin\System\Debug\AbstractDataCollector; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Collects info about the request duration as well as providing * a way to log duration of any operations * * @since 4.4.0 */ class MemoryCollector extends AbstractDataCollector { /** * @var boolean * @since 4.4.0 */ protected $realUsage = false; /** * @var float * @since 4.4.0 */ protected $peakUsage = 0; /** * @param Registry $params Parameters. * @param float $peakUsage * @param boolean $realUsage * * @since 4.4.0 */ public function __construct(Registry $params, $peakUsage = null, $realUsage = null) { parent::__construct($params); if ($peakUsage !== null) { $this->peakUsage = $peakUsage; } if ($realUsage !== null) { $this->realUsage = $realUsage; } } /** * Returns whether total allocated memory page size is used instead of actual used memory size * by the application. See $real_usage parameter on memory_get_peak_usage for details. * * @return boolean * * @since 4.4.0 */ public function getRealUsage() { return $this->realUsage; } /** * Sets whether total allocated memory page size is used instead of actual used memory size * by the application. See $real_usage parameter on memory_get_peak_usage for details. * * @param boolean $realUsage * * @since 4.4.0 */ public function setRealUsage($realUsage) { $this->realUsage = $realUsage; } /** * Returns the peak memory usage * * @return integer * * @since 4.4.0 */ public function getPeakUsage() { return $this->peakUsage; } /** * Updates the peak memory usage value * * @since 4.4.0 */ public function updatePeakUsage() { if ($this->peakUsage === null) { $this->peakUsage = memory_get_peak_usage($this->realUsage); } } /** * @return array * * @since 4.4.0 */ public function collect() { $this->updatePeakUsage(); return [ 'peak_usage' => $this->peakUsage, 'peak_usage_str' => $this->getDataFormatter()->formatBytes($this->peakUsage, 3), ]; } /** * @return string * * @since 4.4.0 */ public function getName() { return 'memory'; } /** * @return array * * @since 4.4.0 */ public function getWidgets() { return [ 'memory' => [ 'icon' => 'cogs', 'tooltip' => 'Memory Usage', 'map' => 'memory.peak_usage_str', 'default' => "'0B'", ], ]; } } src/DataCollector/SessionCollector.php000064400000005641151721517170014073 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use Joomla\CMS\Factory; use Joomla\Plugin\System\Debug\AbstractDataCollector; use Joomla\Plugin\System\Debug\Extension\Debug; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * SessionDataCollector * * @since 4.0.0 */ class SessionCollector extends AbstractDataCollector { /** * Collector name. * * @var string * @since 4.0.0 */ private $name = 'session'; /** * Collected data. * * @var array * @since 4.4.0 */ protected $sessionData; /** * Constructor. * * @param Registry $params Parameters. * @param bool $collect Collect the session data. * * @since 4.4.0 */ public function __construct($params, $collect = false) { parent::__construct($params); if ($collect) { $this->collect(); } } /** * Called by the DebugBar when data needs to be collected * * @param bool $overwrite Overwrite the previously collected session data. * * @return array Collected data * * @since 4.0.0 */ public function collect($overwrite = false) { if ($this->sessionData === null || $overwrite) { $this->sessionData = []; $data = Factory::getApplication()->getSession()->all(); // redact value of potentially secret keys array_walk_recursive($data, static function (&$value, $key) { if (!preg_match(Debug::PROTECTED_COLLECTOR_KEYS, $key)) { return; } $value = '***redacted***'; }); foreach ($data as $key => $value) { $this->sessionData[$key] = $this->getDataFormatter()->formatVar($value); } } return ['data' => $this->sessionData]; } /** * Returns the unique name of the collector * * @since 4.0.0 * * @return string */ public function getName() { return $this->name; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @since 4.0.0 * * @return array */ public function getWidgets() { return [ 'session' => [ 'icon' => 'key', 'widget' => 'PhpDebugBar.Widgets.VariableListWidget', 'map' => $this->name . '.data', 'default' => '[]', ], ]; } } src/DataCollector/LanguageStringsCollector.php000064400000011452151721517170015542 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DataCollector\AssetProvider; use Joomla\CMS\Factory; use Joomla\CMS\Language\Language; use Joomla\CMS\Uri\Uri; use Joomla\Plugin\System\Debug\AbstractDataCollector; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * LanguageStringsDataCollector * * @since 4.0.0 */ class LanguageStringsCollector extends AbstractDataCollector implements AssetProvider { /** * Collector name. * * @var string * @since 4.0.0 */ private $name = 'languageStrings'; /** * Called by the DebugBar when data needs to be collected * * @since 4.0.0 * * @return array Collected data */ public function collect(): array { return [ 'data' => $this->getData(), 'count' => $this->getCount(), ]; } /** * Returns the unique name of the collector * * @since 4.0.0 * * @return string */ public function getName(): string { return $this->name; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @since 4.0.0 * * @return array */ public function getWidgets(): array { return [ 'untranslated' => [ 'icon' => 'question-circle', 'widget' => 'PhpDebugBar.Widgets.languageStringsWidget', 'map' => $this->name . '.data', 'default' => '', ], 'untranslated:badge' => [ 'map' => $this->name . '.count', 'default' => 'null', ], ]; } /** * Returns an array with the following keys: * - base_path * - base_url * - css: an array of filenames * - js: an array of filenames * * @since 4.0.0 * @return array */ public function getAssets(): array { return [ 'js' => Uri::root(true) . '/media/plg_system_debug/widgets/languageStrings/widget.min.js', 'css' => Uri::root(true) . '/media/plg_system_debug/widgets/languageStrings/widget.min.css', ]; } /** * Collect data. * * @return array * * @since 4.0.0 */ private function getData(): array { $orphans = Factory::getLanguage()->getOrphans(); $data = []; foreach ($orphans as $orphan => $occurrences) { $data[$orphan] = []; foreach ($occurrences as $occurrence) { $item = []; $item['string'] = $occurrence['string'] ?? 'n/a'; $item['trace'] = []; $item['caller'] = ''; if (isset($occurrence['trace'])) { $cnt = 0; $trace = []; $callerLocation = ''; array_shift($occurrence['trace']); foreach ($occurrence['trace'] as $i => $stack) { $class = $stack['class'] ?? ''; $file = $stack['file'] ?? ''; $line = $stack['line'] ?? ''; $caller = $this->formatCallerInfo($stack); $location = $file && $line ? "$file:$line" : 'same'; $isCaller = 0; if (!$callerLocation && $class !== Language::class && !strpos($file, 'Text.php')) { $callerLocation = $location; $isCaller = 1; } $trace[] = [ \count($occurrence['trace']) - $cnt, $isCaller, $caller, $file, $line, ]; $cnt++; } $item['trace'] = $trace; $item['caller'] = $callerLocation; } $data[$orphan][] = $item; } } return [ 'orphans' => $data, 'jroot' => JPATH_ROOT, 'xdebugLink' => $this->getXdebugLinkTemplate(), ]; } /** * Get a count value. * * @return integer * * @since 4.0.0 */ private function getCount(): int { return \count(Factory::getLanguage()->getOrphans()); } } src/DataCollector/InfoCollector.php000064400000012647151721517170013347 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DataCollector\AssetProvider; use Joomla\CMS\Application\AdministratorApplication; use Joomla\CMS\Application\SiteApplication; use Joomla\CMS\Factory; use Joomla\CMS\Uri\Uri; use Joomla\CMS\User\User; use Joomla\Plugin\System\Debug\AbstractDataCollector; use Joomla\Registry\Registry; use Psr\Http\Message\ResponseInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * InfoDataCollector * * @since 4.0.0 */ class InfoCollector extends AbstractDataCollector implements AssetProvider { /** * Collector name. * * @var string * @since 4.0.0 */ private $name = 'info'; /** * Request ID. * * @var string * @since 4.0.0 */ private $requestId; /** * InfoDataCollector constructor. * * @param Registry $params Parameters * @param string $requestId Request ID * * @since 4.0.0 */ public function __construct(Registry $params, $requestId) { $this->requestId = $requestId; parent::__construct($params); } /** * Returns the unique name of the collector * * @since 4.0.0 * @return string */ public function getName(): string { return $this->name; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @since 4.0.0 * @return array */ public function getWidgets(): array { return [ 'info' => [ 'icon' => 'info-circle', 'title' => 'J! Info', 'widget' => 'PhpDebugBar.Widgets.InfoWidget', 'map' => $this->name, 'default' => '{}', ], ]; } /** * Returns an array with the following keys: * - base_path * - base_url * - css: an array of filenames * - js: an array of filenames * * @since 4.0.0 * @return array */ public function getAssets(): array { return [ 'js' => Uri::root(true) . '/media/plg_system_debug/widgets/info/widget.min.js', 'css' => Uri::root(true) . '/media/plg_system_debug/widgets/info/widget.min.css', ]; } /** * Called by the DebugBar when data needs to be collected * * @since 4.0.0 * * @return array Collected data */ public function collect(): array { /** @type SiteApplication|AdministratorApplication $application */ $application = Factory::getApplication(); $model = $application->bootComponent('com_admin') ->getMVCFactory()->createModel('Sysinfo', 'Administrator'); return [ 'phpVersion' => PHP_VERSION, 'joomlaVersion' => JVERSION, 'requestId' => $this->requestId, 'identity' => $this->getIdentityInfo($application->getIdentity()), 'response' => $this->getResponseInfo($application->getResponse()), 'template' => $this->getTemplateInfo($application->getTemplate(true)), 'database' => $this->getDatabaseInfo($model->getInfo()), ]; } /** * Get Identity info. * * @param User $identity The identity. * * @since 4.0.0 * * @return array */ private function getIdentityInfo(User $identity): array { if (!$identity->id) { return ['type' => 'guest']; } return [ 'type' => 'user', 'id' => $identity->id, 'name' => $identity->name, 'username' => $identity->username, ]; } /** * Get response info. * * @param ResponseInterface $response The response. * * @since 4.0.0 * * @return array */ private function getResponseInfo(ResponseInterface $response): array { return [ 'status_code' => $response->getStatusCode(), ]; } /** * Get template info. * * @param object $template The template. * * @since 4.0.0 * * @return array */ private function getTemplateInfo($template): array { return [ 'template' => $template->template ?? '', 'home' => $template->home ?? '', 'id' => $template->id ?? '', ]; } /** * Get database info. * * @param array $info General information. * * @since 4.0.0 * * @return array */ private function getDatabaseInfo(array $info): array { return [ 'dbserver' => $info['dbserver'] ?? '', 'dbversion' => $info['dbversion'] ?? '', 'dbcollation' => $info['dbcollation'] ?? '', 'dbconnectioncollation' => $info['dbconnectioncollation'] ?? '', 'dbconnectionencryption' => $info['dbconnectionencryption'] ?? '', 'dbconnencryptsupported' => $info['dbconnencryptsupported'] ?? '', ]; } } src/DataCollector/LanguageErrorsCollector.php000064400000006617151721517170015374 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug\DataCollector; use DebugBar\DataCollector\AssetProvider; use Joomla\CMS\Factory; use Joomla\CMS\Uri\Uri; use Joomla\Plugin\System\Debug\AbstractDataCollector; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * LanguageErrorsDataCollector * * @since 4.0.0 */ class LanguageErrorsCollector extends AbstractDataCollector implements AssetProvider { /** * Collector name. * * @var string * @since 4.0.0 */ private $name = 'languageErrors'; /** * The count. * * @var integer * @since 4.0.0 */ private $count = 0; /** * Called by the DebugBar when data needs to be collected * * @since 4.0.0 * * @return array Collected data */ public function collect(): array { return [ 'data' => [ 'files' => $this->getData(), 'jroot' => JPATH_ROOT, 'xdebugLink' => $this->getXdebugLinkTemplate(), ], 'count' => $this->getCount(), ]; } /** * Returns the unique name of the collector * * @since 4.0.0 * * @return string */ public function getName(): string { return $this->name; } /** * Returns a hash where keys are control names and their values * an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()} * * @since 4.0.0 * * @return array */ public function getWidgets(): array { return [ 'errors' => [ 'icon' => 'warning', 'widget' => 'PhpDebugBar.Widgets.languageErrorsWidget', 'map' => $this->name . '.data', 'default' => '', ], 'errors:badge' => [ 'map' => $this->name . '.count', 'default' => 'null', ], ]; } /** * Returns an array with the following keys: * - base_path * - base_url * - css: an array of filenames * - js: an array of filenames * * @since 4.0.0 * @return array */ public function getAssets() { return [ 'js' => Uri::root(true) . '/media/plg_system_debug/widgets/languageErrors/widget.min.js', 'css' => Uri::root(true) . '/media/plg_system_debug/widgets/languageErrors/widget.min.css', ]; } /** * Collect data. * * @return array * * @since 4.0.0 */ private function getData(): array { $errorFiles = Factory::getLanguage()->getErrorFiles(); $errors = []; if (\count($errorFiles)) { foreach ($errorFiles as $file => $lines) { foreach ($lines as $line) { $errors[] = [$file, $line]; $this->count++; } } } return $errors; } /** * Get a count value. * * @return int * * @since 4.0.0 */ private function getCount(): int { return $this->count; } } src/JoomlaHttpDriver.php000064400000005075151721517170011317 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug; use DebugBar\HttpDriverInterface; use Joomla\Application\WebApplicationInterface; use Joomla\CMS\Application\CMSApplicationInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Joomla HTTP driver for DebugBar * * @since 4.1.5 */ final class JoomlaHttpDriver implements HttpDriverInterface { /** * @var CMSApplicationInterface * * @since 4.1.5 */ private $app; /** * @var array * * @since 4.1.5 */ private $dummySession = []; /** * Constructor. * * @param CMSApplicationInterface $app * * @since 4.1.5 */ public function __construct(CMSApplicationInterface $app) { $this->app = $app; } /** * Sets HTTP headers * * @param array $headers * * @since 4.1.5 */ public function setHeaders(array $headers) { if ($this->app instanceof WebApplicationInterface) { foreach ($headers as $name => $value) { $this->app->setHeader($name, $value, true); } } } /** * Checks if the session is started * * @return boolean * * @since 4.1.5 */ public function isSessionStarted() { return true; } /** * Sets a value in the session * * @param string $name * @param string $value * * @since 4.1.5 */ public function setSessionValue($name, $value) { $this->dummySession[$name] = $value; } /** * Checks if a value is in the session * * @param string $name * * @return boolean * * @since 4.1.5 */ public function hasSessionValue($name) { return array_key_exists($name, $this->dummySession); } /** * Returns a value from the session * * @param string $name * * @return mixed * * @since 4.1.5 */ public function getSessionValue($name) { return $this->dummySession[$name] ?? null; } /** * Deletes a value from the session * * @param string $name * * @since 4.1.5 */ public function deleteSessionValue($name) { unset($this->dummySession[$name]); } } src/JavascriptRenderer.php000064400000007747151721517170011667 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.Debug * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Debug; use DebugBar\DebugBar; use DebugBar\JavascriptRenderer as DebugBarJavascriptRenderer; use Joomla\CMS\Factory; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Custom JavascriptRenderer for DebugBar * * @since 4.0.0 */ class JavascriptRenderer extends DebugBarJavascriptRenderer { /** * Class constructor. * * @param \DebugBar\DebugBar $debugBar DebugBar instance * @param string $baseUrl The base URL from which assets will be served * @param string $basePath The path which assets are relative to * * @since 4.0.0 */ public function __construct(DebugBar $debugBar, $baseUrl = null, $basePath = null) { parent::__construct($debugBar, $baseUrl, $basePath); // Disable features that loaded by Joomla! API, or not in use $this->setEnableJqueryNoConflict(false); $this->disableVendor('jquery'); $this->disableVendor('fontawesome'); } /** * Renders the html to include needed assets * * Only useful if Assetic is not used * * @return string * * @since 4.0.0 */ public function renderHead() { list($cssFiles, $jsFiles, $inlineCss, $inlineJs, $inlineHead) = $this->getAssets(null, self::RELATIVE_URL); $html = ''; $doc = Factory::getApplication()->getDocument(); foreach ($cssFiles as $file) { $html .= sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n", $file); } foreach ($inlineCss as $content) { $html .= sprintf('<style>%s</style>' . "\n", $content); } foreach ($jsFiles as $file) { $html .= sprintf('<script type="text/javascript" src="%s" defer></script>' . "\n", $file); } $nonce = ''; if ($doc->cspNonce) { $nonce = ' nonce="' . $doc->cspNonce . '"'; } foreach ($inlineJs as $content) { $html .= sprintf('<script type="module"%s>%s</script>' . "\n", $nonce, $content); } foreach ($inlineHead as $content) { $html .= $content . "\n"; } return $html; } /** * Returns the code needed to display the debug bar * * AJAX request should not render the initialization code. * * @param boolean $initialize Whether or not to render the debug bar initialization code * @param boolean $renderStackedData Whether or not to render the stacked data * * @return string * * @since 4.0.0 */ public function render($initialize = true, $renderStackedData = true) { $js = ''; $doc = Factory::getApplication()->getDocument(); if ($initialize) { $js = $this->getJsInitializationCode(); } if ($renderStackedData && $this->debugBar->hasStackedData()) { foreach ($this->debugBar->getStackedData() as $id => $data) { $js .= $this->getAddDatasetCode($id, $data, '(stacked)'); } } $suffix = !$initialize ? '(ajax)' : null; $js .= $this->getAddDatasetCode($this->debugBar->getCurrentRequestId(), $this->debugBar->getData(), $suffix); $nonce = ''; if ($doc->cspNonce) { $nonce = ' nonce="' . $doc->cspNonce . '"'; } if ($this->useRequireJs) { return "<script type=\"module\"$nonce>\nrequire(['debugbar'], function(PhpDebugBar){ $js });\n</script>\n"; } else { return "<script type=\"module\"$nonce>\n$js\n</script>\n"; } } } index.html000060400000000037151721517170006544 0ustar00<!DOCTYPE html><title></title> debug.xml000064400000014532151721517170006370 0ustar00<?xml version="1.0" encoding="UTF-8"?> <extension type="plugin" group="system" method="upgrade"> <name>plg_system_debug</name> <author>Joomla! Project</author> <creationDate>2006-12</creationDate> <copyright>(C) 2006 Open Source Matters, Inc.</copyright> <license>GNU General Public License version 2 or later; see LICENSE.txt</license> <authorEmail>admin@joomla.org</authorEmail> <authorUrl>www.joomla.org</authorUrl> <version>3.0.0</version> <description>PLG_DEBUG_XML_DESCRIPTION</description> <namespace path="src">Joomla\Plugin\System\Debug</namespace> <files> <folder plugin="debug">services</folder> <folder>src</folder> </files> <languages> <language tag="en-GB">language/en-GB/plg_system_debug.ini</language> <language tag="en-GB">language/en-GB/plg_system_debug.sys.ini</language> </languages> <config> <fields name="params"> <fieldset name="basic"> <field name="refresh_assets" type="radio" label="PLG_DEBUG_FIELD_REFRESH_ASSETS_LABEL" description="PLG_DEBUG_FIELD_REFRESH_ASSETS_DESC" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JNO</option> <option value="1">JYES</option> </field> <field name="filter_groups" type="usergrouplist" label="PLG_DEBUG_FIELD_ALLOWED_GROUPS_LABEL" multiple="true" layout="joomla.form.field.list-fancy-select" filter="intarray" /> <field name="memory" type="radio" label="PLG_DEBUG_FIELD_MEMORY_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="request" type="radio" label="PLG_DEBUG_FIELD_REQUEST_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="session" type="radio" label="PLG_DEBUG_FIELD_SESSION_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="profile" type="radio" label="PLG_DEBUG_FIELD_PROFILING_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="queries" type="radio" label="PLG_DEBUG_FIELD_QUERIES_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="query_traces" type="radio" label="PLG_DEBUG_FIELD_QUERY_TRACES_LABEL" layout="joomla.form.field.radio.switcher" default="0" showon="queries:1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="query_profiles" type="radio" label="PLG_DEBUG_FIELD_QUERY_PROFILES_LABEL" layout="joomla.form.field.radio.switcher" default="0" showon="queries:1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="query_explains" type="radio" label="PLG_DEBUG_FIELD_QUERY_EXPLAINS_LABEL" layout="joomla.form.field.radio.switcher" default="0" showon="queries:1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="track_request_history" type="radio" label="PLG_DEBUG_FIELD_TRACK_REQUEST_HISTORY_LABEL" description="PLG_DEBUG_FIELD_TRACK_REQUEST_HISTORY_DESC" layout="joomla.form.field.radio.switcher" default="0" filter="integer" > <option value="0">JDISABLED</option> <option value="1">JENABLED</option> </field> </fieldset> <fieldset name="language" label="PLG_DEBUG_LANGUAGE_FIELDSET_LABEL" > <field name="language_errorfiles" type="radio" label="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="language_files" type="radio" label="PLG_DEBUG_FIELD_LANGUAGE_FILES_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="language_strings" type="radio" label="PLG_DEBUG_FIELD_LANGUAGE_STRING_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="strip-first" type="radio" label="PLG_DEBUG_FIELD_STRIP_FIRST_LABEL" layout="joomla.form.field.radio.switcher" default="1" filter="integer" > <option value="0">JNO</option> <option value="1">JYES</option> </field> <field name="strip-prefix" type="textarea" label="PLG_DEBUG_FIELD_STRIP_PREFIX_LABEL" description="PLG_DEBUG_FIELD_STRIP_PREFIX_DESC" cols="30" rows="4" /> <field name="strip-suffix" type="textarea" label="PLG_DEBUG_FIELD_STRIP_SUFFIX_LABEL" description="PLG_DEBUG_FIELD_STRIP_SUFFIX_DESC" cols="30" rows="4" /> </fieldset> <fieldset name="logging" label="PLG_DEBUG_LOGGING_FIELDSET_LABEL" > <field name="logs" type="radio" label="PLG_DEBUG_FIELD_LOGS_LABEL" layout="joomla.form.field.radio.switcher" default="1" > <option value="0">JHIDE</option> <option value="1">JSHOW</option> </field> <field name="log-deprecated-core" type="radio" label="PLG_DEBUG_FIELD_LOG_DEPRECATED_CORE_LABEL" layout="joomla.form.field.radio.switcher" default="0" filter="integer" showon="logs:1" > <option value="0">JNO</option> <option value="1">JYES</option> </field> </fieldset> </fields> </config> </extension> services/provider.php000064400000002436151721517170010746 0ustar00<?php /** * @package Joomla.Plugin * @subpackage System.debug * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use Joomla\Event\DispatcherInterface; use Joomla\Plugin\System\Debug\Extension\Debug; return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.4.0 */ public function register(Container $container): void { $container->set( PluginInterface::class, function (Container $container) { return new Debug( $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('system', 'debug'), Factory::getApplication(), $container->get(DatabaseInterface::class) ); } ); } };
/home/opticamezl/www/newok/libraries/../libraries/../modules/../api/../cli/../language/../debug.tar