Update website
This commit is contained in:
parent
4413528994
commit
1d90fbf296
6865 changed files with 1091082 additions and 0 deletions
207
admin/phpMyAdmin/libraries/classes/Server/Plugin.php
Normal file
207
admin/phpMyAdmin/libraries/classes/Server/Plugin.php
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
/**
|
||||
* Server Plugin value object
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server;
|
||||
|
||||
/**
|
||||
* Server Plugin value object
|
||||
*/
|
||||
final class Plugin
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var string|null */
|
||||
private $version;
|
||||
|
||||
/** @var string */
|
||||
private $status;
|
||||
|
||||
/** @var string */
|
||||
private $type;
|
||||
|
||||
/** @var string|null */
|
||||
private $typeVersion;
|
||||
|
||||
/** @var string|null */
|
||||
private $library;
|
||||
|
||||
/** @var string|null */
|
||||
private $libraryVersion;
|
||||
|
||||
/** @var string|null */
|
||||
private $author;
|
||||
|
||||
/** @var string|null */
|
||||
private $description;
|
||||
|
||||
/** @var string */
|
||||
private $license;
|
||||
|
||||
/** @var string|null */
|
||||
private $loadOption;
|
||||
|
||||
/** @var string|null */
|
||||
private $maturity;
|
||||
|
||||
/** @var string|null */
|
||||
private $authVersion;
|
||||
|
||||
/**
|
||||
* @param string $name Name of the plugin
|
||||
* @param string|null $version Version from the plugin's general type descriptor
|
||||
* @param string $status Plugin status
|
||||
* @param string $type Type of plugin
|
||||
* @param string|null $typeVersion Version from the plugin's type-specific descriptor
|
||||
* @param string|null $library Plugin's shared object file name
|
||||
* @param string|null $libraryVersion Version from the plugin's API interface
|
||||
* @param string|null $author Author of the plugin
|
||||
* @param string|null $description Description
|
||||
* @param string $license Plugin's licence
|
||||
* @param string|null $loadOption How the plugin was loaded
|
||||
* @param string|null $maturity Plugin's maturity level
|
||||
* @param string|null $authVersion Plugin's version as determined by the plugin author
|
||||
*/
|
||||
private function __construct(
|
||||
string $name,
|
||||
?string $version,
|
||||
string $status,
|
||||
string $type,
|
||||
?string $typeVersion,
|
||||
?string $library,
|
||||
?string $libraryVersion,
|
||||
?string $author,
|
||||
?string $description,
|
||||
string $license,
|
||||
?string $loadOption,
|
||||
?string $maturity,
|
||||
?string $authVersion
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->version = $version;
|
||||
$this->status = $status;
|
||||
$this->type = $type;
|
||||
$this->typeVersion = $typeVersion;
|
||||
$this->library = $library;
|
||||
$this->libraryVersion = $libraryVersion;
|
||||
$this->author = $author;
|
||||
$this->description = $description;
|
||||
$this->license = $license;
|
||||
$this->loadOption = $loadOption;
|
||||
$this->maturity = $maturity;
|
||||
$this->authVersion = $authVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $state array with the properties
|
||||
*/
|
||||
public static function fromState(array $state): self
|
||||
{
|
||||
return new self(
|
||||
$state['name'] ?? '',
|
||||
$state['version'] ?? null,
|
||||
$state['status'] ?? '',
|
||||
$state['type'] ?? '',
|
||||
$state['typeVersion'] ?? null,
|
||||
$state['library'] ?? null,
|
||||
$state['libraryVersion'] ?? null,
|
||||
$state['author'] ?? null,
|
||||
$state['description'] ?? null,
|
||||
$state['license'] ?? '',
|
||||
$state['loadOption'] ?? null,
|
||||
$state['maturity'] ?? null,
|
||||
$state['authVersion'] ?? null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->getName(),
|
||||
'version' => $this->getVersion(),
|
||||
'status' => $this->getStatus(),
|
||||
'type' => $this->getType(),
|
||||
'type_version' => $this->getTypeVersion(),
|
||||
'library' => $this->getLibrary(),
|
||||
'library_version' => $this->getLibraryVersion(),
|
||||
'author' => $this->getAuthor(),
|
||||
'description' => $this->getDescription(),
|
||||
'license' => $this->getLicense(),
|
||||
'load_option' => $this->getLoadOption(),
|
||||
'maturity' => $this->getMaturity(),
|
||||
'auth_version' => $this->getAuthVersion(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getVersion(): ?string
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function getStatus(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getTypeVersion(): ?string
|
||||
{
|
||||
return $this->typeVersion;
|
||||
}
|
||||
|
||||
public function getLibrary(): ?string
|
||||
{
|
||||
return $this->library;
|
||||
}
|
||||
|
||||
public function getLibraryVersion(): ?string
|
||||
{
|
||||
return $this->libraryVersion;
|
||||
}
|
||||
|
||||
public function getAuthor(): ?string
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getLicense(): string
|
||||
{
|
||||
return $this->license;
|
||||
}
|
||||
|
||||
public function getLoadOption(): ?string
|
||||
{
|
||||
return $this->loadOption;
|
||||
}
|
||||
|
||||
public function getMaturity(): ?string
|
||||
{
|
||||
return $this->maturity;
|
||||
}
|
||||
|
||||
public function getAuthVersion(): ?string
|
||||
{
|
||||
return $this->authVersion;
|
||||
}
|
||||
}
|
115
admin/phpMyAdmin/libraries/classes/Server/Plugins.php
Normal file
115
admin/phpMyAdmin/libraries/classes/Server/Plugins.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
|
||||
use function __;
|
||||
|
||||
class Plugins
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
*/
|
||||
public function __construct(DatabaseInterface $dbi)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Plugin[]
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$sql = 'SHOW PLUGINS';
|
||||
if (! $cfg['Server']['DisableIS']) {
|
||||
$sql = 'SELECT * FROM information_schema.PLUGINS ORDER BY PLUGIN_TYPE, PLUGIN_NAME';
|
||||
}
|
||||
|
||||
$result = $this->dbi->query($sql);
|
||||
$plugins = [];
|
||||
while ($row = $result->fetchAssoc()) {
|
||||
$plugins[] = $this->mapRowToPlugin($row);
|
||||
}
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int|string, string>
|
||||
*/
|
||||
public function getAuthentication(): array
|
||||
{
|
||||
$result = $this->dbi->query(
|
||||
'SELECT `PLUGIN_NAME`, `PLUGIN_DESCRIPTION` FROM `information_schema`.`PLUGINS`'
|
||||
. ' WHERE `PLUGIN_TYPE` = \'AUTHENTICATION\';'
|
||||
);
|
||||
|
||||
$plugins = [];
|
||||
|
||||
while ($row = $result->fetchAssoc()) {
|
||||
$plugins[$row['PLUGIN_NAME']] = $this->getTranslatedDescription($row['PLUGIN_DESCRIPTION']);
|
||||
}
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
private function getTranslatedDescription(string $description): string
|
||||
{
|
||||
// mysql_native_password
|
||||
if ($description === 'Native MySQL authentication') {
|
||||
return __('Native MySQL authentication');
|
||||
}
|
||||
|
||||
// sha256_password
|
||||
if ($description === 'SHA256 password authentication') {
|
||||
return __('SHA256 password authentication');
|
||||
}
|
||||
|
||||
// caching_sha2_password
|
||||
if ($description === 'Caching sha2 authentication') {
|
||||
return __('Caching sha2 authentication');
|
||||
}
|
||||
|
||||
// auth_socket || unix_socket
|
||||
if ($description === 'Unix Socket based authentication') {
|
||||
return __('Unix Socket based authentication');
|
||||
}
|
||||
|
||||
// mysql_old_password
|
||||
if ($description === 'Old MySQL-4.0 authentication') {
|
||||
return __('Old MySQL-4.0 authentication');
|
||||
}
|
||||
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $row Row fetched from database
|
||||
*/
|
||||
private function mapRowToPlugin(array $row): Plugin
|
||||
{
|
||||
return Plugin::fromState([
|
||||
'name' => $row['PLUGIN_NAME'] ?? $row['Name'],
|
||||
'version' => $row['PLUGIN_VERSION'] ?? null,
|
||||
'status' => $row['PLUGIN_STATUS'] ?? $row['Status'],
|
||||
'type' => $row['PLUGIN_TYPE'] ?? $row['Type'],
|
||||
'typeVersion' => $row['PLUGIN_TYPE_VERSION'] ?? null,
|
||||
'library' => $row['PLUGIN_LIBRARY'] ?? $row['Library'] ?? null,
|
||||
'libraryVersion' => $row['PLUGIN_LIBRARY_VERSION'] ?? null,
|
||||
'author' => $row['PLUGIN_AUTHOR'] ?? null,
|
||||
'description' => $row['PLUGIN_DESCRIPTION'] ?? null,
|
||||
'license' => $row['PLUGIN_LICENSE'] ?? $row['License'],
|
||||
'loadOption' => $row['LOAD_OPTION'] ?? null,
|
||||
'maturity' => $row['PLUGIN_MATURITY'] ?? null,
|
||||
'authVersion' => $row['PLUGIN_AUTH_VERSION'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
3792
admin/phpMyAdmin/libraries/classes/Server/Privileges.php
Normal file
3792
admin/phpMyAdmin/libraries/classes/Server/Privileges.php
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\Privileges;
|
||||
|
||||
use Exception;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Query\Compatibility;
|
||||
|
||||
use function __;
|
||||
use function sprintf;
|
||||
|
||||
final class AccountLocking
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(DatabaseInterface $dbi)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function lock(string $user, string $host): void
|
||||
{
|
||||
if (! Compatibility::hasAccountLocking($this->dbi->isMariaDB(), $this->dbi->getVersion())) {
|
||||
throw new Exception(__('Account locking is not supported.'));
|
||||
}
|
||||
|
||||
$statement = sprintf(
|
||||
'ALTER USER \'%s\'@\'%s\' ACCOUNT LOCK;',
|
||||
$this->dbi->escapeString($user),
|
||||
$this->dbi->escapeString($host)
|
||||
);
|
||||
if ($this->dbi->tryQuery($statement) !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception($this->dbi->getError());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function unlock(string $user, string $host): void
|
||||
{
|
||||
if (! Compatibility::hasAccountLocking($this->dbi->isMariaDB(), $this->dbi->getVersion())) {
|
||||
throw new Exception(__('Account locking is not supported.'));
|
||||
}
|
||||
|
||||
$statement = sprintf(
|
||||
'ALTER USER \'%s\'@\'%s\' ACCOUNT UNLOCK;',
|
||||
$this->dbi->escapeString($user),
|
||||
$this->dbi->escapeString($host)
|
||||
);
|
||||
if ($this->dbi->tryQuery($statement) !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception($this->dbi->getError());
|
||||
}
|
||||
}
|
120
admin/phpMyAdmin/libraries/classes/Server/Select.php
Normal file
120
admin/phpMyAdmin/libraries/classes/Server/Select.php
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
/**
|
||||
* Code for displaying server selection
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server;
|
||||
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function count;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function str_contains;
|
||||
|
||||
/**
|
||||
* Displays the MySQL servers choice form
|
||||
*/
|
||||
class Select
|
||||
{
|
||||
/**
|
||||
* Renders the server selection in list or selectbox form, or option tags only
|
||||
*
|
||||
* @param bool $not_only_options whether to include form tags or not
|
||||
* @param bool $omit_fieldset whether to omit fieldset tag or not
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function render($not_only_options, $omit_fieldset)
|
||||
{
|
||||
// Show as list?
|
||||
if ($not_only_options) {
|
||||
$list = $GLOBALS['cfg']['DisplayServersList'];
|
||||
$not_only_options = ! $list;
|
||||
} else {
|
||||
$list = false;
|
||||
}
|
||||
|
||||
$form_action = '';
|
||||
if ($not_only_options) {
|
||||
$form_action = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabServer'], 'server');
|
||||
}
|
||||
|
||||
$servers = [];
|
||||
foreach ($GLOBALS['cfg']['Servers'] as $key => $server) {
|
||||
if (empty($server['host'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! empty($GLOBALS['server']) && (int) $GLOBALS['server'] === (int) $key) {
|
||||
$selected = 1;
|
||||
} else {
|
||||
$selected = 0;
|
||||
}
|
||||
|
||||
if (! empty($server['verbose'])) {
|
||||
$label = $server['verbose'];
|
||||
} else {
|
||||
$label = $server['host'];
|
||||
if (! empty($server['port'])) {
|
||||
$label .= ':' . $server['port'];
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($server['only_db'])) {
|
||||
if (! is_array($server['only_db'])) {
|
||||
$label .= ' - ' . $server['only_db'];
|
||||
// try to avoid displaying a too wide selector
|
||||
} elseif (count($server['only_db']) < 4) {
|
||||
$label .= ' - ' . implode(', ', $server['only_db']);
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($server['user']) && $server['auth_type'] === 'config') {
|
||||
$label .= ' (' . $server['user'] . ')';
|
||||
}
|
||||
|
||||
if ($list) {
|
||||
if ($selected) {
|
||||
$servers['list'][] = [
|
||||
'selected' => true,
|
||||
'label' => $label,
|
||||
];
|
||||
} else {
|
||||
$scriptName = Util::getScriptNameForOption($GLOBALS['cfg']['DefaultTabServer'], 'server');
|
||||
$href = $scriptName . Url::getCommon(
|
||||
['server' => $key],
|
||||
! str_contains($scriptName, '?') ? '?' : '&'
|
||||
);
|
||||
$servers['list'][] = [
|
||||
'href' => $href,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$servers['select'][] = [
|
||||
'value' => $key,
|
||||
'selected' => $selected,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$renderDetails = [
|
||||
'not_only_options' => $not_only_options,
|
||||
'omit_fieldset' => $omit_fieldset,
|
||||
'servers' => $servers,
|
||||
];
|
||||
if ($not_only_options) {
|
||||
$renderDetails['form_action'] = $form_action;
|
||||
}
|
||||
|
||||
$template = new Template();
|
||||
|
||||
return $template->render('server/select/index', $renderDetails);
|
||||
}
|
||||
}
|
456
admin/phpMyAdmin/libraries/classes/Server/Status/Data.php
Normal file
456
admin/phpMyAdmin/libraries/classes/Server/Status/Data.php
Normal file
|
@ -0,0 +1,456 @@
|
|||
<?php
|
||||
/**
|
||||
* PhpMyAdmin\Server\Status\Data class
|
||||
* Used by server_status_*.php pages
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\Status;
|
||||
|
||||
use PhpMyAdmin\ReplicationInfo;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function __;
|
||||
use function basename;
|
||||
use function mb_strtolower;
|
||||
use function str_contains;
|
||||
|
||||
/**
|
||||
* This class provides data about the server status
|
||||
*
|
||||
* All properties of the class are read-only
|
||||
*
|
||||
* TODO: Use lazy initialisation for some of the properties
|
||||
* since not all of the server_status_*.php pages need
|
||||
* all the data that this class provides.
|
||||
*/
|
||||
class Data
|
||||
{
|
||||
/** @var array */
|
||||
public $status;
|
||||
|
||||
/** @var array */
|
||||
public $sections;
|
||||
|
||||
/** @var array */
|
||||
public $variables;
|
||||
|
||||
/** @var array */
|
||||
public $usedQueries;
|
||||
|
||||
/** @var array */
|
||||
public $allocationMap;
|
||||
|
||||
/** @var array */
|
||||
public $links;
|
||||
|
||||
/** @var bool */
|
||||
public $dbIsLocal;
|
||||
|
||||
/** @var mixed */
|
||||
public $section;
|
||||
|
||||
/** @var array */
|
||||
public $sectionUsed;
|
||||
|
||||
/** @var string */
|
||||
public $selfUrl;
|
||||
|
||||
/** @var bool */
|
||||
public $dataLoaded;
|
||||
|
||||
/** @var ReplicationInfo */
|
||||
private $replicationInfo;
|
||||
|
||||
public function getReplicationInfo(): ReplicationInfo
|
||||
{
|
||||
return $this->replicationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* An empty setter makes the above properties read-only
|
||||
*
|
||||
* @param string $a key
|
||||
* @param mixed $b value
|
||||
*/
|
||||
public function __set($a, $b): void
|
||||
{
|
||||
// Discard everything
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the allocations for constructor
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAllocations()
|
||||
{
|
||||
return [
|
||||
// variable name => section
|
||||
// variable names match when they begin with the given string
|
||||
|
||||
'Com_' => 'com',
|
||||
'Innodb_' => 'innodb',
|
||||
'Ndb_' => 'ndb',
|
||||
'Handler_' => 'handler',
|
||||
'Qcache_' => 'qcache',
|
||||
'Threads_' => 'threads',
|
||||
'Slow_launch_threads' => 'threads',
|
||||
|
||||
'Binlog_cache_' => 'binlog_cache',
|
||||
'Created_tmp_' => 'created_tmp',
|
||||
'Key_' => 'key',
|
||||
|
||||
'Delayed_' => 'delayed',
|
||||
'Not_flushed_delayed_rows' => 'delayed',
|
||||
|
||||
'Flush_commands' => 'query',
|
||||
'Last_query_cost' => 'query',
|
||||
'Slow_queries' => 'query',
|
||||
'Queries' => 'query',
|
||||
'Prepared_stmt_count' => 'query',
|
||||
|
||||
'Select_' => 'select',
|
||||
'Sort_' => 'sort',
|
||||
|
||||
'Open_tables' => 'table',
|
||||
'Opened_tables' => 'table',
|
||||
'Open_table_definitions' => 'table',
|
||||
'Opened_table_definitions' => 'table',
|
||||
'Table_locks_' => 'table',
|
||||
|
||||
'Rpl_status' => 'repl',
|
||||
'Slave_' => 'repl',
|
||||
|
||||
'Tc_' => 'tc',
|
||||
|
||||
'Ssl_' => 'ssl',
|
||||
|
||||
'Open_files' => 'files',
|
||||
'Open_streams' => 'files',
|
||||
'Opened_files' => 'files',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sections for constructor
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getSections()
|
||||
{
|
||||
return [
|
||||
// section => section name (description)
|
||||
'com' => 'Com',
|
||||
'query' => __('SQL query'),
|
||||
'innodb' => 'InnoDB',
|
||||
'ndb' => 'NDB',
|
||||
'handler' => __('Handler'),
|
||||
'qcache' => __('Query cache'),
|
||||
'threads' => __('Threads'),
|
||||
'binlog_cache' => __('Binary log'),
|
||||
'created_tmp' => __('Temporary data'),
|
||||
'delayed' => __('Delayed inserts'),
|
||||
'key' => __('Key cache'),
|
||||
'select' => __('Joins'),
|
||||
'repl' => __('Replication'),
|
||||
'sort' => __('Sorting'),
|
||||
'table' => __('Tables'),
|
||||
'tc' => __('Transaction coordinator'),
|
||||
'files' => __('Files'),
|
||||
'ssl' => 'SSL',
|
||||
'other' => __('Other'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the links for constructor
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getLinks()
|
||||
{
|
||||
$primaryInfo = $this->replicationInfo->getPrimaryInfo();
|
||||
$replicaInfo = $this->replicationInfo->getReplicaInfo();
|
||||
|
||||
$links = [];
|
||||
// variable or section name => (name => url)
|
||||
|
||||
$links['table'][__('Flush (close) all tables')] = [
|
||||
'url' => $this->selfUrl,
|
||||
'params' => Url::getCommon(['flush' => 'TABLES'], ''),
|
||||
];
|
||||
$links['table'][__('Show open tables')] = [
|
||||
'url' => Url::getFromRoute('/sql'),
|
||||
'params' => Url::getCommon([
|
||||
'sql_query' => 'SHOW OPEN TABLES',
|
||||
'goto' => $this->selfUrl,
|
||||
], ''),
|
||||
];
|
||||
|
||||
if ($primaryInfo['status']) {
|
||||
$links['repl'][__('Show replica hosts')] = [
|
||||
'url' => Url::getFromRoute('/sql'),
|
||||
'params' => Url::getCommon([
|
||||
'sql_query' => 'SHOW SLAVE HOSTS',
|
||||
'goto' => $this->selfUrl,
|
||||
], ''),
|
||||
];
|
||||
$links['repl'][__('Show primary status')] = [
|
||||
'url' => '#replication_primary',
|
||||
'params' => '',
|
||||
];
|
||||
}
|
||||
|
||||
if ($replicaInfo['status']) {
|
||||
$links['repl'][__('Show replica status')] = [
|
||||
'url' => '#replication_replica',
|
||||
'params' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$links['repl']['doc'] = 'replication';
|
||||
|
||||
$links['qcache'][__('Flush query cache')] = [
|
||||
'url' => $this->selfUrl,
|
||||
'params' => Url::getCommon(['flush' => 'QUERY CACHE'], ''),
|
||||
];
|
||||
$links['qcache']['doc'] = 'query_cache';
|
||||
|
||||
$links['threads']['doc'] = 'mysql_threads';
|
||||
|
||||
$links['key']['doc'] = 'myisam_key_cache';
|
||||
|
||||
$links['binlog_cache']['doc'] = 'binary_log';
|
||||
|
||||
$links['Slow_queries']['doc'] = 'slow_query_log';
|
||||
|
||||
$links['innodb'][__('Variables')] = [
|
||||
'url' => Url::getFromRoute('/server/engines/InnoDB'),
|
||||
'params' => '',
|
||||
];
|
||||
$links['innodb'][__('InnoDB Status')] = [
|
||||
'url' => Url::getFromRoute('/server/engines/InnoDB/Status'),
|
||||
'params' => '',
|
||||
];
|
||||
$links['innodb']['doc'] = 'innodb';
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate some values
|
||||
*
|
||||
* @param array $server_status contains results of SHOW GLOBAL STATUS
|
||||
* @param array $server_variables contains results of SHOW GLOBAL VARIABLES
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function calculateValues(array $server_status, array $server_variables)
|
||||
{
|
||||
// Key_buffer_fraction
|
||||
if (
|
||||
isset($server_status['Key_blocks_unused'], $server_variables['key_cache_block_size'])
|
||||
&& isset($server_variables['key_buffer_size'])
|
||||
&& $server_variables['key_buffer_size'] != 0
|
||||
) {
|
||||
$server_status['Key_buffer_fraction_%'] = 100
|
||||
- $server_status['Key_blocks_unused']
|
||||
* $server_variables['key_cache_block_size']
|
||||
/ $server_variables['key_buffer_size']
|
||||
* 100;
|
||||
} elseif (
|
||||
isset($server_status['Key_blocks_used'], $server_variables['key_buffer_size'])
|
||||
&& $server_variables['key_buffer_size'] != 0
|
||||
) {
|
||||
$server_status['Key_buffer_fraction_%'] = $server_status['Key_blocks_used']
|
||||
* 1024
|
||||
/ $server_variables['key_buffer_size'];
|
||||
}
|
||||
|
||||
// Ratio for key read/write
|
||||
if (
|
||||
isset($server_status['Key_writes'], $server_status['Key_write_requests'])
|
||||
&& $server_status['Key_write_requests'] > 0
|
||||
) {
|
||||
$key_writes = $server_status['Key_writes'];
|
||||
$key_write_requests = $server_status['Key_write_requests'];
|
||||
$server_status['Key_write_ratio_%'] = 100 * $key_writes / $key_write_requests;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($server_status['Key_reads'], $server_status['Key_read_requests'])
|
||||
&& $server_status['Key_read_requests'] > 0
|
||||
) {
|
||||
$key_reads = $server_status['Key_reads'];
|
||||
$key_read_requests = $server_status['Key_read_requests'];
|
||||
$server_status['Key_read_ratio_%'] = 100 * $key_reads / $key_read_requests;
|
||||
}
|
||||
|
||||
// Threads_cache_hitrate
|
||||
if (
|
||||
isset($server_status['Threads_created'], $server_status['Connections'])
|
||||
&& $server_status['Connections'] > 0
|
||||
) {
|
||||
$server_status['Threads_cache_hitrate_%'] = 100 - $server_status['Threads_created']
|
||||
/ $server_status['Connections'] * 100;
|
||||
}
|
||||
|
||||
return $server_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort variables into arrays
|
||||
*
|
||||
* @param array $server_status contains results of SHOW GLOBAL STATUS
|
||||
* @param array $allocations allocations for sections
|
||||
* @param array $allocationMap map variables to their section
|
||||
* @param array $sectionUsed is a section used?
|
||||
* @param array $used_queries used queries
|
||||
*
|
||||
* @return array ($allocationMap, $sectionUsed, $used_queries)
|
||||
*/
|
||||
private function sortVariables(
|
||||
array $server_status,
|
||||
array $allocations,
|
||||
array $allocationMap,
|
||||
array $sectionUsed,
|
||||
array $used_queries
|
||||
) {
|
||||
foreach ($server_status as $name => $value) {
|
||||
$section_found = false;
|
||||
foreach ($allocations as $filter => $section) {
|
||||
if (! str_contains($name, $filter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$allocationMap[$name] = $section;
|
||||
$sectionUsed[$section] = true;
|
||||
$section_found = true;
|
||||
if ($section === 'com' && $value > 0) {
|
||||
$used_queries[$name] = $value;
|
||||
}
|
||||
|
||||
break; // Only exits inner loop
|
||||
}
|
||||
|
||||
if ($section_found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$allocationMap[$name] = 'other';
|
||||
$sectionUsed['other'] = true;
|
||||
}
|
||||
|
||||
return [
|
||||
$allocationMap,
|
||||
$sectionUsed,
|
||||
$used_queries,
|
||||
];
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$this->replicationInfo = new ReplicationInfo($dbi);
|
||||
$this->replicationInfo->load($_POST['primary_connection'] ?? null);
|
||||
|
||||
$this->selfUrl = basename($GLOBALS['PMA_PHP_SELF']);
|
||||
|
||||
// get status from server
|
||||
$server_status_result = $dbi->tryQuery('SHOW GLOBAL STATUS');
|
||||
if ($server_status_result === false) {
|
||||
$server_status = [];
|
||||
$this->dataLoaded = false;
|
||||
} else {
|
||||
$this->dataLoaded = true;
|
||||
$server_status = $server_status_result->fetchAllKeyPair();
|
||||
unset($server_status_result);
|
||||
}
|
||||
|
||||
// for some calculations we require also some server settings
|
||||
$server_variables = $dbi->fetchResult('SHOW GLOBAL VARIABLES', 0, 1);
|
||||
|
||||
// cleanup of some deprecated values
|
||||
$server_status = self::cleanDeprecated($server_status);
|
||||
|
||||
// calculate some values
|
||||
$server_status = $this->calculateValues($server_status, $server_variables);
|
||||
|
||||
// split variables in sections
|
||||
$allocations = $this->getAllocations();
|
||||
|
||||
$sections = $this->getSections();
|
||||
|
||||
// define some needful links/commands
|
||||
$links = $this->getLinks();
|
||||
|
||||
// Variable to contain all com_ variables (query statistics)
|
||||
$used_queries = [];
|
||||
|
||||
// Variable to map variable names to their respective section name
|
||||
// (used for js category filtering)
|
||||
$allocationMap = [];
|
||||
|
||||
// Variable to mark used sections
|
||||
$sectionUsed = [];
|
||||
|
||||
// sort vars into arrays
|
||||
[
|
||||
$allocationMap,
|
||||
$sectionUsed,
|
||||
$used_queries,
|
||||
] = $this->sortVariables($server_status, $allocations, $allocationMap, $sectionUsed, $used_queries);
|
||||
|
||||
// admin commands are not queries (e.g. they include COM_PING,
|
||||
// which is excluded from $server_status['Questions'])
|
||||
unset($used_queries['Com_admin_commands']);
|
||||
|
||||
// Set all class properties
|
||||
$this->dbIsLocal = false;
|
||||
// can be null if $cfg['ServerDefault'] = 0;
|
||||
$serverHostToLower = mb_strtolower((string) $GLOBALS['cfg']['Server']['host']);
|
||||
if (
|
||||
$serverHostToLower === 'localhost'
|
||||
|| $GLOBALS['cfg']['Server']['host'] === '127.0.0.1'
|
||||
|| $GLOBALS['cfg']['Server']['host'] === '::1'
|
||||
) {
|
||||
$this->dbIsLocal = true;
|
||||
}
|
||||
|
||||
$this->status = $server_status;
|
||||
$this->sections = $sections;
|
||||
$this->variables = $server_variables;
|
||||
$this->usedQueries = $used_queries;
|
||||
$this->allocationMap = $allocationMap;
|
||||
$this->links = $links;
|
||||
$this->sectionUsed = $sectionUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup of some deprecated values
|
||||
*
|
||||
* @param array $server_status status array to process
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function cleanDeprecated(array $server_status)
|
||||
{
|
||||
$deprecated = [
|
||||
'Com_prepare_sql' => 'Com_stmt_prepare',
|
||||
'Com_execute_sql' => 'Com_stmt_execute',
|
||||
'Com_dealloc_sql' => 'Com_stmt_close',
|
||||
];
|
||||
foreach ($deprecated as $old => $new) {
|
||||
if (! isset($server_status[$old], $server_status[$new])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($server_status[$old]);
|
||||
}
|
||||
|
||||
return $server_status;
|
||||
}
|
||||
}
|
555
admin/phpMyAdmin/libraries/classes/Server/Status/Monitor.php
Normal file
555
admin/phpMyAdmin/libraries/classes/Server/Status/Monitor.php
Normal file
|
@ -0,0 +1,555 @@
|
|||
<?php
|
||||
/**
|
||||
* functions for displaying server status sub item: monitor
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\Status;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Profiling;
|
||||
use PhpMyAdmin\Server\SysInfo\SysInfo;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function array_sum;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function is_numeric;
|
||||
use function json_decode;
|
||||
use function mb_strlen;
|
||||
use function mb_strpos;
|
||||
use function mb_strtolower;
|
||||
use function mb_substr;
|
||||
use function microtime;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* functions for displaying server status sub item: monitor
|
||||
*/
|
||||
class Monitor
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
*/
|
||||
public function __construct($dbi)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON for real-time charting data
|
||||
*
|
||||
* @param string $requiredData Required data
|
||||
*
|
||||
* @return array JSON
|
||||
*/
|
||||
public function getJsonForChartingData(string $requiredData): array
|
||||
{
|
||||
$ret = json_decode($requiredData, true);
|
||||
$statusVars = [];
|
||||
$serverVars = [];
|
||||
$sysinfo = $cpuload = $memory = 0;
|
||||
|
||||
/* Accumulate all required variables and data */
|
||||
[$serverVars, $statusVars, $ret] = $this->getJsonForChartingDataGet(
|
||||
$ret,
|
||||
$serverVars,
|
||||
$statusVars,
|
||||
$sysinfo,
|
||||
$cpuload,
|
||||
$memory
|
||||
);
|
||||
|
||||
// Retrieve all required status variables
|
||||
$statusVarValues = [];
|
||||
if (count($statusVars)) {
|
||||
$statusVarValues = $this->dbi->fetchResult(
|
||||
"SHOW GLOBAL STATUS WHERE Variable_name='"
|
||||
. implode("' OR Variable_name='", $statusVars) . "'",
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieve all required server variables
|
||||
$serverVarValues = [];
|
||||
if (count($serverVars)) {
|
||||
$serverVarValues = $this->dbi->fetchResult(
|
||||
"SHOW GLOBAL VARIABLES WHERE Variable_name='"
|
||||
. implode("' OR Variable_name='", $serverVars) . "'",
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// ...and now assign them
|
||||
$ret = $this->getJsonForChartingDataSet($ret, $statusVarValues, $serverVarValues);
|
||||
|
||||
$ret['x'] = (int) (microtime(true) * 1000);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the variables for real-time charting data
|
||||
*
|
||||
* @param array $ret Real-time charting data
|
||||
* @param array $statusVarValues Status variable values
|
||||
* @param array $serverVarValues Server variable values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getJsonForChartingDataSet(
|
||||
array $ret,
|
||||
array $statusVarValues,
|
||||
array $serverVarValues
|
||||
): array {
|
||||
foreach ($ret as $chart_id => $chartNodes) {
|
||||
foreach ($chartNodes as $node_id => $nodeDataPoints) {
|
||||
foreach ($nodeDataPoints as $point_id => $dataPoint) {
|
||||
switch ($dataPoint['type']) {
|
||||
case 'statusvar':
|
||||
$ret[$chart_id][$node_id][$point_id]['value'] = $statusVarValues[$dataPoint['name']];
|
||||
break;
|
||||
case 'servervar':
|
||||
$ret[$chart_id][$node_id][$point_id]['value'] = $serverVarValues[$dataPoint['name']];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get called to get JSON for charting data
|
||||
*
|
||||
* @param array $ret Real-time charting data
|
||||
* @param array $serverVars Server variable values
|
||||
* @param array $statusVars Status variable values
|
||||
* @param mixed $sysinfo System info
|
||||
* @param mixed $cpuload CPU load
|
||||
* @param mixed $memory Memory
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getJsonForChartingDataGet(
|
||||
array $ret,
|
||||
array $serverVars,
|
||||
array $statusVars,
|
||||
$sysinfo,
|
||||
$cpuload,
|
||||
$memory
|
||||
) {
|
||||
// For each chart
|
||||
foreach ($ret as $chartId => $chartNodes) {
|
||||
// For each data series
|
||||
foreach ($chartNodes as $nodeId => $nodeDataPoints) {
|
||||
// For each data point in the series (usually just 1)
|
||||
foreach ($nodeDataPoints as $pointId => $dataPoint) {
|
||||
[$serverVars, $statusVars, $ret[$chartId][$nodeId][$pointId]] = $this->getJsonForChartingDataSwitch(
|
||||
$dataPoint['type'],
|
||||
$dataPoint['name'],
|
||||
$serverVars,
|
||||
$statusVars,
|
||||
$ret[$chartId][$nodeId][$pointId],
|
||||
$sysinfo,
|
||||
$cpuload,
|
||||
$memory
|
||||
);
|
||||
} /* foreach */
|
||||
} /* foreach */
|
||||
}
|
||||
|
||||
return [
|
||||
$serverVars,
|
||||
$statusVars,
|
||||
$ret,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch called to get JSON for charting data
|
||||
*
|
||||
* @param string $type Type
|
||||
* @param string $pName Name
|
||||
* @param array $serverVars Server variable values
|
||||
* @param array $statusVars Status variable values
|
||||
* @param array $ret Real-time charting data
|
||||
* @param mixed $sysinfo System info
|
||||
* @param mixed $cpuload CPU load
|
||||
* @param mixed $memory Memory
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getJsonForChartingDataSwitch(
|
||||
$type,
|
||||
$pName,
|
||||
array $serverVars,
|
||||
array $statusVars,
|
||||
array $ret,
|
||||
$sysinfo,
|
||||
$cpuload,
|
||||
$memory
|
||||
) {
|
||||
/**
|
||||
* We only collect the status and server variables here to read them all in one query,
|
||||
* and only afterwards assign them. Also do some allow list filtering on the names
|
||||
*/
|
||||
switch ($type) {
|
||||
case 'servervar':
|
||||
if (! preg_match('/[^a-zA-Z_]+/', $pName)) {
|
||||
$serverVars[] = $pName;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'statusvar':
|
||||
if (! preg_match('/[^a-zA-Z_]+/', $pName)) {
|
||||
$statusVars[] = $pName;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'proc':
|
||||
$result = $this->dbi->query('SHOW PROCESSLIST');
|
||||
$ret['value'] = $result->numRows();
|
||||
break;
|
||||
|
||||
case 'cpu':
|
||||
if (! $sysinfo) {
|
||||
$sysinfo = SysInfo::get();
|
||||
}
|
||||
|
||||
if (! $cpuload) {
|
||||
$cpuload = $sysinfo->loadavg();
|
||||
}
|
||||
|
||||
if (SysInfo::getOs() === 'Linux') {
|
||||
$ret['idle'] = $cpuload['idle'];
|
||||
$ret['busy'] = $cpuload['busy'];
|
||||
} else {
|
||||
$ret['value'] = $cpuload['loadavg'];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'memory':
|
||||
if (! $sysinfo) {
|
||||
$sysinfo = SysInfo::get();
|
||||
}
|
||||
|
||||
if (! $memory) {
|
||||
$memory = $sysinfo->memory();
|
||||
}
|
||||
|
||||
$ret['value'] = $memory[$pName] ?? 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
$serverVars,
|
||||
$statusVars,
|
||||
$ret,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON for log data with type: slow
|
||||
*
|
||||
* @param int $start Unix Time: Start time for query
|
||||
* @param int $end Unix Time: End time for query
|
||||
*/
|
||||
public function getJsonForLogDataTypeSlow(int $start, int $end): ?array
|
||||
{
|
||||
$query = 'SELECT start_time, user_host, ';
|
||||
$query .= 'Sec_to_Time(Sum(Time_to_Sec(query_time))) as query_time, ';
|
||||
$query .= 'Sec_to_Time(Sum(Time_to_Sec(lock_time))) as lock_time, ';
|
||||
$query .= 'SUM(rows_sent) AS rows_sent, ';
|
||||
$query .= 'SUM(rows_examined) AS rows_examined, db, sql_text, ';
|
||||
$query .= 'COUNT(sql_text) AS \'#\' ';
|
||||
$query .= 'FROM `mysql`.`slow_log` ';
|
||||
$query .= 'WHERE start_time > FROM_UNIXTIME(' . $start . ') ';
|
||||
// See: mode = ONLY_FULL_GROUP_BY
|
||||
$query .= 'AND start_time < FROM_UNIXTIME(' . $end . ') GROUP BY start_time, user_host, db, sql_text';
|
||||
|
||||
$result = $this->dbi->tryQuery($query);
|
||||
if ($result === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$return = [
|
||||
'rows' => [],
|
||||
'sum' => [],
|
||||
];
|
||||
|
||||
while ($row = $result->fetchAssoc()) {
|
||||
$type = mb_strtolower(
|
||||
mb_substr(
|
||||
$row['sql_text'],
|
||||
0,
|
||||
(int) mb_strpos($row['sql_text'], ' ')
|
||||
)
|
||||
);
|
||||
|
||||
switch ($type) {
|
||||
case 'insert':
|
||||
case 'update':
|
||||
//Cut off big inserts and updates, but append byte count instead
|
||||
if (mb_strlen($row['sql_text']) > 220) {
|
||||
$implodeSqlText = implode(
|
||||
' ',
|
||||
(array) Util::formatByteDown(
|
||||
mb_strlen($row['sql_text']),
|
||||
2,
|
||||
2
|
||||
)
|
||||
);
|
||||
$row['sql_text'] = mb_substr($row['sql_text'], 0, 200)
|
||||
. '... [' . $implodeSqlText . ']';
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (! isset($return['sum'][$type])) {
|
||||
$return['sum'][$type] = 0;
|
||||
}
|
||||
|
||||
$return['sum'][$type] += $row['#'];
|
||||
$return['rows'][] = $row;
|
||||
}
|
||||
|
||||
$return['sum']['TOTAL'] = array_sum($return['sum']);
|
||||
$return['numRows'] = count($return['rows']);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON for log data with type: general
|
||||
*
|
||||
* @param int $start Unix Time: Start time for query
|
||||
* @param int $end Unix Time: End time for query
|
||||
* @param bool $isTypesLimited Whether to limit types or not
|
||||
* @param bool $removeVariables Whether to remove variables or not
|
||||
*/
|
||||
public function getJsonForLogDataTypeGeneral(
|
||||
int $start,
|
||||
int $end,
|
||||
bool $isTypesLimited,
|
||||
bool $removeVariables
|
||||
): ?array {
|
||||
$limitTypes = '';
|
||||
if ($isTypesLimited) {
|
||||
$limitTypes = 'AND argument REGEXP \'^(INSERT|SELECT|UPDATE|DELETE)\' ';
|
||||
}
|
||||
|
||||
$query = 'SELECT TIME(event_time) as event_time, user_host, thread_id, ';
|
||||
$query .= 'server_id, argument, count(argument) as \'#\' ';
|
||||
$query .= 'FROM `mysql`.`general_log` ';
|
||||
$query .= 'WHERE command_type=\'Query\' ';
|
||||
$query .= 'AND event_time > FROM_UNIXTIME(' . $start . ') ';
|
||||
$query .= 'AND event_time < FROM_UNIXTIME(' . $end . ') ';
|
||||
// See: mode = ONLY_FULL_GROUP_BY
|
||||
$query .= $limitTypes . 'GROUP by event_time, user_host, thread_id, server_id, argument'; // HAVING count > 1';
|
||||
|
||||
$result = $this->dbi->tryQuery($query);
|
||||
if ($result === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$return = [
|
||||
'rows' => [],
|
||||
'sum' => [],
|
||||
];
|
||||
$insertTables = [];
|
||||
$insertTablesFirst = -1;
|
||||
$i = 0;
|
||||
|
||||
while ($row = $result->fetchAssoc()) {
|
||||
preg_match('/^(\w+)\s/', $row['argument'], $match);
|
||||
$type = mb_strtolower($match[1]);
|
||||
|
||||
if (! isset($return['sum'][$type])) {
|
||||
$return['sum'][$type] = 0;
|
||||
}
|
||||
|
||||
$return['sum'][$type] += $row['#'];
|
||||
|
||||
switch ($type) {
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 'insert':
|
||||
// Group inserts if selected
|
||||
if (
|
||||
$removeVariables && preg_match(
|
||||
'/^INSERT INTO (`|\'|"|)([^\s\\1]+)\\1/i',
|
||||
$row['argument'],
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
if (! isset($insertTables[$matches[2]])) {
|
||||
$insertTables[$matches[2]] = 0;
|
||||
}
|
||||
|
||||
$insertTables[$matches[2]]++;
|
||||
if ($insertTables[$matches[2]] > 1) {
|
||||
$return['rows'][$insertTablesFirst]['#'] = $insertTables[$matches[2]];
|
||||
|
||||
// Add a ... to the end of this query to indicate that
|
||||
// there's been other queries
|
||||
$temp = $return['rows'][$insertTablesFirst]['argument'];
|
||||
$return['rows'][$insertTablesFirst]['argument'] .= $this->getSuspensionPoints(
|
||||
$temp[strlen($temp) - 1]
|
||||
);
|
||||
|
||||
// Group this value, thus do not add to the result list
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$insertTablesFirst = $i;
|
||||
$insertTables[$matches[2]] += $row['#'] - 1;
|
||||
}
|
||||
|
||||
// No break here
|
||||
|
||||
case 'update':
|
||||
// Cut off big inserts and updates,
|
||||
// but append byte count therefor
|
||||
if (mb_strlen($row['argument']) > 220) {
|
||||
$row['argument'] = mb_substr($row['argument'], 0, 200)
|
||||
. '... ['
|
||||
. implode(
|
||||
' ',
|
||||
(array) Util::formatByteDown(
|
||||
mb_strlen($row['argument']),
|
||||
2,
|
||||
2
|
||||
)
|
||||
)
|
||||
. ']';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$return['rows'][] = $row;
|
||||
$i++;
|
||||
}
|
||||
|
||||
$return['sum']['TOTAL'] = array_sum($return['sum']);
|
||||
$return['numRows'] = count($return['rows']);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return suspension points if needed
|
||||
*
|
||||
* @param string $lastChar Last char
|
||||
*
|
||||
* @return string Return suspension points if needed
|
||||
*/
|
||||
private function getSuspensionPoints(string $lastChar): string
|
||||
{
|
||||
if ($lastChar !== '.') {
|
||||
return '<br>...';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON for logging vars
|
||||
*
|
||||
* @param string|null $name Variable name
|
||||
* @param string|null $value Variable value
|
||||
*
|
||||
* @return array JSON
|
||||
*/
|
||||
public function getJsonForLoggingVars(?string $name, ?string $value): array
|
||||
{
|
||||
if (isset($name, $value)) {
|
||||
$escapedValue = $this->dbi->escapeString($value);
|
||||
if (! is_numeric($escapedValue)) {
|
||||
$escapedValue = "'" . $escapedValue . "'";
|
||||
}
|
||||
|
||||
if (! preg_match('/[^a-zA-Z0-9_]+/', $name)) {
|
||||
$this->dbi->query('SET GLOBAL ' . $name . ' = ' . $escapedValue);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->dbi->fetchResult(
|
||||
'SHOW GLOBAL VARIABLES WHERE Variable_name IN'
|
||||
. ' ("general_log","slow_query_log","long_query_time","log_output")',
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON for query_analyzer
|
||||
*
|
||||
* @param string $database Database name
|
||||
* @param string $query SQL query
|
||||
*
|
||||
* @return array JSON
|
||||
*/
|
||||
public function getJsonForQueryAnalyzer(
|
||||
string $database,
|
||||
string $query
|
||||
): array {
|
||||
global $cached_affected_rows;
|
||||
|
||||
$return = [];
|
||||
|
||||
if (strlen($database) > 0) {
|
||||
$this->dbi->selectDb($database);
|
||||
}
|
||||
|
||||
$profiling = Profiling::isSupported($this->dbi);
|
||||
|
||||
if ($profiling) {
|
||||
$this->dbi->query('SET PROFILING=1;');
|
||||
}
|
||||
|
||||
// Do not cache query
|
||||
$sqlQuery = preg_replace('/^(\s*SELECT)/i', '\\1 SQL_NO_CACHE', $query);
|
||||
|
||||
$this->dbi->tryQuery($sqlQuery);
|
||||
$return['affectedRows'] = $cached_affected_rows;
|
||||
|
||||
$result = $this->dbi->tryQuery('EXPLAIN ' . $sqlQuery);
|
||||
if ($result !== false) {
|
||||
$return['explain'] = $result->fetchAllAssoc();
|
||||
}
|
||||
|
||||
// In case an error happened
|
||||
$return['error'] = $this->dbi->getError();
|
||||
|
||||
if ($profiling) {
|
||||
$return['profiling'] = [];
|
||||
$result = $this->dbi->tryQuery(
|
||||
'SELECT seq,state,duration FROM INFORMATION_SCHEMA.PROFILING WHERE QUERY_ID=1 ORDER BY seq'
|
||||
);
|
||||
if ($result !== false) {
|
||||
$return['profiling'] = $result->fetchAllAssoc();
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
191
admin/phpMyAdmin/libraries/classes/Server/Status/Processes.php
Normal file
191
admin/phpMyAdmin/libraries/classes/Server/Status/Processes.php
Normal file
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\Status;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function mb_strtolower;
|
||||
use function strlen;
|
||||
use function ucfirst;
|
||||
|
||||
final class Processes
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(DatabaseInterface $dbi)
|
||||
{
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return array<string, array|string|bool>
|
||||
*/
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$urlParams = [];
|
||||
|
||||
$showFullSql = ! empty($params['full']);
|
||||
if ($showFullSql) {
|
||||
$urlParams['full'] = '';
|
||||
} else {
|
||||
$urlParams['full'] = 1;
|
||||
}
|
||||
|
||||
$sqlQuery = $showFullSql
|
||||
? 'SHOW FULL PROCESSLIST'
|
||||
: 'SHOW PROCESSLIST';
|
||||
if (
|
||||
(! empty($params['order_by_field'])
|
||||
&& ! empty($params['sort_order']))
|
||||
|| ! empty($params['showExecuting'])
|
||||
) {
|
||||
$urlParams['order_by_field'] = $params['order_by_field'];
|
||||
$urlParams['sort_order'] = $params['sort_order'];
|
||||
$urlParams['showExecuting'] = $params['showExecuting'];
|
||||
$sqlQuery = 'SELECT * FROM `INFORMATION_SCHEMA`.`PROCESSLIST` ';
|
||||
}
|
||||
|
||||
if (! empty($params['showExecuting'])) {
|
||||
$sqlQuery .= ' WHERE state != "" ';
|
||||
}
|
||||
|
||||
if (! empty($params['order_by_field']) && ! empty($params['sort_order'])) {
|
||||
$sqlQuery .= ' ORDER BY '
|
||||
. Util::backquote($params['order_by_field'])
|
||||
. ' ' . $params['sort_order'];
|
||||
}
|
||||
|
||||
$result = $this->dbi->query($sqlQuery);
|
||||
$rows = [];
|
||||
while ($process = $result->fetchAssoc()) {
|
||||
// Array keys need to modify due to the way it has used
|
||||
// to display column values
|
||||
foreach (array_keys($process) as $key) {
|
||||
$newKey = ucfirst(mb_strtolower($key));
|
||||
if ($newKey === $key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$process[$newKey] = $process[$key];
|
||||
unset($process[$key]);
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'id' => $process['Id'],
|
||||
'user' => $process['User'],
|
||||
'host' => $process['Host'],
|
||||
'db' => ! isset($process['Db']) || strlen($process['Db']) === 0 ? '' : $process['Db'],
|
||||
'command' => $process['Command'],
|
||||
'time' => $process['Time'],
|
||||
'state' => ! empty($process['State']) ? $process['State'] : '---',
|
||||
'progress' => ! empty($process['Progress']) ? $process['Progress'] : '---',
|
||||
'info' => ! empty($process['Info']) ? Generator::formatSql($process['Info'], ! $showFullSql) : '---',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'columns' => $this->getSortableColumnsForProcessList($showFullSql, $params),
|
||||
'rows' => $rows,
|
||||
'refresh_params' => $urlParams,
|
||||
'is_mariadb' => $this->dbi->isMariaDB(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getSortableColumnsForProcessList(bool $showFullSql, array $params): array
|
||||
{
|
||||
// This array contains display name and real column name of each
|
||||
// sortable column in the table
|
||||
$sortableColumns = [
|
||||
[
|
||||
'column_name' => __('ID'),
|
||||
'order_by_field' => 'Id',
|
||||
],
|
||||
[
|
||||
'column_name' => __('User'),
|
||||
'order_by_field' => 'User',
|
||||
],
|
||||
[
|
||||
'column_name' => __('Host'),
|
||||
'order_by_field' => 'Host',
|
||||
],
|
||||
[
|
||||
'column_name' => __('Database'),
|
||||
'order_by_field' => 'Db',
|
||||
],
|
||||
[
|
||||
'column_name' => __('Command'),
|
||||
'order_by_field' => 'Command',
|
||||
],
|
||||
[
|
||||
'column_name' => __('Time'),
|
||||
'order_by_field' => 'Time',
|
||||
],
|
||||
[
|
||||
'column_name' => __('Status'),
|
||||
'order_by_field' => 'State',
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->dbi->isMariaDB()) {
|
||||
$sortableColumns[] = [
|
||||
'column_name' => __('Progress'),
|
||||
'order_by_field' => 'Progress',
|
||||
];
|
||||
}
|
||||
|
||||
$sortableColumns[] = [
|
||||
'column_name' => __('SQL query'),
|
||||
'order_by_field' => 'Info',
|
||||
];
|
||||
|
||||
$sortableColCount = count($sortableColumns);
|
||||
|
||||
$columns = [];
|
||||
foreach ($sortableColumns as $columnKey => $column) {
|
||||
$is_sorted = ! empty($params['order_by_field'])
|
||||
&& ! empty($params['sort_order'])
|
||||
&& ($params['order_by_field'] == $column['order_by_field']);
|
||||
|
||||
$column['sort_order'] = 'ASC';
|
||||
if ($is_sorted && $params['sort_order'] === 'ASC') {
|
||||
$column['sort_order'] = 'DESC';
|
||||
}
|
||||
|
||||
if (isset($params['showExecuting'])) {
|
||||
$column['showExecuting'] = 'on';
|
||||
}
|
||||
|
||||
$columns[$columnKey] = [
|
||||
'name' => $column['column_name'],
|
||||
'params' => $column,
|
||||
'is_sorted' => $is_sorted,
|
||||
'sort_order' => $column['sort_order'],
|
||||
'has_full_query' => false,
|
||||
'is_full' => false,
|
||||
];
|
||||
|
||||
if (0 !== --$sortableColCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$columns[$columnKey]['has_full_query'] = true;
|
||||
if (! $showFullSql) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$columns[$columnKey]['is_full'] = true;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
}
|
48
admin/phpMyAdmin/libraries/classes/Server/SysInfo/Base.php
Normal file
48
admin/phpMyAdmin/libraries/classes/Server/SysInfo/Base.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\SysInfo;
|
||||
|
||||
use const PHP_OS;
|
||||
|
||||
/**
|
||||
* Basic SysInfo class not providing any real data.
|
||||
*/
|
||||
class Base
|
||||
{
|
||||
/**
|
||||
* The OS name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $os = PHP_OS;
|
||||
|
||||
/**
|
||||
* Gets load information
|
||||
*
|
||||
* @return array with load data
|
||||
*/
|
||||
public function loadavg()
|
||||
{
|
||||
return ['loadavg' => 0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about memory usage
|
||||
*
|
||||
* @return array with memory usage data
|
||||
*/
|
||||
public function memory()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether class is supported in this environment
|
||||
*/
|
||||
public function supported(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
115
admin/phpMyAdmin/libraries/classes/Server/SysInfo/Linux.php
Normal file
115
admin/phpMyAdmin/libraries/classes/Server/SysInfo/Linux.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\SysInfo;
|
||||
|
||||
use function array_combine;
|
||||
use function array_merge;
|
||||
use function file_get_contents;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function is_readable;
|
||||
use function mb_strpos;
|
||||
use function mb_substr;
|
||||
use function preg_match_all;
|
||||
use function preg_split;
|
||||
|
||||
/**
|
||||
* Linux based SysInfo class
|
||||
*/
|
||||
class Linux extends Base
|
||||
{
|
||||
/**
|
||||
* The OS name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $os = 'Linux';
|
||||
|
||||
/**
|
||||
* Gets load information
|
||||
*
|
||||
* @return array<string, int> with load data
|
||||
*/
|
||||
public function loadavg()
|
||||
{
|
||||
$buf = file_get_contents('/proc/stat');
|
||||
if ($buf === false) {
|
||||
$buf = '';
|
||||
}
|
||||
|
||||
$pos = mb_strpos($buf, "\n");
|
||||
if ($pos === false) {
|
||||
$pos = 0;
|
||||
}
|
||||
|
||||
$nums = preg_split(
|
||||
'/\s+/',
|
||||
mb_substr(
|
||||
$buf,
|
||||
0,
|
||||
$pos
|
||||
)
|
||||
);
|
||||
|
||||
if (! is_array($nums)) {
|
||||
return ['busy' => 0, 'idle' => 0];
|
||||
}
|
||||
|
||||
return [
|
||||
'busy' => (int) $nums[1] + (int) $nums[2] + (int) $nums[3],
|
||||
'idle' => (int) $nums[4],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether class is supported in this environment
|
||||
*/
|
||||
public function supported(): bool
|
||||
{
|
||||
return @is_readable('/proc/meminfo') && @is_readable('/proc/stat');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about memory usage
|
||||
*
|
||||
* @return array with memory usage data
|
||||
*/
|
||||
public function memory()
|
||||
{
|
||||
$content = @file_get_contents('/proc/meminfo');
|
||||
if ($content === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
preg_match_all(SysInfo::MEMORY_REGEXP, $content, $matches);
|
||||
|
||||
/** @var array<string, int>|false $mem */
|
||||
$mem = array_combine($matches[1], $matches[2]);
|
||||
if ($mem === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$defaults = [
|
||||
'MemTotal' => 0,
|
||||
'MemFree' => 0,
|
||||
'Cached' => 0,
|
||||
'Buffers' => 0,
|
||||
'SwapTotal' => 0,
|
||||
'SwapFree' => 0,
|
||||
'SwapCached' => 0,
|
||||
];
|
||||
|
||||
$mem = array_merge($defaults, $mem);
|
||||
|
||||
foreach ($mem as $idx => $value) {
|
||||
$mem[$idx] = intval($value);
|
||||
}
|
||||
|
||||
$mem['MemUsed'] = $mem['MemTotal'] - $mem['MemFree'] - $mem['Cached'] - $mem['Buffers'];
|
||||
$mem['SwapUsed'] = $mem['SwapTotal'] - $mem['SwapFree'] - $mem['SwapCached'];
|
||||
|
||||
return $mem;
|
||||
}
|
||||
}
|
83
admin/phpMyAdmin/libraries/classes/Server/SysInfo/SunOs.php
Normal file
83
admin/phpMyAdmin/libraries/classes/Server/SysInfo/SunOs.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\SysInfo;
|
||||
|
||||
use function explode;
|
||||
use function is_readable;
|
||||
use function shell_exec;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* SunOS based SysInfo class
|
||||
*/
|
||||
class SunOs extends Base
|
||||
{
|
||||
/**
|
||||
* The OS name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $os = 'SunOS';
|
||||
|
||||
/**
|
||||
* Read value from kstat
|
||||
*
|
||||
* @param string $key Key to read
|
||||
*
|
||||
* @return string with value
|
||||
*/
|
||||
private function kstat($key)
|
||||
{
|
||||
/** @psalm-suppress ForbiddenCode */
|
||||
$m = shell_exec('kstat -p d ' . $key);
|
||||
|
||||
if ($m) {
|
||||
[, $value] = explode("\t", trim($m), 2);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets load information
|
||||
*
|
||||
* @return array with load data
|
||||
*/
|
||||
public function loadavg()
|
||||
{
|
||||
$load1 = $this->kstat('unix:0:system_misc:avenrun_1min');
|
||||
|
||||
return ['loadavg' => $load1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether class is supported in this environment
|
||||
*/
|
||||
public function supported(): bool
|
||||
{
|
||||
return @is_readable('/proc/meminfo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about memory usage
|
||||
*
|
||||
* @return array with memory usage data
|
||||
*/
|
||||
public function memory()
|
||||
{
|
||||
$pagesize = (int) $this->kstat('unix:0:seg_cache:slab_size');
|
||||
$mem = [];
|
||||
$mem['MemTotal'] = (int) $this->kstat('unix:0:system_pages:pagestotal') * $pagesize;
|
||||
$mem['MemUsed'] = (int) $this->kstat('unix:0:system_pages:pageslocked') * $pagesize;
|
||||
$mem['MemFree'] = (int) $this->kstat('unix:0:system_pages:pagesfree') * $pagesize;
|
||||
$mem['SwapTotal'] = (int) $this->kstat('unix:0:vminfo:swap_avail') / 1024;
|
||||
$mem['SwapUsed'] = (int) $this->kstat('unix:0:vminfo:swap_alloc') / 1024;
|
||||
$mem['SwapFree'] = (int) $this->kstat('unix:0:vminfo:swap_free') / 1024;
|
||||
|
||||
return $mem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\SysInfo;
|
||||
|
||||
use function in_array;
|
||||
use function ucfirst;
|
||||
|
||||
use const PHP_OS;
|
||||
|
||||
/**
|
||||
* Library for extracting information about system memory and cpu.
|
||||
* Currently supports all Windows and Linux platforms
|
||||
*
|
||||
* This code is based on the OS Classes from the phpsysinfo project
|
||||
* (https://phpsysinfo.github.io/phpsysinfo/)
|
||||
*/
|
||||
class SysInfo
|
||||
{
|
||||
public const MEMORY_REGEXP = '/^(MemTotal|MemFree|Cached|Buffers|SwapCached|SwapTotal|SwapFree):\s+(.*)\s*kB/im';
|
||||
|
||||
/**
|
||||
* Returns OS type used for sysinfo class
|
||||
*
|
||||
* @param string $php_os PHP_OS constant
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getOs($php_os = PHP_OS)
|
||||
{
|
||||
// look for common UNIX-like systems
|
||||
$unix_like = [
|
||||
'FreeBSD',
|
||||
'DragonFly',
|
||||
];
|
||||
if (in_array($php_os, $unix_like)) {
|
||||
$php_os = 'Linux';
|
||||
}
|
||||
|
||||
return ucfirst($php_os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets SysInfo class matching current OS
|
||||
*
|
||||
* @return Base sysinfo class
|
||||
*/
|
||||
public static function get()
|
||||
{
|
||||
$php_os = self::getOs();
|
||||
|
||||
switch ($php_os) {
|
||||
case 'Linux':
|
||||
$sysInfo = new Linux();
|
||||
if ($sysInfo->supported()) {
|
||||
return $sysInfo;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'WINNT':
|
||||
$sysInfo = new WindowsNt();
|
||||
if ($sysInfo->supported()) {
|
||||
return $sysInfo;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'SunOS':
|
||||
$sysInfo = new SunOs();
|
||||
if ($sysInfo->supported()) {
|
||||
return $sysInfo;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return new Base();
|
||||
}
|
||||
}
|
147
admin/phpMyAdmin/libraries/classes/Server/SysInfo/WindowsNt.php
Normal file
147
admin/phpMyAdmin/libraries/classes/Server/SysInfo/WindowsNt.php
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Server\SysInfo;
|
||||
|
||||
use COM;
|
||||
|
||||
use function class_exists;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Windows NT based SysInfo class
|
||||
*/
|
||||
class WindowsNt extends Base
|
||||
{
|
||||
/** @var COM|null */
|
||||
private $wmi;
|
||||
|
||||
/**
|
||||
* The OS name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $os = 'WINNT';
|
||||
|
||||
/**
|
||||
* Constructor to access to wmi database.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (! class_exists('COM')) {
|
||||
$this->wmi = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize the wmi object
|
||||
$objLocator = new COM('WbemScripting.SWbemLocator');
|
||||
$this->wmi = $objLocator->ConnectServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets load information
|
||||
*
|
||||
* @return array with load data
|
||||
*/
|
||||
public function loadavg()
|
||||
{
|
||||
$sum = 0;
|
||||
$buffer = $this->getWMI('Win32_Processor', ['LoadPercentage']);
|
||||
|
||||
foreach ($buffer as $load) {
|
||||
$value = $load['LoadPercentage'];
|
||||
$sum += $value;
|
||||
}
|
||||
|
||||
return ['loadavg' => $sum / count($buffer)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether class is supported in this environment
|
||||
*/
|
||||
public function supported(): bool
|
||||
{
|
||||
return $this->wmi !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from WMI
|
||||
*
|
||||
* @param string $strClass Class to read
|
||||
* @param array $strValue Values to read
|
||||
*
|
||||
* @return array with results
|
||||
*/
|
||||
private function getWMI($strClass, array $strValue = [])
|
||||
{
|
||||
$arrData = [];
|
||||
|
||||
$objWEBM = $this->wmi->Get($strClass);
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$arrProp = $objWEBM->Properties_;
|
||||
$arrWEBMCol = $objWEBM->Instances_();
|
||||
foreach ($arrWEBMCol as $objItem) {
|
||||
$arrInstance = [];
|
||||
foreach ($arrProp as $propItem) {
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$name = $propItem->Name;
|
||||
if (! empty($strValue) && ! in_array($name, $strValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $objItem->$name;
|
||||
if (is_string($value)) {
|
||||
$arrInstance[$name] = trim($value);
|
||||
} else {
|
||||
$arrInstance[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$arrData[] = $arrInstance;
|
||||
}
|
||||
|
||||
return $arrData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about memory usage
|
||||
*
|
||||
* @return array with memory usage data
|
||||
*/
|
||||
public function memory()
|
||||
{
|
||||
$buffer = $this->getWMI(
|
||||
'Win32_OperatingSystem',
|
||||
[
|
||||
'TotalVisibleMemorySize',
|
||||
'FreePhysicalMemory',
|
||||
]
|
||||
);
|
||||
$mem = [];
|
||||
$mem['MemTotal'] = $buffer[0]['TotalVisibleMemorySize'];
|
||||
$mem['MemFree'] = $buffer[0]['FreePhysicalMemory'];
|
||||
$mem['MemUsed'] = $mem['MemTotal'] - $mem['MemFree'];
|
||||
|
||||
$buffer = $this->getWMI('Win32_PageFileUsage');
|
||||
|
||||
$mem['SwapTotal'] = 0;
|
||||
$mem['SwapFree'] = 0;
|
||||
$mem['SwapUsed'] = 0;
|
||||
$mem['SwapPeak'] = 0;
|
||||
|
||||
foreach ($buffer as $swapdevice) {
|
||||
$mem['SwapTotal'] += $swapdevice['AllocatedBaseSize'] * 1024;
|
||||
$mem['SwapUsed'] += $swapdevice['CurrentUsage'] * 1024;
|
||||
$mem['SwapPeak'] += $swapdevice['PeakUsage'] * 1024;
|
||||
}
|
||||
|
||||
$mem['SwapFree'] = $mem['SwapTotal'] - $mem['SwapUsed'];
|
||||
|
||||
return $mem;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue