%PDF- %PDF-
| Direktori : /var/www/projetos/suporte.iigd.com.br/src/Debug/ |
| Current File : /var/www/projetos/suporte.iigd.com.br/src/Debug/Profile.php |
<?php
/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/
namespace Glpi\Debug;
final class Profile
{
private string $id;
private ?string $parent_id;
/**
* @var bool If true, the profile is loaded from an old request so current debug info should not be accessible from this profile
*/
private bool $is_readonly = false;
/**
* @var array|null Debug info for this profile. This is only set for loaded/readonly profiles.
*/
private ?array $debug_info = null;
private array $additional_info = [];
private static ?self $current = null;
public function __construct(string $id, ?string $parent_id)
{
$this->id = $id;
$this->parent_id = $parent_id;
}
public static function getCurrent(): self
{
if (self::$current === null) {
$id = $_SERVER['HTTP_X_GLPI_AJAX_ID'] ?? bin2hex(random_bytes(8));
$parent_id = $_SERVER['HTTP_X_GLPI_AJAX_PARENT_ID'] ?? null;
self::$current = new self($id, $parent_id);
// Register a shutdown function to save the profile
register_shutdown_function(static function () {
// Stop all profiler timers (should just be the main php_request one unless something died)
Profiler::getInstance()->stopAll();
self::getCurrent()->save();
});
}
return self::$current;
}
public static function pull(string $id): ?self
{
if (!isset($_SESSION['debug_profiles'][$id])) {
return null;
}
try {
$profile_data = json_decode(gzdecode($_SESSION['debug_profiles'][$id]), true, 512, JSON_THROW_ON_ERROR);
$profile = new self($profile_data['id'], $profile_data['parent_id']);
$profile->is_readonly = true;
$profile->debug_info = $profile_data;
unset($_SESSION['debug_profiles'][$id]);
return $profile;
} catch (\Throwable $e) {
return null;
}
}
public function getID(): string
{
return $this->id;
}
public function getParentID(): ?string
{
return $this->parent_id;
}
public function setData(string $widget, $data)
{
if (!array_key_exists($widget, $this->additional_info)) {
$this->additional_info[$widget] = [];
}
$this->additional_info[$widget][] = $data;
}
public function addSQLQueryData(string $query, int $time, int $rows = 0, string $errors = '', string $warnings = '')
{
if (!array_key_exists('sql', $this->additional_info)) {
$this->additional_info['sql'] = [
'queries' => [],
];
}
$next_num = count($this->additional_info['sql']['queries'] ?? []);
$this->additional_info['sql']['queries'][] = [
'num' => $next_num,
'query' => $query,
'time' => $time,
'rows' => $rows,
'errors' => $errors,
'warnings' => $warnings,
];
}
public function getDebugInfo(): array
{
if ($this->is_readonly) {
return $this->debug_info;
}
$execution_time = -1;
if (isset($this->additional_info['profiler'])) {
$main_section = array_values(array_filter($this->additional_info['profiler'], static function (array $section) {
return $section['category'] === Profiler::CATEGORY_CORE && $section['name'] === 'php_request';
}));
if (count($main_section)) {
$execution_time = $main_section[0]['end'] - $main_section[0]['start'];
}
}
/**
* Each top-level key corresponds to a debug toolbar widget id
*/
$debug_info = [
'id' => $this->id,
'parent_id' => $this->parent_id,
'server_performance' => [
'execution_time' => (float) $execution_time,
'memory_usage' => memory_get_usage(),
'memory_peak' => memory_get_peak_usage(),
'memory_limit' => \Toolbox::getMemoryLimit(),
],
'sql' => [
'queries' => [],
],
'globals' => []
];
if ($this->parent_id === null) {
// We only need these for top-level requests. For AJAX, this data is already known by the client.
$debug_info['globals']['get'] = $_GET;
$debug_info['globals']['post'] = $_POST;
}
$session = $_SESSION ?? [];
unset($session['debug_profiles']);
$debug_info['globals']['session'] = $session;
$debug_info['globals']['server'] = $_SERVER;
foreach ($this->additional_info as $widget => $data) {
if (!array_key_exists($widget, $debug_info)) {
$debug_info[$widget] = $data;
} else {
$debug_info[$widget] = array_merge($debug_info[$widget], $data);
}
}
return $debug_info;
}
public function save(): void
{
if (isAPI() || isCommandLine()) {
// No saving debug info for API or CLI requests
return;
}
if ($this->is_readonly) {
return;
}
if ($this->parent_id === null) {
// Don't save top-level requests. The data is sent in the response in a script tag when the bar is initialized.
return;
}
$info = $this->getDebugInfo();
try {
$json = json_encode($info, JSON_THROW_ON_ERROR);
$gz = gzencode($json, 9);
$_SESSION['debug_profiles'][$this->id] = $gz;
} catch (\Throwable $e) {
// Ignore
}
}
}