Update website
This commit is contained in:
parent
0a686aeb9a
commit
c4ffa0f6ee
4360 changed files with 1727 additions and 718385 deletions
|
@ -1,101 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function __;
|
||||
use function strlen;
|
||||
|
||||
abstract class AbstractController
|
||||
{
|
||||
/** @var ResponseRenderer */
|
||||
protected $response;
|
||||
|
||||
/** @var Template */
|
||||
protected $template;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $templateData
|
||||
*/
|
||||
protected function render(string $templatePath, array $templateData = []): void
|
||||
{
|
||||
$this->response->addHTML($this->template->render($templatePath, $templateData));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $files
|
||||
*/
|
||||
protected function addScriptFiles(array $files): void
|
||||
{
|
||||
$header = $this->response->getHeader();
|
||||
$scripts = $header->getScripts();
|
||||
$scripts->addFiles($files);
|
||||
}
|
||||
|
||||
protected function hasDatabase(): bool
|
||||
{
|
||||
global $db, $is_db, $errno, $dbi, $message;
|
||||
|
||||
if (isset($is_db) && $is_db) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$is_db = false;
|
||||
if (strlen($db) > 0) {
|
||||
$is_db = $dbi->selectDb($db);
|
||||
// This "Command out of sync" 2014 error may happen, for example
|
||||
// after calling a MySQL procedure; at this point we can't select
|
||||
// the db but it's not necessarily wrong
|
||||
if ($dbi->getError() && $errno == 2014) {
|
||||
$is_db = true;
|
||||
unset($errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($db) === 0 || ! $is_db) {
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(
|
||||
'message',
|
||||
Message::error(__('No databases selected.'))
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not a valid db name -> back to the welcome page
|
||||
$params = ['reload' => '1'];
|
||||
if (isset($message)) {
|
||||
$params['message'] = $message;
|
||||
}
|
||||
|
||||
$this->redirect('/', $params);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $is_db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*/
|
||||
protected function redirect(string $route, array $params = []): void
|
||||
{
|
||||
$uri = './index.php?route=' . $route . Url::getCommonRaw($params, '&');
|
||||
Core::sendHeaderLocation($uri);
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\BrowseForeigners;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Display selection for relational field values
|
||||
*/
|
||||
class BrowseForeignersController extends AbstractController
|
||||
{
|
||||
/** @var BrowseForeigners */
|
||||
private $browseForeigners;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
BrowseForeigners $browseForeigners,
|
||||
Relation $relation
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->browseForeigners = $browseForeigners;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
/** @var string|null $database */
|
||||
$database = $request->getParsedBodyParam('db');
|
||||
/** @var string|null $table */
|
||||
$table = $request->getParsedBodyParam('table');
|
||||
/** @var string|null $field */
|
||||
$field = $request->getParsedBodyParam('field');
|
||||
/** @var string $fieldKey */
|
||||
$fieldKey = $request->getParsedBodyParam('fieldkey', '');
|
||||
/** @var string $data */
|
||||
$data = $request->getParsedBodyParam('data', '');
|
||||
/** @var string|null $foreignShowAll */
|
||||
$foreignShowAll = $request->getParsedBodyParam('foreign_showAll');
|
||||
/** @var string $foreignFilter */
|
||||
$foreignFilter = $request->getParsedBodyParam('foreign_filter', '');
|
||||
|
||||
if (! isset($database, $table, $field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->getFooter()->setMinimal();
|
||||
$header = $this->response->getHeader();
|
||||
$header->disableMenuAndConsole();
|
||||
$header->setBodyId('body_browse_foreigners');
|
||||
|
||||
$foreigners = $this->relation->getForeigners($database, $table);
|
||||
$foreignLimit = $this->browseForeigners->getForeignLimit($foreignShowAll);
|
||||
$foreignData = $this->relation->getForeignData(
|
||||
$foreigners,
|
||||
$field,
|
||||
true,
|
||||
$foreignFilter,
|
||||
$foreignLimit ?? '',
|
||||
true
|
||||
);
|
||||
|
||||
$this->response->addHTML($this->browseForeigners->getHtmlForRelationalFieldSelection(
|
||||
$database,
|
||||
$table,
|
||||
$field,
|
||||
$foreignData,
|
||||
$fieldKey,
|
||||
$data
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple script to set correct charset for changelog
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use function __;
|
||||
use function array_keys;
|
||||
use function file_get_contents;
|
||||
use function htmlspecialchars;
|
||||
use function is_readable;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use function preg_replace;
|
||||
use function printf;
|
||||
use function readgzfile;
|
||||
use function substr;
|
||||
|
||||
class ChangeLogController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
$this->response->disable();
|
||||
$this->response->getHeader()->sendHttpHeaders();
|
||||
|
||||
$filename = CHANGELOG_FILE;
|
||||
|
||||
/**
|
||||
* Read changelog.
|
||||
*/
|
||||
// Check if the file is available, some distributions remove these.
|
||||
if (! @is_readable($filename)) {
|
||||
printf(
|
||||
__(
|
||||
'The %s file is not available on this system, please visit %s for more information.'
|
||||
),
|
||||
$filename,
|
||||
'<a href="https://www.phpmyadmin.net/">phpmyadmin.net</a>'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if the if is in a compressed format
|
||||
if (substr($filename, -3) === '.gz') {
|
||||
ob_start();
|
||||
readgzfile($filename);
|
||||
$changelog = ob_get_clean();
|
||||
} else {
|
||||
$changelog = file_get_contents($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whole changelog in variable.
|
||||
*/
|
||||
$changelog = htmlspecialchars((string) $changelog);
|
||||
|
||||
$github_url = 'https://github.com/phpmyadmin/phpmyadmin/';
|
||||
$faq_url = 'https://docs.phpmyadmin.net/en/latest/faq.html';
|
||||
|
||||
$replaces = [
|
||||
'@(https?://[./a-zA-Z0-9.-_-]*[/a-zA-Z0-9_])@' => '<a href="url.php?url=\\1">\\1</a>',
|
||||
|
||||
// mail address
|
||||
'/([0-9]{4}-[0-9]{2}-[0-9]{2}) (.+[^ ]) +<(.*@.*)>/i' => '\\1 <a href="mailto:\\3">\\2</a>',
|
||||
|
||||
// FAQ entries
|
||||
'/FAQ ([0-9]+)\.([0-9a-z]+)/i' => '<a href="url.php?url=' . $faq_url . '#faq\\1-\\2">FAQ \\1.\\2</a>',
|
||||
|
||||
// GitHub issues
|
||||
'/issue\s*#?([0-9]{4,5}) /i' => '<a href="url.php?url=' . $github_url . 'issues/\\1">issue #\\1</a> ',
|
||||
|
||||
// CVE/CAN entries
|
||||
'/((CAN|CVE)-[0-9]+-[0-9]+)/' => '<a href="url.php?url='
|
||||
. 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=\\1">\\1</a>',
|
||||
|
||||
// PMASAentries
|
||||
'/(PMASA-[0-9]+-[0-9]+)/' => '<a href="url.php?url=https://www.phpmyadmin.net/security/\\1/">\\1</a>',
|
||||
|
||||
// Highlight releases (with links)
|
||||
'/([0-9]+)\.([0-9]+)\.([0-9]+)\.0 (\([0-9-]+\))/' => '<a id="\\1_\\2_\\3"></a>'
|
||||
. '<a href="url.php?url=' . $github_url . 'commits/RELEASE_\\1_\\2_\\3">'
|
||||
. '\\1.\\2.\\3.0 \\4</a>',
|
||||
'/([0-9]+)\.([0-9]+)\.([0-9]+)\.([1-9][0-9]*) (\([0-9-]+\))/' => '<a id="\\1_\\2_\\3_\\4"></a>'
|
||||
. '<a href="url.php?url=' . $github_url . 'commits/RELEASE_\\1_\\2_\\3_\\4">'
|
||||
. '\\1.\\2.\\3.\\4 \\5</a>',
|
||||
|
||||
// Highlight releases (not linkable)
|
||||
'/( ### )(.*)/' => '\\1<b>\\2</b>',
|
||||
|
||||
// Links target and rel
|
||||
'/a href="/' => 'a target="_blank" rel="noopener noreferrer" href="',
|
||||
|
||||
];
|
||||
|
||||
$this->response->header('Content-type: text/html; charset=utf-8');
|
||||
|
||||
echo $this->template->render('changelog', [
|
||||
'changelog' => preg_replace(array_keys($replaces), $replaces, $changelog),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use const SQL_DIR;
|
||||
|
||||
/**
|
||||
* Displays status of phpMyAdmin configuration storage
|
||||
*/
|
||||
class CheckRelationsController extends AbstractController
|
||||
{
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Relation $relation)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $db, $cfg;
|
||||
|
||||
/** @var string|null $createPmaDb */
|
||||
$createPmaDb = $request->getParsedBodyParam('create_pmadb');
|
||||
/** @var string|null $fixAllPmaDb */
|
||||
$fixAllPmaDb = $request->getParsedBodyParam('fixall_pmadb');
|
||||
/** @var string|null $fixPmaDb */
|
||||
$fixPmaDb = $request->getParsedBodyParam('fix_pmadb');
|
||||
|
||||
$cfgStorageDbName = $this->relation->getConfigurationStorageDbName();
|
||||
|
||||
// If request for creating the pmadb
|
||||
if (isset($createPmaDb) && $this->relation->createPmaDatabase($cfgStorageDbName)) {
|
||||
$this->relation->fixPmaTables($cfgStorageDbName);
|
||||
}
|
||||
|
||||
// If request for creating all PMA tables.
|
||||
if (isset($fixAllPmaDb)) {
|
||||
$this->relation->fixPmaTables($db);
|
||||
}
|
||||
|
||||
// If request for creating missing PMA tables.
|
||||
if (isset($fixPmaDb)) {
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
$this->relation->fixPmaTables((string) $relationParameters->db);
|
||||
}
|
||||
|
||||
// Do not use any previous $relationParameters value as it could have changed after a successful fixPmaTables()
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('relation/check_relations', [
|
||||
'db' => $db,
|
||||
'zero_conf' => $cfg['ZeroConf'],
|
||||
'relation_parameters' => $relationParameters->toArray(),
|
||||
'sql_dir' => SQL_DIR,
|
||||
'config_storage_database_name' => $cfgStorageDbName,
|
||||
'are_config_storage_tables_defined' => $this->relation->arePmadbTablesDefined(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
final class CollationConnectionController extends AbstractController
|
||||
{
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Config $config)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$this->config->setUserValue(
|
||||
null,
|
||||
'DefaultConnectionCollation',
|
||||
$_POST['collation_connection'],
|
||||
'utf8mb4_unicode_ci'
|
||||
);
|
||||
|
||||
$this->response->header('Location: index.php?route=/' . Url::getCommonRaw([], '&'));
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
final class ColumnController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
/** @var string|null $db */
|
||||
$db = $request->getParsedBodyParam('db');
|
||||
/** @var string|null $table */
|
||||
$table = $request->getParsedBodyParam('table');
|
||||
|
||||
if (! isset($db, $table)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(['message' => Message::error()]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON(['columns' => $this->dbi->getColumnNames($db, $table)]);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Config;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
final class GetConfigController extends AbstractController
|
||||
{
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Config $config)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
/** @var string|null $key */
|
||||
$key = $request->getParsedBodyParam('key');
|
||||
|
||||
if (! isset($key)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(['message' => Message::error()]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON(['value' => $this->config->get($key)]);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Config;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function json_decode;
|
||||
|
||||
final class SetConfigController extends AbstractController
|
||||
{
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Config $config)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
/** @var string|null $key */
|
||||
$key = $request->getParsedBodyParam('key');
|
||||
/** @var string|null $value */
|
||||
$value = $request->getParsedBodyParam('value');
|
||||
|
||||
if (! isset($key, $value)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(['message' => Message::error()]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->config->setUserValue(null, $key, json_decode($value));
|
||||
|
||||
if ($result === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(['message' => $result]);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController as Controller;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
abstract class AbstractController extends Controller
|
||||
{
|
||||
/** @var string */
|
||||
protected $db;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->db = $db;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\CentralColumns;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Database\CentralColumns;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
final class PopulateColumnsController extends AbstractController
|
||||
{
|
||||
/** @var CentralColumns */
|
||||
private $centralColumns;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
CentralColumns $centralColumns
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->centralColumns = $centralColumns;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$columns = $this->centralColumns->getColumnsNotInCentralList($this->db, $_POST['selectedTable']);
|
||||
$this->render('database/central_columns/populate_columns', ['columns' => $columns]);
|
||||
}
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Central Columns view/edit
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Database\CentralColumns;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
use function is_bool;
|
||||
use function is_numeric;
|
||||
use function parse_str;
|
||||
use function sprintf;
|
||||
|
||||
class CentralColumnsController extends AbstractController
|
||||
{
|
||||
/** @var CentralColumns */
|
||||
private $centralColumns;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
CentralColumns $centralColumns
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->centralColumns = $centralColumns;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $message, $pos, $num_cols;
|
||||
|
||||
if (isset($_POST['edit_save'])) {
|
||||
echo $this->editSave([
|
||||
'col_name' => $_POST['col_name'] ?? null,
|
||||
'orig_col_name' => $_POST['orig_col_name'] ?? null,
|
||||
'col_default' => $_POST['col_default'] ?? null,
|
||||
'col_default_sel' => $_POST['col_default_sel'] ?? null,
|
||||
'col_extra' => $_POST['col_extra'] ?? null,
|
||||
'col_isNull' => $_POST['col_isNull'] ?? null,
|
||||
'col_length' => $_POST['col_length'] ?? null,
|
||||
'col_attribute' => $_POST['col_attribute'] ?? null,
|
||||
'col_type' => $_POST['col_type'] ?? null,
|
||||
'collation' => $_POST['collation'] ?? null,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['add_new_column'])) {
|
||||
$tmp_msg = $this->addNewColumn([
|
||||
'col_name' => $_POST['col_name'] ?? null,
|
||||
'col_default' => $_POST['col_default'] ?? null,
|
||||
'col_default_sel' => $_POST['col_default_sel'] ?? null,
|
||||
'col_extra' => $_POST['col_extra'] ?? null,
|
||||
'col_isNull' => $_POST['col_isNull'] ?? null,
|
||||
'col_length' => $_POST['col_length'] ?? null,
|
||||
'col_attribute' => $_POST['col_attribute'] ?? null,
|
||||
'col_type' => $_POST['col_type'] ?? null,
|
||||
'collation' => $_POST['collation'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
if (isset($_POST['getColumnList'])) {
|
||||
$this->response->addJSON('message', $this->getColumnList([
|
||||
'cur_table' => $_POST['cur_table'] ?? null,
|
||||
]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['add_column'])) {
|
||||
$tmp_msg = $this->addColumn([
|
||||
'table-select' => $_POST['table-select'] ?? null,
|
||||
'column-select' => $_POST['column-select'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->addScriptFiles([
|
||||
'vendor/jquery/jquery.uitablefilter.js',
|
||||
'vendor/jquery/jquery.tablesorter.js',
|
||||
'database/central_columns.js',
|
||||
]);
|
||||
|
||||
if (isset($_POST['edit_central_columns_page'])) {
|
||||
$this->editPage([
|
||||
'selected_fld' => $_POST['selected_fld'] ?? null,
|
||||
'db' => $_POST['db'] ?? null,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['multi_edit_central_column_save'])) {
|
||||
$message = $this->updateMultipleColumn([
|
||||
'db' => $_POST['db'] ?? null,
|
||||
'orig_col_name' => $_POST['orig_col_name'] ?? null,
|
||||
'field_name' => $_POST['field_name'] ?? null,
|
||||
'field_default_type' => $_POST['field_default_type'] ?? null,
|
||||
'field_default_value' => $_POST['field_default_value'] ?? null,
|
||||
'field_length' => $_POST['field_length'] ?? null,
|
||||
'field_attribute' => $_POST['field_attribute'] ?? null,
|
||||
'field_type' => $_POST['field_type'] ?? null,
|
||||
'field_collation' => $_POST['field_collation'] ?? null,
|
||||
'field_null' => $_POST['field_null'] ?? null,
|
||||
'col_extra' => $_POST['col_extra'] ?? null,
|
||||
]);
|
||||
if (! is_bool($message)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $message);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['delete_save'])) {
|
||||
$tmp_msg = $this->deleteSave([
|
||||
'db' => $_POST['db'] ?? null,
|
||||
'col_name' => $_POST['col_name'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->main([
|
||||
'pos' => $_POST['pos'] ?? null,
|
||||
'total_rows' => $_POST['total_rows'] ?? null,
|
||||
]);
|
||||
|
||||
$pos = 0;
|
||||
if (isset($_POST['pos']) && is_numeric($_POST['pos'])) {
|
||||
$pos = (int) $_POST['pos'];
|
||||
}
|
||||
|
||||
$num_cols = $this->centralColumns->getColumnsCount($db, $pos, (int) $cfg['MaxRows']);
|
||||
$message = Message::success(
|
||||
sprintf(__('Showing rows %1$s - %2$s.'), $pos + 1, $pos + $num_cols)
|
||||
);
|
||||
if (! isset($tmp_msg) || $tmp_msg === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = $tmp_msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
public function main(array $params): void
|
||||
{
|
||||
global $text_dir;
|
||||
|
||||
if (! empty($params['total_rows']) && is_numeric($params['total_rows'])) {
|
||||
$totalRows = (int) $params['total_rows'];
|
||||
} else {
|
||||
$totalRows = $this->centralColumns->getCount($this->db);
|
||||
}
|
||||
|
||||
$pos = 0;
|
||||
if (isset($params['pos']) && is_numeric($params['pos'])) {
|
||||
$pos = (int) $params['pos'];
|
||||
}
|
||||
|
||||
$variables = $this->centralColumns->getTemplateVariablesForMain($this->db, $totalRows, $pos, $text_dir);
|
||||
|
||||
$this->render('database/central_columns/main', $variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return array JSON
|
||||
*/
|
||||
public function getColumnList(array $params): array
|
||||
{
|
||||
return $this->centralColumns->getListRaw($this->db, $params['cur_table'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return true|Message
|
||||
*/
|
||||
public function editSave(array $params)
|
||||
{
|
||||
$columnDefault = $params['col_default'];
|
||||
if ($columnDefault === 'NONE' && $params['col_default_sel'] !== 'USER_DEFINED') {
|
||||
$columnDefault = '';
|
||||
}
|
||||
|
||||
return $this->centralColumns->updateOneColumn(
|
||||
$this->db,
|
||||
$params['orig_col_name'],
|
||||
$params['col_name'],
|
||||
$params['col_type'],
|
||||
$params['col_attribute'],
|
||||
$params['col_length'],
|
||||
isset($params['col_isNull']) ? 1 : 0,
|
||||
$params['collation'],
|
||||
$params['col_extra'] ?? '',
|
||||
$columnDefault
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return true|Message
|
||||
*/
|
||||
public function addNewColumn(array $params)
|
||||
{
|
||||
$columnDefault = $params['col_default'];
|
||||
if ($columnDefault === 'NONE' && $params['col_default_sel'] !== 'USER_DEFINED') {
|
||||
$columnDefault = '';
|
||||
}
|
||||
|
||||
return $this->centralColumns->updateOneColumn(
|
||||
$this->db,
|
||||
'',
|
||||
$params['col_name'],
|
||||
$params['col_type'],
|
||||
$params['col_attribute'],
|
||||
$params['col_length'],
|
||||
isset($params['col_isNull']) ? 1 : 0,
|
||||
$params['collation'],
|
||||
$params['col_extra'] ?? '',
|
||||
$columnDefault
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return true|Message
|
||||
*/
|
||||
public function addColumn(array $params)
|
||||
{
|
||||
return $this->centralColumns->syncUniqueColumns(
|
||||
[$params['column-select']],
|
||||
false,
|
||||
$params['table-select']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
public function editPage(array $params): void
|
||||
{
|
||||
$rows = $this->centralColumns->getHtmlForEditingPage($params['selected_fld'], $params['db']);
|
||||
|
||||
$this->render('database/central_columns/edit', ['rows' => $rows]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return true|Message
|
||||
*/
|
||||
public function updateMultipleColumn(array $params)
|
||||
{
|
||||
return $this->centralColumns->updateMultipleColumn($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params Request parameters
|
||||
*
|
||||
* @return true|Message
|
||||
*/
|
||||
public function deleteSave(array $params)
|
||||
{
|
||||
$name = [];
|
||||
parse_str($params['col_name'], $name);
|
||||
|
||||
return $this->centralColumns->deleteColumnsFromList($params['db'], $name['selected_fld'], false);
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Index;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Transformations;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function is_array;
|
||||
use function str_replace;
|
||||
|
||||
class DataDictionaryController extends AbstractController
|
||||
{
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Transformations */
|
||||
private $transformations;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Relation $relation,
|
||||
Transformations $transformations,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->relation = $relation;
|
||||
$this->transformations = $transformations;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
Util::checkParameters(['db'], true);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$comment = $this->relation->getDbComment($this->db);
|
||||
|
||||
$this->dbi->selectDb($this->db);
|
||||
$tablesNames = $this->dbi->getTables($this->db);
|
||||
|
||||
$tables = [];
|
||||
foreach ($tablesNames as $tableName) {
|
||||
$showComment = (string) $this->dbi->getTable($this->db, $tableName)->getStatusInfo('TABLE_COMMENT');
|
||||
|
||||
[, $primaryKeys] = Util::processIndexData(
|
||||
$this->dbi->getTableIndexes($this->db, $tableName)
|
||||
);
|
||||
|
||||
[$foreigners, $hasRelation] = $this->relation->getRelationsAndStatus(
|
||||
$relationParameters->relationFeature !== null,
|
||||
$this->db,
|
||||
$tableName
|
||||
);
|
||||
|
||||
$columnsComments = $this->relation->getComments($this->db, $tableName);
|
||||
|
||||
$columns = $this->dbi->getColumns($this->db, $tableName);
|
||||
$rows = [];
|
||||
foreach ($columns as $row) {
|
||||
$extractedColumnSpec = Util::extractColumnSpec($row['Type']);
|
||||
|
||||
$relation = '';
|
||||
if ($hasRelation) {
|
||||
$foreigner = $this->relation->searchColumnInForeigners($foreigners, $row['Field']);
|
||||
if (is_array($foreigner) && isset($foreigner['foreign_table'], $foreigner['foreign_field'])) {
|
||||
$relation = $foreigner['foreign_table'];
|
||||
$relation .= ' -> ';
|
||||
$relation .= $foreigner['foreign_field'];
|
||||
}
|
||||
}
|
||||
|
||||
$mime = '';
|
||||
if ($relationParameters->browserTransformationFeature !== null) {
|
||||
$mimeMap = $this->transformations->getMime($this->db, $tableName, true);
|
||||
if (is_array($mimeMap) && isset($mimeMap[$row['Field']]['mimetype'])) {
|
||||
$mime = str_replace('_', '/', $mimeMap[$row['Field']]['mimetype']);
|
||||
}
|
||||
}
|
||||
|
||||
$rows[$row['Field']] = [
|
||||
'name' => $row['Field'],
|
||||
'has_primary_key' => isset($primaryKeys[$row['Field']]),
|
||||
'type' => $extractedColumnSpec['type'],
|
||||
'print_type' => $extractedColumnSpec['print_type'],
|
||||
'is_nullable' => $row['Null'] !== '' && $row['Null'] !== 'NO',
|
||||
'default' => $row['Default'] ?? null,
|
||||
'comment' => $columnsComments[$row['Field']] ?? '',
|
||||
'mime' => $mime,
|
||||
'relation' => $relation,
|
||||
];
|
||||
}
|
||||
|
||||
$tables[$tableName] = [
|
||||
'name' => $tableName,
|
||||
'comment' => $showComment,
|
||||
'has_relation' => $hasRelation,
|
||||
'has_mime' => $relationParameters->browserTransformationFeature !== null,
|
||||
'columns' => $rows,
|
||||
'indexes' => Index::getFromTable($tableName, $this->db),
|
||||
];
|
||||
}
|
||||
|
||||
$this->render('database/data_dictionary/index', [
|
||||
'database' => $this->db,
|
||||
'comment' => $comment,
|
||||
'tables' => $tables,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Database\Designer;
|
||||
use PhpMyAdmin\Database\Designer\Common as DesignerCommon;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function htmlspecialchars;
|
||||
use function in_array;
|
||||
use function sprintf;
|
||||
|
||||
class DesignerController extends AbstractController
|
||||
{
|
||||
/** @var Designer */
|
||||
private $databaseDesigner;
|
||||
|
||||
/** @var DesignerCommon */
|
||||
private $designerCommon;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Designer $databaseDesigner,
|
||||
DesignerCommon $designerCommon
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->databaseDesigner = $databaseDesigner;
|
||||
$this->designerCommon = $designerCommon;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $script_display_field, $tab_column, $tables_all_keys, $tables_pk_or_unique_keys;
|
||||
global $success, $page, $message, $display_page, $selected_page, $tab_pos, $fullTableNames, $script_tables;
|
||||
global $script_contr, $params, $tables, $num_tables, $total_num_tables, $sub_part;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos, $classes_side_menu, $cfg, $errorUrl;
|
||||
|
||||
if (isset($_POST['dialog'])) {
|
||||
if ($_POST['dialog'] === 'edit') {
|
||||
$html = $this->databaseDesigner->getHtmlForEditOrDeletePages($_POST['db'], 'editPage');
|
||||
} elseif ($_POST['dialog'] === 'delete') {
|
||||
$html = $this->databaseDesigner->getHtmlForEditOrDeletePages($_POST['db'], 'deletePage');
|
||||
} elseif ($_POST['dialog'] === 'save_as') {
|
||||
$html = $this->databaseDesigner->getHtmlForPageSaveAs($_POST['db']);
|
||||
} elseif ($_POST['dialog'] === 'export') {
|
||||
$html = $this->databaseDesigner->getHtmlForSchemaExport($_POST['db'], $_POST['selected_page']);
|
||||
} elseif ($_POST['dialog'] === 'add_table') {
|
||||
// Pass the db and table to the getTablesInfo so we only have the table we asked for
|
||||
$script_display_field = $this->designerCommon->getTablesInfo($_POST['db'], $_POST['table']);
|
||||
$tab_column = $this->designerCommon->getColumnsInfo($script_display_field);
|
||||
$tables_all_keys = $this->designerCommon->getAllKeys($script_display_field);
|
||||
$tables_pk_or_unique_keys = $this->designerCommon->getPkOrUniqueKeys($script_display_field);
|
||||
|
||||
$html = $this->databaseDesigner->getDatabaseTables(
|
||||
$_POST['db'],
|
||||
$script_display_field,
|
||||
[],
|
||||
-1,
|
||||
$tab_column,
|
||||
$tables_all_keys,
|
||||
$tables_pk_or_unique_keys
|
||||
);
|
||||
}
|
||||
|
||||
if (! empty($html)) {
|
||||
$this->response->addHTML($html);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['operation'])) {
|
||||
if ($_POST['operation'] === 'deletePage') {
|
||||
$success = $this->designerCommon->deletePage($_POST['selected_page']);
|
||||
$this->response->setRequestStatus($success);
|
||||
} elseif ($_POST['operation'] === 'savePage') {
|
||||
if ($_POST['save_page'] === 'same') {
|
||||
$page = $_POST['selected_page'];
|
||||
} elseif ($this->designerCommon->getPageExists($_POST['selected_value'])) {
|
||||
$this->response->addJSON(
|
||||
'message',
|
||||
sprintf(
|
||||
/* l10n: The user tries to save a page with an existing name in Designer */
|
||||
__('There already exists a page named "%s" please rename it to something else.'),
|
||||
htmlspecialchars($_POST['selected_value'])
|
||||
)
|
||||
);
|
||||
$this->response->setRequestStatus(false);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$page = $this->designerCommon->createNewPage($_POST['selected_value'], $_POST['db']);
|
||||
$this->response->addJSON('id', $page);
|
||||
}
|
||||
|
||||
$success = $this->designerCommon->saveTablePositions($page);
|
||||
$this->response->setRequestStatus($success);
|
||||
} elseif ($_POST['operation'] === 'setDisplayField') {
|
||||
[
|
||||
$success,
|
||||
$message,
|
||||
] = $this->designerCommon->saveDisplayField($_POST['db'], $_POST['table'], $_POST['field']);
|
||||
$this->response->setRequestStatus($success);
|
||||
$this->response->addJSON('message', $message);
|
||||
} elseif ($_POST['operation'] === 'addNewRelation') {
|
||||
[$success, $message] = $this->designerCommon->addNewRelation(
|
||||
$_POST['db'],
|
||||
$_POST['T1'],
|
||||
$_POST['F1'],
|
||||
$_POST['T2'],
|
||||
$_POST['F2'],
|
||||
$_POST['on_delete'],
|
||||
$_POST['on_update'],
|
||||
$_POST['DB1'],
|
||||
$_POST['DB2']
|
||||
);
|
||||
$this->response->setRequestStatus($success);
|
||||
$this->response->addJSON('message', $message);
|
||||
} elseif ($_POST['operation'] === 'removeRelation') {
|
||||
[$success, $message] = $this->designerCommon->removeRelation(
|
||||
$_POST['T1'],
|
||||
$_POST['F1'],
|
||||
$_POST['T2'],
|
||||
$_POST['F2']
|
||||
);
|
||||
$this->response->setRequestStatus($success);
|
||||
$this->response->addJSON('message', $message);
|
||||
} elseif ($_POST['operation'] === 'save_setting_value') {
|
||||
$success = $this->designerCommon->saveSetting($_POST['index'], $_POST['value']);
|
||||
$this->response->setRequestStatus($success);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$script_display_field = $this->designerCommon->getTablesInfo();
|
||||
|
||||
$display_page = -1;
|
||||
$selected_page = null;
|
||||
|
||||
$visualBuilderMode = isset($_GET['query']);
|
||||
|
||||
if ($visualBuilderMode) {
|
||||
$display_page = $this->designerCommon->getDefaultPage($_GET['db']);
|
||||
} elseif (! empty($_GET['page'])) {
|
||||
$display_page = $_GET['page'];
|
||||
} else {
|
||||
$display_page = $this->designerCommon->getLoadingPage($_GET['db']);
|
||||
}
|
||||
|
||||
if ($display_page != -1) {
|
||||
$selected_page = $this->designerCommon->getPageName($display_page);
|
||||
}
|
||||
|
||||
$tab_pos = $this->designerCommon->getTablePositions($display_page);
|
||||
|
||||
$fullTableNames = [];
|
||||
|
||||
foreach ($script_display_field as $designerTable) {
|
||||
$fullTableNames[] = $designerTable->getDbTableString();
|
||||
}
|
||||
|
||||
foreach ($tab_pos as $position) {
|
||||
if (in_array($position['dbName'] . '.' . $position['tableName'], $fullTableNames)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$designerTables = $this->designerCommon->getTablesInfo($position['dbName'], $position['tableName']);
|
||||
foreach ($designerTables as $designerTable) {
|
||||
$script_display_field[] = $designerTable;
|
||||
}
|
||||
}
|
||||
|
||||
$tab_column = $this->designerCommon->getColumnsInfo($script_display_field);
|
||||
$script_tables = $this->designerCommon->getScriptTabs($script_display_field);
|
||||
$tables_pk_or_unique_keys = $this->designerCommon->getPkOrUniqueKeys($script_display_field);
|
||||
$tables_all_keys = $this->designerCommon->getAllKeys($script_display_field);
|
||||
$classes_side_menu = $this->databaseDesigner->returnClassNamesFromMenuButtons();
|
||||
|
||||
$script_contr = $this->designerCommon->getScriptContr($script_display_field);
|
||||
|
||||
$params = ['lang' => $GLOBALS['lang']];
|
||||
if (isset($_GET['db'])) {
|
||||
$params['db'] = $_GET['db'];
|
||||
}
|
||||
|
||||
$this->response->getFooter()->setMinimal();
|
||||
$header = $this->response->getHeader();
|
||||
$header->setBodyId('designer_body');
|
||||
|
||||
$this->addScriptFiles([
|
||||
'designer/database.js',
|
||||
'designer/objects.js',
|
||||
'designer/page.js',
|
||||
'designer/history.js',
|
||||
'designer/move.js',
|
||||
'designer/init.js',
|
||||
]);
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part ?? '');
|
||||
|
||||
// Embed some data into HTML, later it will be read
|
||||
// by designer/init.js and converted to JS variables.
|
||||
$this->response->addHTML(
|
||||
$this->databaseDesigner->getHtmlForMain(
|
||||
$db,
|
||||
$_GET['db'],
|
||||
$script_display_field,
|
||||
$script_tables,
|
||||
$script_contr,
|
||||
$script_display_field,
|
||||
$display_page,
|
||||
$visualBuilderMode,
|
||||
$selected_page,
|
||||
$classes_side_menu,
|
||||
$tab_pos,
|
||||
$tab_column,
|
||||
$tables_all_keys,
|
||||
$tables_pk_or_unique_keys
|
||||
)
|
||||
);
|
||||
|
||||
$this->response->addHTML('<div id="PMA_disable_floating_menubar"></div>');
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Database\Events;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function strlen;
|
||||
|
||||
final class EventsController extends AbstractController
|
||||
{
|
||||
/** @var Events */
|
||||
private $events;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Events $events,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->events = $events;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $tables, $num_tables, $total_num_tables, $sub_part, $errors, $text_dir;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos, $cfg, $errorUrl;
|
||||
|
||||
$this->addScriptFiles(['database/events.js']);
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part ?? '');
|
||||
} elseif (strlen($db) > 0) {
|
||||
$this->dbi->selectDb($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep a list of errors that occurred while
|
||||
* processing an 'Add' or 'Edit' operation.
|
||||
*/
|
||||
$errors = [];
|
||||
|
||||
$this->events->handleEditor();
|
||||
$this->events->export();
|
||||
|
||||
$items = $this->dbi->getEvents($db);
|
||||
|
||||
$this->render('database/events/index', [
|
||||
'db' => $db,
|
||||
'items' => $items,
|
||||
'has_privilege' => Util::currentUserHasPrivilege('EVENT', $db),
|
||||
'scheduler_state' => $this->events->getEventSchedulerStatus(),
|
||||
'text_dir' => $text_dir,
|
||||
'is_ajax' => $this->response->isAjax() && empty($_REQUEST['ajax_page_request']),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\Export;
|
||||
use PhpMyAdmin\Export\Options;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_merge;
|
||||
use function is_array;
|
||||
|
||||
final class ExportController extends AbstractController
|
||||
{
|
||||
/** @var Export */
|
||||
private $export;
|
||||
|
||||
/** @var Options */
|
||||
private $exportOptions;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Export $export,
|
||||
Options $exportOptions
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->export = $export;
|
||||
$this->exportOptions = $exportOptions;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $sub_part, $urlParams, $sql_query;
|
||||
global $tables, $num_tables, $total_num_tables, $tooltip_truename;
|
||||
global $tooltip_aliasname, $pos, $table_select, $unlim_num_rows, $cfg, $errorUrl;
|
||||
|
||||
$pageSettings = new PageSettings('Export');
|
||||
$pageSettingsErrorHtml = $pageSettings->getErrorHTML();
|
||||
$pageSettingsHtml = $pageSettings->getHTML();
|
||||
|
||||
$this->addScriptFiles(['export.js']);
|
||||
|
||||
// $sub_part is used in Util::getDbInfo() to see if we are coming from
|
||||
// /database/export, in which case we don't obey $cfg['MaxTableList']
|
||||
$sub_part = '_export';
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urlParams['goto'] = Url::getFromRoute('/database/export');
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part);
|
||||
|
||||
// exit if no tables in db found
|
||||
if ($num_tables < 1) {
|
||||
$this->response->addHTML(
|
||||
Message::error(__('No tables found in database.'))->getDisplay()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! empty($_POST['selected_tbl']) && empty($table_select)) {
|
||||
$table_select = $_POST['selected_tbl'];
|
||||
}
|
||||
|
||||
$tablesForMultiValues = [];
|
||||
|
||||
foreach ($tables as $each_table) {
|
||||
if (isset($_POST['table_select']) && is_array($_POST['table_select'])) {
|
||||
$is_checked = $this->export->getCheckedClause($each_table['Name'], $_POST['table_select']);
|
||||
} elseif (isset($table_select)) {
|
||||
$is_checked = $this->export->getCheckedClause($each_table['Name'], $table_select);
|
||||
} else {
|
||||
$is_checked = true;
|
||||
}
|
||||
|
||||
if (isset($_POST['table_structure']) && is_array($_POST['table_structure'])) {
|
||||
$structure_checked = $this->export->getCheckedClause($each_table['Name'], $_POST['table_structure']);
|
||||
} else {
|
||||
$structure_checked = $is_checked;
|
||||
}
|
||||
|
||||
if (isset($_POST['table_data']) && is_array($_POST['table_data'])) {
|
||||
$data_checked = $this->export->getCheckedClause($each_table['Name'], $_POST['table_data']);
|
||||
} else {
|
||||
$data_checked = $is_checked;
|
||||
}
|
||||
|
||||
$tablesForMultiValues[] = [
|
||||
'name' => $each_table['Name'],
|
||||
'is_checked_select' => $is_checked,
|
||||
'is_checked_structure' => $structure_checked,
|
||||
'is_checked_data' => $data_checked,
|
||||
];
|
||||
}
|
||||
|
||||
if (! isset($sql_query)) {
|
||||
$sql_query = '';
|
||||
}
|
||||
|
||||
if (! isset($unlim_num_rows)) {
|
||||
$unlim_num_rows = 0;
|
||||
}
|
||||
|
||||
$isReturnBackFromRawExport = isset($_POST['export_type']) && $_POST['export_type'] === 'raw';
|
||||
if (isset($_POST['raw_query']) || $isReturnBackFromRawExport) {
|
||||
$export_type = 'raw';
|
||||
} else {
|
||||
$export_type = 'database';
|
||||
}
|
||||
|
||||
$GLOBALS['single_table'] = $_POST['single_table'] ?? $_GET['single_table'] ?? $GLOBALS['single_table'] ?? null;
|
||||
|
||||
$exportList = Plugins::getExport($export_type, isset($GLOBALS['single_table']));
|
||||
|
||||
if (empty($exportList)) {
|
||||
$this->response->addHTML(Message::error(
|
||||
__('Could not load export plugins, please check your installation!')
|
||||
)->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$options = $this->exportOptions->getOptions(
|
||||
$export_type,
|
||||
$db,
|
||||
$table,
|
||||
$sql_query,
|
||||
$num_tables,
|
||||
$unlim_num_rows,
|
||||
$exportList
|
||||
);
|
||||
|
||||
$this->render('database/export/index', array_merge($options, [
|
||||
'page_settings_error_html' => $pageSettingsErrorHtml,
|
||||
'page_settings_html' => $pageSettingsHtml,
|
||||
'structure_or_data_forced' => $_POST['structure_or_data_forced'] ?? 0,
|
||||
'tables' => $tablesForMultiValues,
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\Import;
|
||||
use PhpMyAdmin\Import\Ajax;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
|
||||
use function __;
|
||||
use function intval;
|
||||
use function is_numeric;
|
||||
|
||||
final class ImportController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $tables, $num_tables, $total_num_tables, $cfg;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos, $sub_part, $SESSION_KEY, $errorUrl;
|
||||
|
||||
$pageSettings = new PageSettings('Import');
|
||||
$pageSettingsErrorHtml = $pageSettings->getErrorHTML();
|
||||
$pageSettingsHtml = $pageSettings->getHTML();
|
||||
|
||||
$this->addScriptFiles(['import.js']);
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part ?? '');
|
||||
|
||||
[$SESSION_KEY, $uploadId] = Ajax::uploadProgressSetup();
|
||||
|
||||
$importList = Plugins::getImport('database');
|
||||
|
||||
if (empty($importList)) {
|
||||
$this->response->addHTML(Message::error(__(
|
||||
'Could not load import plugins, please check your installation!'
|
||||
))->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$offset = null;
|
||||
if (isset($_REQUEST['offset']) && is_numeric($_REQUEST['offset'])) {
|
||||
$offset = intval($_REQUEST['offset']);
|
||||
}
|
||||
|
||||
$timeoutPassed = $_REQUEST['timeout_passed'] ?? null;
|
||||
$localImportFile = $_REQUEST['local_import_file'] ?? null;
|
||||
$compressions = Import::getCompressions();
|
||||
|
||||
$charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']);
|
||||
|
||||
$idKey = $_SESSION[$SESSION_KEY]['handler']::getIdKey();
|
||||
$hiddenInputs = [
|
||||
$idKey => $uploadId,
|
||||
'import_type' => 'database',
|
||||
'db' => $db,
|
||||
];
|
||||
|
||||
$default = isset($_GET['format']) ? (string) $_GET['format'] : Plugins::getDefault('Import', 'format');
|
||||
$choice = Plugins::getChoice($importList, $default);
|
||||
$options = Plugins::getOptions('Import', $importList);
|
||||
$skipQueriesDefault = Plugins::getDefault('Import', 'skip_queries');
|
||||
$isAllowInterruptChecked = Plugins::checkboxCheck('Import', 'allow_interrupt');
|
||||
$maxUploadSize = (int) $GLOBALS['config']->get('max_upload_size');
|
||||
|
||||
$this->render('database/import/index', [
|
||||
'page_settings_error_html' => $pageSettingsErrorHtml,
|
||||
'page_settings_html' => $pageSettingsHtml,
|
||||
'upload_id' => $uploadId,
|
||||
'handler' => $_SESSION[$SESSION_KEY]['handler'],
|
||||
'hidden_inputs' => $hiddenInputs,
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'max_upload_size' => $maxUploadSize,
|
||||
'formatted_maximum_upload_size' => Util::getFormattedMaximumUploadSize($maxUploadSize),
|
||||
'plugins_choice' => $choice,
|
||||
'options' => $options,
|
||||
'skip_queries_default' => $skipQueriesDefault,
|
||||
'is_allow_interrupt_checked' => $isAllowInterruptChecked,
|
||||
'local_import_file' => $localImportFile,
|
||||
'is_upload' => $GLOBALS['config']->get('enable_upload'),
|
||||
'upload_dir' => $cfg['UploadDir'] ?? null,
|
||||
'timeout_passed_global' => $GLOBALS['timeout_passed'] ?? null,
|
||||
'compressions' => $compressions,
|
||||
'is_encoding_supported' => Encoding::isSupported(),
|
||||
'encodings' => Encoding::listEncodings(),
|
||||
'import_charset' => $cfg['Import']['charset'] ?? null,
|
||||
'timeout_passed' => $timeoutPassed,
|
||||
'offset' => $offset,
|
||||
'can_convert_kanji' => Encoding::canConvertKanji(),
|
||||
'charsets' => $charsets,
|
||||
'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
|
||||
'user_upload_dir' => Util::userDir((string) ($cfg['UploadDir'] ?? '')),
|
||||
'local_files' => Import::getLocalFiles($importList),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\MultiTableQuery;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Database\MultiTableQuery;
|
||||
|
||||
final class QueryController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
$params = [
|
||||
'sql_query' => $_POST['sql_query'],
|
||||
'db' => $_POST['db'] ?? $_GET['db'] ?? null,
|
||||
];
|
||||
|
||||
$this->response->addHTML(MultiTableQuery::displayResults($params['sql_query'], $params['db']));
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\MultiTableQuery;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Query\Generator as QueryGenerator;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function rtrim;
|
||||
|
||||
final class TablesController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$params = [
|
||||
'tables' => $_GET['tables'] ?? [],
|
||||
'db' => $_GET['db'] ?? '',
|
||||
];
|
||||
|
||||
$tablesListForQuery = '';
|
||||
foreach ($params['tables'] as $table) {
|
||||
$tablesListForQuery .= "'" . $this->dbi->escapeString($table) . "',";
|
||||
}
|
||||
|
||||
$tablesListForQuery = rtrim($tablesListForQuery, ',');
|
||||
|
||||
$constrains = $this->dbi->fetchResult(
|
||||
QueryGenerator::getInformationSchemaForeignKeyConstraintsRequest(
|
||||
$this->dbi->escapeString($params['db']),
|
||||
$tablesListForQuery
|
||||
)
|
||||
);
|
||||
$this->response->addJSON(['foreignKeyConstrains' => $constrains]);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Database\MultiTableQuery;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Handles database multi-table querying
|
||||
*/
|
||||
class MultiTableQueryController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$this->addScriptFiles([
|
||||
'database/multi_table_query.js',
|
||||
'database/query_generator.js',
|
||||
]);
|
||||
|
||||
$queryInstance = new MultiTableQuery($this->dbi, $this->template, $this->db);
|
||||
|
||||
$this->response->addHTML($queryInstance->getFormHtml());
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Operations;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Operations;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
|
||||
final class CollationController extends AbstractController
|
||||
{
|
||||
/** @var Operations */
|
||||
private $operations;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Operations $operations,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->operations = $operations;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $cfg, $errorUrl;
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($_POST['db_collation'])) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', Message::error(__('No collation provided.')));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sql_query = 'ALTER DATABASE ' . Util::backquote($db)
|
||||
. ' DEFAULT' . Util::getCharsetQueryPart($_POST['db_collation'] ?? '');
|
||||
$this->dbi->query($sql_query);
|
||||
$message = Message::success();
|
||||
|
||||
/**
|
||||
* Changes tables charset if requested by the user
|
||||
*/
|
||||
if (isset($_POST['change_all_tables_collations']) && $_POST['change_all_tables_collations'] === 'on') {
|
||||
[$tables] = Util::getDbInfo($db, '');
|
||||
foreach ($tables as $tableName => $data) {
|
||||
if ($this->dbi->getTable($db, $tableName)->isView()) {
|
||||
// Skip views, we can not change the collation of a view.
|
||||
// issue #15283
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql_query = 'ALTER TABLE '
|
||||
. Util::backquote($db)
|
||||
. '.'
|
||||
. Util::backquote($tableName)
|
||||
. ' DEFAULT '
|
||||
. Util::getCharsetQueryPart($_POST['db_collation'] ?? '');
|
||||
$this->dbi->query($sql_query);
|
||||
|
||||
/**
|
||||
* Changes columns charset if requested by the user
|
||||
*/
|
||||
if (
|
||||
! isset($_POST['change_all_tables_columns_collations']) ||
|
||||
$_POST['change_all_tables_columns_collations'] !== 'on'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->operations->changeAllColumnsCollation($db, $tableName, $_POST['db_collation']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON('message', $message);
|
||||
}
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Operations;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Plugins\Export\ExportSql;
|
||||
use PhpMyAdmin\Query\Utilities;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function mb_strtolower;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* Handles miscellaneous database operations.
|
||||
*/
|
||||
class OperationsController extends AbstractController
|
||||
{
|
||||
/** @var Operations */
|
||||
private $operations;
|
||||
|
||||
/** @var CheckUserPrivileges */
|
||||
private $checkUserPrivileges;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var RelationCleanup */
|
||||
private $relationCleanup;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Operations $operations,
|
||||
CheckUserPrivileges $checkUserPrivileges,
|
||||
Relation $relation,
|
||||
RelationCleanup $relationCleanup,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->operations = $operations;
|
||||
$this->checkUserPrivileges = $checkUserPrivileges;
|
||||
$this->relation = $relation;
|
||||
$this->relationCleanup = $relationCleanup;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $server, $sql_query, $move, $message, $tables_full, $errorUrl;
|
||||
global $export_sql_plugin, $views, $sqlConstratints, $local_query, $reload, $urlParams, $tables;
|
||||
global $total_num_tables, $sub_part, $tooltip_truename;
|
||||
global $db_collation, $tooltip_aliasname, $pos, $is_information_schema, $single_table, $num_tables;
|
||||
|
||||
$this->checkUserPrivileges->getPrivileges();
|
||||
|
||||
$this->addScriptFiles(['database/operations.js']);
|
||||
|
||||
$sql_query = '';
|
||||
|
||||
/**
|
||||
* Rename/move or copy database
|
||||
*/
|
||||
if (strlen($db) > 0 && (! empty($_POST['db_rename']) || ! empty($_POST['db_copy']))) {
|
||||
if (! empty($_POST['db_rename'])) {
|
||||
$move = true;
|
||||
} else {
|
||||
$move = false;
|
||||
}
|
||||
|
||||
if (! isset($_POST['newname']) || strlen($_POST['newname']) === 0) {
|
||||
$message = Message::error(__('The database name is empty!'));
|
||||
} else {
|
||||
// lower_case_table_names=1 `DB` becomes `db`
|
||||
if ($this->dbi->getLowerCaseNames() === '1') {
|
||||
$_POST['newname'] = mb_strtolower($_POST['newname']);
|
||||
}
|
||||
|
||||
if ($_POST['newname'] === $_REQUEST['db']) {
|
||||
$message = Message::error(
|
||||
__('Cannot copy database to the same name. Change the name and try again.')
|
||||
);
|
||||
} else {
|
||||
$_error = false;
|
||||
if ($move || ! empty($_POST['create_database_before_copying'])) {
|
||||
$this->operations->createDbBeforeCopy();
|
||||
}
|
||||
|
||||
// here I don't use DELIMITER because it's not part of the
|
||||
// language; I have to send each statement one by one
|
||||
|
||||
// to avoid selecting alternatively the current and new db
|
||||
// we would need to modify the CREATE definitions to qualify
|
||||
// the db name
|
||||
$this->operations->runProcedureAndFunctionDefinitions($db);
|
||||
|
||||
// go back to current db, just in case
|
||||
$this->dbi->selectDb($db);
|
||||
|
||||
$tables_full = $this->dbi->getTablesFull($db);
|
||||
|
||||
// remove all foreign key constraints, otherwise we can get errors
|
||||
/** @var ExportSql $export_sql_plugin */
|
||||
$export_sql_plugin = Plugins::getPlugin('export', 'sql', [
|
||||
'export_type' => 'database',
|
||||
'single_table' => isset($single_table),
|
||||
]);
|
||||
|
||||
// create stand-in tables for views
|
||||
$views = $this->operations->getViewsAndCreateSqlViewStandIn($tables_full, $export_sql_plugin, $db);
|
||||
|
||||
// copy tables
|
||||
$sqlConstratints = $this->operations->copyTables($tables_full, $move, $db);
|
||||
|
||||
// handle the views
|
||||
if (! $_error) {
|
||||
$this->operations->handleTheViews($views, $move, $db);
|
||||
}
|
||||
|
||||
unset($views);
|
||||
|
||||
// now that all tables exist, create all the accumulated constraints
|
||||
if (! $_error && count($sqlConstratints) > 0) {
|
||||
$this->operations->createAllAccumulatedConstraints($sqlConstratints);
|
||||
}
|
||||
|
||||
unset($sqlConstratints);
|
||||
|
||||
if ($this->dbi->getVersion() >= 50100) {
|
||||
// here DELIMITER is not used because it's not part of the
|
||||
// language; each statement is sent one by one
|
||||
|
||||
$this->operations->runEventDefinitionsForDb($db);
|
||||
}
|
||||
|
||||
// go back to current db, just in case
|
||||
$this->dbi->selectDb($db);
|
||||
|
||||
// Duplicate the bookmarks for this db (done once for each db)
|
||||
$this->operations->duplicateBookmarks($_error, $db);
|
||||
|
||||
if (! $_error && $move) {
|
||||
if (isset($_POST['adjust_privileges']) && ! empty($_POST['adjust_privileges'])) {
|
||||
$this->operations->adjustPrivilegesMoveDb($db, $_POST['newname']);
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup pmadb stuff for this db
|
||||
*/
|
||||
$this->relationCleanup->database($db);
|
||||
|
||||
// if someday the RENAME DATABASE reappears, do not DROP
|
||||
$local_query = 'DROP DATABASE '
|
||||
. Util::backquote($db) . ';';
|
||||
$sql_query .= "\n" . $local_query;
|
||||
$this->dbi->query($local_query);
|
||||
|
||||
$message = Message::success(
|
||||
__('Database %1$s has been renamed to %2$s.')
|
||||
);
|
||||
$message->addParam($db);
|
||||
$message->addParam($_POST['newname']);
|
||||
} elseif (! $_error) {
|
||||
if (isset($_POST['adjust_privileges']) && ! empty($_POST['adjust_privileges'])) {
|
||||
$this->operations->adjustPrivilegesCopyDb($db, $_POST['newname']);
|
||||
}
|
||||
|
||||
$message = Message::success(
|
||||
__('Database %1$s has been copied to %2$s.')
|
||||
);
|
||||
$message->addParam($db);
|
||||
$message->addParam($_POST['newname']);
|
||||
} else {
|
||||
$message = Message::error();
|
||||
}
|
||||
|
||||
$reload = true;
|
||||
|
||||
/* Change database to be used */
|
||||
if (! $_error && $move) {
|
||||
$db = $_POST['newname'];
|
||||
} elseif (! $_error) {
|
||||
if (isset($_POST['switch_to_new']) && $_POST['switch_to_new'] === 'true') {
|
||||
$_SESSION['pma_switch_to_new'] = true;
|
||||
$db = $_POST['newname'];
|
||||
} else {
|
||||
$_SESSION['pma_switch_to_new'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Database has been successfully renamed/moved. If in an Ajax request,
|
||||
* generate the output with {@link ResponseRenderer} and exit
|
||||
*/
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON('message', $message);
|
||||
$this->response->addJSON('newname', $_POST['newname']);
|
||||
$this->response->addJSON(
|
||||
'sql_query',
|
||||
Generator::getMessage('', $sql_query)
|
||||
);
|
||||
$this->response->addJSON('db', $db);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
/**
|
||||
* Check if comments were updated
|
||||
* (must be done before displaying the menu tabs)
|
||||
*/
|
||||
if (isset($_POST['comment'])) {
|
||||
$this->relation->setDbComment($db, $_POST['comment']);
|
||||
}
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urlParams['goto'] = Url::getFromRoute('/database/operations');
|
||||
|
||||
// Gets the database structure
|
||||
$sub_part = '_structure';
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,
|
||||
$isSystemSchema,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part);
|
||||
|
||||
$oldMessage = '';
|
||||
if (isset($message)) {
|
||||
$oldMessage = Generator::getMessage($message, $sql_query);
|
||||
unset($message);
|
||||
}
|
||||
|
||||
$db_collation = $this->dbi->getDbCollation($db);
|
||||
$is_information_schema = Utilities::isSystemSchema($db);
|
||||
|
||||
if ($is_information_schema) {
|
||||
return;
|
||||
}
|
||||
|
||||
$databaseComment = '';
|
||||
if ($relationParameters->columnCommentsFeature !== null) {
|
||||
$databaseComment = $this->relation->getDbComment($db);
|
||||
}
|
||||
|
||||
$hasAdjustPrivileges = $GLOBALS['db_priv'] && $GLOBALS['table_priv']
|
||||
&& $GLOBALS['col_priv'] && $GLOBALS['proc_priv'] && $GLOBALS['is_reload_priv'];
|
||||
|
||||
$isDropDatabaseAllowed = ($this->dbi->isSuperUser() || $cfg['AllowUserDropDatabase'])
|
||||
&& ! $isSystemSchema && $db !== 'mysql';
|
||||
|
||||
$switchToNew = isset($_SESSION['pma_switch_to_new']) && $_SESSION['pma_switch_to_new'];
|
||||
|
||||
$charsets = Charsets::getCharsets($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']);
|
||||
$collations = Charsets::getCollations($this->dbi, $GLOBALS['cfg']['Server']['DisableIS']);
|
||||
|
||||
if (! $relationParameters->hasAllFeatures() && $cfg['PmaNoRelation_DisableWarning'] == false) {
|
||||
$message = Message::notice(
|
||||
__(
|
||||
'The phpMyAdmin configuration storage has been deactivated. %sFind out why%s.'
|
||||
)
|
||||
);
|
||||
$message->addParamHtml(
|
||||
'<a href="' . Url::getFromRoute('/check-relations')
|
||||
. '" data-post="' . Url::getCommon(['db' => $db]) . '">'
|
||||
);
|
||||
$message->addParamHtml('</a>');
|
||||
/* Show error if user has configured something, notice elsewhere */
|
||||
if (! empty($cfg['Servers'][$server]['pmadb'])) {
|
||||
$message->isError(true);
|
||||
}
|
||||
}
|
||||
|
||||
$this->render('database/operations/index', [
|
||||
'message' => $oldMessage,
|
||||
'db' => $db,
|
||||
'has_comment' => $relationParameters->columnCommentsFeature !== null,
|
||||
'db_comment' => $databaseComment,
|
||||
'db_collation' => $db_collation,
|
||||
'has_adjust_privileges' => $hasAdjustPrivileges,
|
||||
'is_drop_database_allowed' => $isDropDatabaseAllowed,
|
||||
'switch_to_new' => $switchToNew,
|
||||
'charsets' => $charsets,
|
||||
'collations' => $collations,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Controller for database privileges
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Privileges;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function mb_strtolower;
|
||||
|
||||
/**
|
||||
* Controller for database privileges
|
||||
*/
|
||||
class PrivilegesController extends AbstractController
|
||||
{
|
||||
/** @var Privileges */
|
||||
private $privileges;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Privileges $privileges,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->privileges = $privileges;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $params Request parameters
|
||||
* @psalm-param array{checkprivsdb: string} $params
|
||||
*/
|
||||
public function __invoke(array $params): string
|
||||
{
|
||||
global $cfg, $text_dir;
|
||||
|
||||
$scriptName = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
|
||||
$db = $params['checkprivsdb'];
|
||||
if ($this->dbi->getLowerCaseNames() === '1') {
|
||||
$db = mb_strtolower($params['checkprivsdb']);
|
||||
}
|
||||
|
||||
$privileges = [];
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$privileges = $this->privileges->getAllPrivileges($db);
|
||||
}
|
||||
|
||||
return $this->template->render('database/privileges/index', [
|
||||
'is_superuser' => $this->dbi->isSuperUser(),
|
||||
'db' => $db,
|
||||
'database_url' => $scriptName,
|
||||
'text_dir' => $text_dir,
|
||||
'is_createuser' => $this->dbi->isCreateUser(),
|
||||
'is_grantuser' => $this->dbi->isGrantUser(),
|
||||
'privileges' => $privileges,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\Database\Qbe;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Operations;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\SavedSearches;
|
||||
use PhpMyAdmin\Sql;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Transformations;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function stripos;
|
||||
|
||||
class QueryByExampleController extends AbstractController
|
||||
{
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Relation $relation,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->relation = $relation;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $savedSearchList, $savedSearch, $currentSearchId;
|
||||
global $sql_query, $goto, $sub_part, $tables, $num_tables, $total_num_tables;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos, $urlParams, $cfg, $errorUrl;
|
||||
|
||||
$savedQbeSearchesFeature = $this->relation->getRelationParameters()->savedQueryByExampleSearchesFeature;
|
||||
|
||||
$savedSearchList = [];
|
||||
$savedSearch = null;
|
||||
$currentSearchId = null;
|
||||
$this->addScriptFiles(['database/qbe.js']);
|
||||
if ($savedQbeSearchesFeature !== null) {
|
||||
//Get saved search list.
|
||||
$savedSearch = new SavedSearches();
|
||||
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
|
||||
->setDbname($db);
|
||||
|
||||
if (! empty($_POST['searchId'])) {
|
||||
$savedSearch->setId($_POST['searchId']);
|
||||
}
|
||||
|
||||
//Action field is sent.
|
||||
if (isset($_POST['action'])) {
|
||||
$savedSearch->setSearchName($_POST['searchName']);
|
||||
if ($_POST['action'] === 'create') {
|
||||
$savedSearch->setId(null)
|
||||
->setCriterias($_POST)
|
||||
->save($savedQbeSearchesFeature);
|
||||
} elseif ($_POST['action'] === 'update') {
|
||||
$savedSearch->setCriterias($_POST)
|
||||
->save($savedQbeSearchesFeature);
|
||||
} elseif ($_POST['action'] === 'delete') {
|
||||
$savedSearch->delete($savedQbeSearchesFeature);
|
||||
//After deletion, reset search.
|
||||
$savedSearch = new SavedSearches();
|
||||
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
|
||||
->setDbname($db);
|
||||
$_POST = [];
|
||||
} elseif ($_POST['action'] === 'load') {
|
||||
if (empty($_POST['searchId'])) {
|
||||
//when not loading a search, reset the object.
|
||||
$savedSearch = new SavedSearches();
|
||||
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
|
||||
->setDbname($db);
|
||||
$_POST = [];
|
||||
} else {
|
||||
$savedSearch->load($savedQbeSearchesFeature);
|
||||
}
|
||||
}
|
||||
//Else, it's an "update query"
|
||||
}
|
||||
|
||||
$savedSearchList = $savedSearch->getList($savedQbeSearchesFeature);
|
||||
$currentSearchId = $savedSearch->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* A query has been submitted -> (maybe) execute it
|
||||
*/
|
||||
$hasMessageToDisplay = false;
|
||||
if (isset($_POST['submit_sql']) && ! empty($sql_query)) {
|
||||
if (stripos($sql_query, 'SELECT') !== 0) {
|
||||
$hasMessageToDisplay = true;
|
||||
} else {
|
||||
$goto = Url::getFromRoute('/database/sql');
|
||||
|
||||
$sql = new Sql(
|
||||
$this->dbi,
|
||||
$this->relation,
|
||||
new RelationCleanup($this->dbi, $this->relation),
|
||||
new Operations($this->dbi, $this->relation),
|
||||
new Transformations(),
|
||||
$this->template
|
||||
);
|
||||
|
||||
$this->response->addHTML($sql->executeQueryAndSendQueryResponse(
|
||||
null, // analyzed_sql_results
|
||||
false, // is_gotofile
|
||||
$_POST['db'], // db
|
||||
null, // table
|
||||
false, // find_real_end
|
||||
null, // sql_query_for_bookmark
|
||||
null, // extra_data
|
||||
null, // message_to_show
|
||||
null, // sql_data
|
||||
$goto, // goto
|
||||
null, // disp_query
|
||||
null, // disp_message
|
||||
$sql_query, // sql_query
|
||||
null // complete_query
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$sub_part = '_qbe';
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urlParams['goto'] = Url::getFromRoute('/database/qbe');
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part);
|
||||
|
||||
$databaseQbe = new Qbe($this->relation, $this->template, $this->dbi, $db, $savedSearchList, $savedSearch);
|
||||
|
||||
$this->render('database/qbe/index', [
|
||||
'url_params' => $urlParams,
|
||||
'has_message_to_display' => $hasMessageToDisplay,
|
||||
'selection_form_html' => $databaseQbe->getSelectionForm(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\Database\Routines;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\DbTableExists;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function in_array;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* Routines management.
|
||||
*/
|
||||
class RoutinesController extends AbstractController
|
||||
{
|
||||
/** @var CheckUserPrivileges */
|
||||
private $checkUserPrivileges;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
CheckUserPrivileges $checkUserPrivileges,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->checkUserPrivileges = $checkUserPrivileges;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $tables, $num_tables, $total_num_tables, $sub_part;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos;
|
||||
global $errors, $errorUrl, $urlParams, $cfg;
|
||||
|
||||
$this->addScriptFiles(['database/routines.js']);
|
||||
|
||||
$type = $_REQUEST['type'] ?? null;
|
||||
|
||||
$this->checkUserPrivileges->getPrivileges();
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
/**
|
||||
* Displays the header and tabs
|
||||
*/
|
||||
if (! empty($table) && in_array($table, $this->dbi->getTables($db))) {
|
||||
Util::checkParameters(['db', 'table']);
|
||||
|
||||
$urlParams = ['db' => $db, 'table' => $table];
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table');
|
||||
$errorUrl .= Url::getCommon($urlParams, '&');
|
||||
|
||||
DbTableExists::check();
|
||||
} else {
|
||||
$table = '';
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part ?? '');
|
||||
}
|
||||
} elseif (strlen($db) > 0) {
|
||||
$this->dbi->selectDb($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep a list of errors that occurred while
|
||||
* processing an 'Add' or 'Edit' operation.
|
||||
*/
|
||||
$errors = [];
|
||||
|
||||
$routines = new Routines($this->dbi, $this->template, $this->response);
|
||||
|
||||
$routines->handleEditor();
|
||||
$routines->handleExecute();
|
||||
$routines->export();
|
||||
|
||||
if (! isset($type) || ! in_array($type, ['FUNCTION', 'PROCEDURE'])) {
|
||||
$type = null;
|
||||
}
|
||||
|
||||
$items = $this->dbi->getRoutines($db, $type);
|
||||
$isAjax = $this->response->isAjax() && empty($_REQUEST['ajax_page_request']);
|
||||
|
||||
$rows = '';
|
||||
foreach ($items as $item) {
|
||||
$rows .= $routines->getRow($item, $isAjax ? 'ajaxInsert hide' : '');
|
||||
}
|
||||
|
||||
$this->render('database/routines/index', [
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'items' => $items,
|
||||
'rows' => $rows,
|
||||
'has_privilege' => Util::currentUserHasPrivilege('CREATE ROUTINE', $db, $table),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Database\Search;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
|
||||
class SearchController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $errorUrl, $urlParams, $tables, $num_tables, $total_num_tables, $sub_part;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos;
|
||||
|
||||
$this->addScriptFiles(['database/search.js', 'sql.js', 'makegrid.js']);
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If config variable $cfg['UseDbSearch'] is on false : exit.
|
||||
if (! $cfg['UseDbSearch']) {
|
||||
Generator::mysqlDie(
|
||||
__('Access denied!'),
|
||||
'',
|
||||
false,
|
||||
$errorUrl
|
||||
);
|
||||
}
|
||||
|
||||
$urlParams['goto'] = Url::getFromRoute('/database/search');
|
||||
|
||||
// Create a database search instance
|
||||
$databaseSearch = new Search($this->dbi, $db, $this->template);
|
||||
|
||||
// Display top links if we are not in an Ajax request
|
||||
if (! $this->response->isAjax()) {
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part ?? '');
|
||||
}
|
||||
|
||||
// Main search form has been submitted, get results
|
||||
if (isset($_POST['submit_search'])) {
|
||||
$this->response->addHTML($databaseSearch->getSearchResults());
|
||||
}
|
||||
|
||||
// If we are in an Ajax request, we need to exit after displaying all the HTML
|
||||
if ($this->response->isAjax() && empty($_REQUEST['ajax_page_request'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Display the search form
|
||||
$this->response->addHTML($databaseSearch->getMainHtml());
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function json_encode;
|
||||
|
||||
/**
|
||||
* Table/Column autocomplete in SQL editors.
|
||||
*/
|
||||
class SqlAutoCompleteController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $sql_autocomplete;
|
||||
|
||||
$sql_autocomplete = true;
|
||||
if ($cfg['EnableAutocompleteForTablesAndColumns']) {
|
||||
$db = $_POST['db'] ?? $db;
|
||||
$sql_autocomplete = [];
|
||||
if ($db) {
|
||||
$tableNames = $this->dbi->getTables($db);
|
||||
foreach ($tableNames as $tableName) {
|
||||
$sql_autocomplete[$tableName] = $this->dbi->getColumns($db, $tableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->addJSON(['tables' => json_encode($sql_autocomplete)]);
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\SqlQueryForm;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function htmlspecialchars;
|
||||
|
||||
/**
|
||||
* Database SQL executor
|
||||
*/
|
||||
class SqlController extends AbstractController
|
||||
{
|
||||
/** @var SqlQueryForm */
|
||||
private $sqlQueryForm;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, SqlQueryForm $sqlQueryForm)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->sqlQueryForm = $sqlQueryForm;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $goto, $back, $db, $cfg, $errorUrl;
|
||||
|
||||
$this->addScriptFiles(['makegrid.js', 'vendor/jquery/jquery.uitablefilter.js', 'sql.js']);
|
||||
|
||||
$pageSettings = new PageSettings('Sql');
|
||||
$this->response->addHTML($pageSettings->getErrorHTML());
|
||||
$this->response->addHTML($pageSettings->getHTML());
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* After a syntax error, we return to this script
|
||||
* with the typed query in the textarea.
|
||||
*/
|
||||
$goto = Url::getFromRoute('/database/sql');
|
||||
$back = $goto;
|
||||
|
||||
$this->response->addHTML($this->sqlQueryForm->getHtml(
|
||||
$db,
|
||||
'',
|
||||
true,
|
||||
false,
|
||||
isset($_POST['delimiter'])
|
||||
? htmlspecialchars($_POST['delimiter'])
|
||||
: ';'
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\SqlParser\Utils\Formatter;
|
||||
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* Format SQL for SQL editors.
|
||||
*/
|
||||
class SqlFormatController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
$params = ['sql' => $_POST['sql'] ?? null];
|
||||
$query = strlen((string) $params['sql']) > 0 ? $params['sql'] : '';
|
||||
$this->response->addJSON(['sql' => Formatter::format($query)]);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
|
||||
use function __;
|
||||
|
||||
final class AddPrefixController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$params = ['db' => $db];
|
||||
foreach ($selected as $selectedValue) {
|
||||
$params['selected'][] = $selectedValue;
|
||||
}
|
||||
|
||||
$this->response->disable();
|
||||
$this->render('database/structure/add_prefix', ['url_params' => $params]);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function count;
|
||||
|
||||
final class AddPrefixTableController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $message, $sql_query;
|
||||
|
||||
$selected = $_POST['selected'] ?? [];
|
||||
|
||||
$sql_query = '';
|
||||
$selectedCount = count($selected);
|
||||
|
||||
for ($i = 0; $i < $selectedCount; $i++) {
|
||||
$newTableName = $_POST['add_prefix'] . $selected[$i];
|
||||
$aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i])
|
||||
. ' RENAME ' . Util::backquote($newTableName);
|
||||
|
||||
$sql_query .= $aQuery . ';' . "\n";
|
||||
$this->dbi->selectDb($db);
|
||||
$this->dbi->query($aQuery);
|
||||
}
|
||||
|
||||
$message = Message::success();
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = $message;
|
||||
}
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\Database\CentralColumns;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
|
||||
final class AddController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $message;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$centralColumns = new CentralColumns($this->dbi);
|
||||
$error = $centralColumns->syncUniqueColumns($selected);
|
||||
|
||||
$message = $error instanceof Message ? $error : Message::success(__('Success!'));
|
||||
|
||||
unset($_POST['submit_mult']);
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\Database\CentralColumns;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
|
||||
final class MakeConsistentController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $message;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$centralColumns = new CentralColumns($this->dbi);
|
||||
$error = $centralColumns->makeConsistentWithList($db, $selected);
|
||||
|
||||
$message = $error instanceof Message ? $error : Message::success(__('Success!'));
|
||||
|
||||
unset($_POST['submit_mult']);
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure\CentralColumns;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\Database\CentralColumns;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
|
||||
final class RemoveController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $message;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$centralColumns = new CentralColumns($this->dbi);
|
||||
$error = $centralColumns->deleteColumnsFromList($_POST['db'], $selected);
|
||||
|
||||
$message = $error instanceof Message ? $error : Message::success(__('Success!'));
|
||||
|
||||
unset($_POST['submit_mult']);
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
|
||||
use function __;
|
||||
|
||||
final class ChangePrefixFormController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
$submitMult = $_POST['submit_mult'] ?? '';
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$route = '/database/structure/replace-prefix';
|
||||
if ($submitMult === 'copy_tbl_change_prefix') {
|
||||
$route = '/database/structure/copy-table-with-prefix';
|
||||
}
|
||||
|
||||
$urlParams = ['db' => $db];
|
||||
foreach ($selected as $selectedValue) {
|
||||
$urlParams['selected'][] = $selectedValue;
|
||||
}
|
||||
|
||||
$this->response->disable();
|
||||
$this->render('database/structure/change_prefix_form', [
|
||||
'route' => $route,
|
||||
'url_params' => $urlParams,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
|
||||
use function __;
|
||||
|
||||
final class CopyFormController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $dblist;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$urlParams = ['db' => $db];
|
||||
foreach ($selected as $selectedValue) {
|
||||
$urlParams['selected'][] = $selectedValue;
|
||||
}
|
||||
|
||||
$databasesList = $dblist->databases;
|
||||
foreach ($databasesList as $key => $databaseName) {
|
||||
if ($databaseName == $db) {
|
||||
$databasesList->offsetUnset($key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->disable();
|
||||
$this->render('database/structure/copy_form', [
|
||||
'url_params' => $urlParams,
|
||||
'options' => $databasesList->getList(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Operations;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function count;
|
||||
|
||||
final class CopyTableController extends AbstractController
|
||||
{
|
||||
/** @var Operations */
|
||||
private $operations;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Operations $operations,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->operations = $operations;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $message;
|
||||
|
||||
$selected = $_POST['selected'] ?? [];
|
||||
$targetDb = $_POST['target_db'] ?? null;
|
||||
$selectedCount = count($selected);
|
||||
|
||||
for ($i = 0; $i < $selectedCount; $i++) {
|
||||
Table::moveCopy(
|
||||
$db,
|
||||
$selected[$i],
|
||||
$targetDb,
|
||||
$selected[$i],
|
||||
$_POST['what'],
|
||||
false,
|
||||
'one_table',
|
||||
isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true'
|
||||
);
|
||||
|
||||
if (empty($_POST['adjust_privileges'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->operations->adjustPrivilegesCopyTable($db, $selected[$i], $targetDb, $selected[$i]);
|
||||
}
|
||||
|
||||
$message = Message::success();
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = $message;
|
||||
}
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Table;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function count;
|
||||
use function mb_strlen;
|
||||
use function mb_substr;
|
||||
|
||||
final class CopyTableWithPrefixController extends AbstractController
|
||||
{
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $message;
|
||||
|
||||
$selected = $_POST['selected'] ?? [];
|
||||
$fromPrefix = $_POST['from_prefix'] ?? null;
|
||||
$toPrefix = $_POST['to_prefix'] ?? null;
|
||||
|
||||
$selectedCount = count($selected);
|
||||
|
||||
for ($i = 0; $i < $selectedCount; $i++) {
|
||||
$current = $selected[$i];
|
||||
$newTableName = $toPrefix . mb_substr($current, mb_strlen((string) $fromPrefix));
|
||||
|
||||
Table::moveCopy(
|
||||
$db,
|
||||
$current,
|
||||
$db,
|
||||
$newTableName,
|
||||
'data',
|
||||
false,
|
||||
'one_table',
|
||||
isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true'
|
||||
);
|
||||
}
|
||||
|
||||
$message = Message::success();
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = $message;
|
||||
}
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
|
||||
use function __;
|
||||
use function htmlspecialchars;
|
||||
use function in_array;
|
||||
|
||||
final class DropFormController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$views = $this->dbi->getVirtualTables($db);
|
||||
|
||||
$fullQueryViews = '';
|
||||
$fullQuery = '';
|
||||
|
||||
foreach ($selected as $selectedValue) {
|
||||
$current = $selectedValue;
|
||||
if (! empty($views) && in_array($current, $views)) {
|
||||
$fullQueryViews .= (empty($fullQueryViews) ? 'DROP VIEW ' : ', ')
|
||||
. Util::backquote(htmlspecialchars($current));
|
||||
} else {
|
||||
$fullQuery .= (empty($fullQuery) ? 'DROP TABLE ' : ', ')
|
||||
. Util::backquote(htmlspecialchars($current));
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($fullQuery)) {
|
||||
$fullQuery .= ';<br>' . "\n";
|
||||
}
|
||||
|
||||
if (! empty($fullQueryViews)) {
|
||||
$fullQuery .= $fullQueryViews . ';<br>' . "\n";
|
||||
}
|
||||
|
||||
$urlParams = ['db' => $db];
|
||||
foreach ($selected as $selectedValue) {
|
||||
$urlParams['selected'][] = $selectedValue;
|
||||
}
|
||||
|
||||
foreach ($views as $current) {
|
||||
$urlParams['views'][] = $current;
|
||||
}
|
||||
|
||||
$this->render('database/structure/drop_form', [
|
||||
'url_params' => $urlParams,
|
||||
'full_query' => $fullQuery,
|
||||
'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function in_array;
|
||||
|
||||
final class DropTableController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var RelationCleanup */
|
||||
private $relationCleanup;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
RelationCleanup $relationCleanup,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->relationCleanup = $relationCleanup;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $message, $reload, $sql_query;
|
||||
|
||||
$reload = $_POST['reload'] ?? $reload ?? null;
|
||||
$multBtn = $_POST['mult_btn'] ?? '';
|
||||
$selected = $_POST['selected'] ?? [];
|
||||
|
||||
$views = $this->dbi->getVirtualTables($db);
|
||||
|
||||
if ($multBtn !== __('Yes')) {
|
||||
$message = Message::success(__('No change'));
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = Message::success();
|
||||
}
|
||||
|
||||
unset($_POST['mult_btn']);
|
||||
|
||||
($this->structureController)();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$defaultFkCheckValue = ForeignKey::handleDisableCheckInit();
|
||||
$sql_query = '';
|
||||
$sqlQueryViews = '';
|
||||
$selectedCount = count($selected);
|
||||
|
||||
for ($i = 0; $i < $selectedCount; $i++) {
|
||||
$this->relationCleanup->table($db, $selected[$i]);
|
||||
$current = $selected[$i];
|
||||
|
||||
if (! empty($views) && in_array($current, $views)) {
|
||||
$sqlQueryViews .= (empty($sqlQueryViews) ? 'DROP VIEW ' : ', ') . Util::backquote($current);
|
||||
} else {
|
||||
$sql_query .= (empty($sql_query) ? 'DROP TABLE ' : ', ') . Util::backquote($current);
|
||||
}
|
||||
|
||||
$reload = 1;
|
||||
}
|
||||
|
||||
if (! empty($sql_query)) {
|
||||
$sql_query .= ';';
|
||||
} elseif (! empty($sqlQueryViews)) {
|
||||
$sql_query = $sqlQueryViews . ';';
|
||||
unset($sqlQueryViews);
|
||||
}
|
||||
|
||||
// Unset cache values for tables count, issue #14205
|
||||
if (isset($_SESSION['tmpval'])) {
|
||||
if (isset($_SESSION['tmpval']['table_limit_offset'])) {
|
||||
unset($_SESSION['tmpval']['table_limit_offset']);
|
||||
}
|
||||
|
||||
if (isset($_SESSION['tmpval']['table_limit_offset_db'])) {
|
||||
unset($_SESSION['tmpval']['table_limit_offset_db']);
|
||||
}
|
||||
}
|
||||
|
||||
$message = Message::success();
|
||||
|
||||
$this->dbi->selectDb($db);
|
||||
$result = $this->dbi->tryQuery($sql_query);
|
||||
|
||||
if (! $result) {
|
||||
$message = Message::error($this->dbi->getError());
|
||||
}
|
||||
|
||||
if ($result && ! empty($sqlQueryViews)) {
|
||||
$sql_query .= ' ' . $sqlQueryViews . ';';
|
||||
$result = $this->dbi->tryQuery($sqlQueryViews);
|
||||
unset($sqlQueryViews);
|
||||
}
|
||||
|
||||
if (! $result) {
|
||||
$message = Message::error($this->dbi->getError());
|
||||
}
|
||||
|
||||
ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue);
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = $message;
|
||||
}
|
||||
|
||||
unset($_POST['mult_btn']);
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
|
||||
use function __;
|
||||
use function htmlspecialchars;
|
||||
|
||||
final class EmptyFormController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db;
|
||||
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$fullQuery = '';
|
||||
$urlParams = ['db' => $db];
|
||||
|
||||
foreach ($selected as $selectedValue) {
|
||||
$fullQuery .= 'TRUNCATE ';
|
||||
$fullQuery .= Util::backquote(htmlspecialchars($selectedValue)) . ';<br>';
|
||||
$urlParams['selected'][] = $selectedValue;
|
||||
}
|
||||
|
||||
$this->render('database/structure/empty_form', [
|
||||
'url_params' => $urlParams,
|
||||
'full_query' => $fullQuery,
|
||||
'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\FlashMessages;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Operations;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Sql;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Transformations;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
|
||||
final class EmptyTableController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var RelationCleanup */
|
||||
private $relationCleanup;
|
||||
|
||||
/** @var Operations */
|
||||
private $operations;
|
||||
|
||||
/** @var FlashMessages */
|
||||
private $flash;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
Relation $relation,
|
||||
RelationCleanup $relationCleanup,
|
||||
Operations $operations,
|
||||
FlashMessages $flash,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->relation = $relation;
|
||||
$this->relationCleanup = $relationCleanup;
|
||||
$this->operations = $operations;
|
||||
$this->flash = $flash;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $message, $sql_query;
|
||||
|
||||
$multBtn = $_POST['mult_btn'] ?? '';
|
||||
$selected = $_POST['selected'] ?? [];
|
||||
|
||||
if ($multBtn !== __('Yes')) {
|
||||
$this->flash->addMessage('success', __('No change'));
|
||||
$this->redirect('/database/structure', ['db' => $db]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$defaultFkCheckValue = ForeignKey::handleDisableCheckInit();
|
||||
|
||||
$sql_query = '';
|
||||
$selectedCount = count($selected);
|
||||
|
||||
for ($i = 0; $i < $selectedCount; $i++) {
|
||||
$aQuery = 'TRUNCATE ';
|
||||
$aQuery .= Util::backquote($selected[$i]);
|
||||
|
||||
$sql_query .= $aQuery . ';' . "\n";
|
||||
$this->dbi->selectDb($db);
|
||||
$this->dbi->query($aQuery);
|
||||
}
|
||||
|
||||
if (! empty($_REQUEST['pos'])) {
|
||||
$sql = new Sql(
|
||||
$this->dbi,
|
||||
$this->relation,
|
||||
$this->relationCleanup,
|
||||
$this->operations,
|
||||
new Transformations(),
|
||||
$this->template
|
||||
);
|
||||
|
||||
$_REQUEST['pos'] = $sql->calculatePosForLastPage($db, $table, $_REQUEST['pos']);
|
||||
}
|
||||
|
||||
ForeignKey::handleDisableCheckCleanup($defaultFkCheckValue);
|
||||
|
||||
$message = Message::success();
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = $message;
|
||||
}
|
||||
|
||||
unset($_POST['mult_btn']);
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\RecentFavoriteTable;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function md5;
|
||||
use function sha1;
|
||||
|
||||
final class FavoriteTableController extends AbstractController
|
||||
{
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, Relation $relation)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $errorUrl;
|
||||
|
||||
$parameters = [
|
||||
'favorite_table' => $_REQUEST['favorite_table'] ?? null,
|
||||
'favoriteTables' => $_REQUEST['favoriteTables'] ?? null,
|
||||
'sync_favorite_tables' => $_REQUEST['sync_favorite_tables'] ?? null,
|
||||
];
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase() || ! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$favoriteInstance = RecentFavoriteTable::getInstance('favorite');
|
||||
if (isset($parameters['favoriteTables'])) {
|
||||
$favoriteTables = json_decode($parameters['favoriteTables'], true);
|
||||
} else {
|
||||
$favoriteTables = [];
|
||||
}
|
||||
|
||||
// Required to keep each user's preferences separate.
|
||||
$user = sha1($cfg['Server']['user']);
|
||||
|
||||
// Request for Synchronization of favorite tables.
|
||||
if (isset($parameters['sync_favorite_tables'])) {
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
if ($relationParameters->favoriteTablesFeature !== null) {
|
||||
$this->response->addJSON($this->synchronizeFavoriteTables(
|
||||
$favoriteInstance,
|
||||
$user,
|
||||
$favoriteTables
|
||||
));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$changes = true;
|
||||
$favoriteTable = $parameters['favorite_table'] ?? '';
|
||||
$alreadyFavorite = $this->checkFavoriteTable($favoriteTable);
|
||||
|
||||
if (isset($_REQUEST['remove_favorite'])) {
|
||||
if ($alreadyFavorite) {
|
||||
// If already in favorite list, remove it.
|
||||
$favoriteInstance->remove($this->db, $favoriteTable);
|
||||
$alreadyFavorite = false; // for favorite_anchor template
|
||||
}
|
||||
} elseif (isset($_REQUEST['add_favorite'])) {
|
||||
if (! $alreadyFavorite) {
|
||||
$numTables = count($favoriteInstance->getTables());
|
||||
if ($numTables == $cfg['NumFavoriteTables']) {
|
||||
$changes = false;
|
||||
} else {
|
||||
// Otherwise add to favorite list.
|
||||
$favoriteInstance->add($this->db, $favoriteTable);
|
||||
$alreadyFavorite = true; // for favorite_anchor template
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$favoriteTables[$user] = $favoriteInstance->getTables();
|
||||
|
||||
$json = [];
|
||||
$json['changes'] = $changes;
|
||||
if (! $changes) {
|
||||
$json['message'] = $this->template->render('components/error_message', [
|
||||
'msg' => __('Favorite List is full!'),
|
||||
]);
|
||||
$this->response->addJSON($json);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if current table is already in favorite list.
|
||||
$favoriteParams = [
|
||||
'db' => $this->db,
|
||||
'ajax_request' => true,
|
||||
'favorite_table' => $favoriteTable,
|
||||
($alreadyFavorite ? 'remove' : 'add') . '_favorite' => true,
|
||||
];
|
||||
|
||||
$json['user'] = $user;
|
||||
$json['favoriteTables'] = json_encode($favoriteTables);
|
||||
$json['list'] = $favoriteInstance->getHtmlList();
|
||||
$json['anchor'] = $this->template->render('database/structure/favorite_anchor', [
|
||||
'table_name_hash' => md5($favoriteTable),
|
||||
'db_table_name_hash' => md5($this->db . '.' . $favoriteTable),
|
||||
'fav_params' => $favoriteParams,
|
||||
'already_favorite' => $alreadyFavorite,
|
||||
]);
|
||||
|
||||
$this->response->addJSON($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize favorite tables
|
||||
*
|
||||
* @param RecentFavoriteTable $favoriteInstance Instance of this class
|
||||
* @param string $user The user hash
|
||||
* @param array $favoriteTables Existing favorites
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function synchronizeFavoriteTables(
|
||||
RecentFavoriteTable $favoriteInstance,
|
||||
string $user,
|
||||
array $favoriteTables
|
||||
): array {
|
||||
$favoriteInstanceTables = $favoriteInstance->getTables();
|
||||
|
||||
if (empty($favoriteInstanceTables) && isset($favoriteTables[$user])) {
|
||||
foreach ($favoriteTables[$user] as $value) {
|
||||
$favoriteInstance->add($value['db'], $value['table']);
|
||||
}
|
||||
}
|
||||
|
||||
$favoriteTables[$user] = $favoriteInstance->getTables();
|
||||
|
||||
// Set flag when localStorage and pmadb(if present) are in sync.
|
||||
$_SESSION['tmpval']['favorites_synced'][$GLOBALS['server']] = true;
|
||||
|
||||
return [
|
||||
'favoriteTables' => json_encode($favoriteTables),
|
||||
'list' => $favoriteInstance->getHtmlList(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check if a table is already in favorite list.
|
||||
*
|
||||
* @param string $currentTable current table
|
||||
*/
|
||||
private function checkFavoriteTable(string $currentTable): bool
|
||||
{
|
||||
// ensure $_SESSION['tmpval']['favoriteTables'] is initialized
|
||||
RecentFavoriteTable::getInstance('favorite');
|
||||
$favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
|
||||
foreach ($favoriteTables as $value) {
|
||||
if ($value['db'] == $this->db && $value['table'] == $currentTable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function json_encode;
|
||||
|
||||
/**
|
||||
* Handles request for real row count on database level view page.
|
||||
*/
|
||||
final class RealRowCountController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $errorUrl;
|
||||
|
||||
$parameters = [
|
||||
'real_row_count_all' => $_REQUEST['real_row_count_all'] ?? null,
|
||||
'table' => $_REQUEST['table'] ?? null,
|
||||
];
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase() || ! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
[$tables] = Util::getDbInfo($this->db, '_structure');
|
||||
|
||||
// If there is a request to update all table's row count.
|
||||
if (! isset($parameters['real_row_count_all'])) {
|
||||
// Get the real row count for the table.
|
||||
$realRowCount = (int) $this->dbi
|
||||
->getTable($this->db, (string) $parameters['table'])
|
||||
->getRealRowCountTable();
|
||||
// Format the number.
|
||||
$realRowCount = Util::formatNumber($realRowCount, 0);
|
||||
|
||||
$this->response->addJSON(['real_row_count' => $realRowCount]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Array to store the results.
|
||||
$realRowCountAll = [];
|
||||
// Iterate over each table and fetch real row count.
|
||||
foreach ($tables as $table) {
|
||||
$rowCount = $this->dbi
|
||||
->getTable($this->db, $table['TABLE_NAME'])
|
||||
->getRealRowCountTable();
|
||||
$realRowCountAll[] = [
|
||||
'table' => $table['TABLE_NAME'],
|
||||
'row_count' => $rowCount,
|
||||
];
|
||||
}
|
||||
|
||||
$this->response->addJSON(['real_row_count_all' => json_encode($realRowCountAll)]);
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\StructureController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function count;
|
||||
use function mb_strlen;
|
||||
use function mb_substr;
|
||||
|
||||
final class ReplacePrefixController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var StructureController */
|
||||
private $structureController;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
DatabaseInterface $dbi,
|
||||
StructureController $structureController
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
$this->structureController = $structureController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $message, $sql_query;
|
||||
|
||||
$selected = $_POST['selected'] ?? [];
|
||||
$fromPrefix = $_POST['from_prefix'] ?? '';
|
||||
$toPrefix = $_POST['to_prefix'] ?? '';
|
||||
|
||||
$sql_query = '';
|
||||
$selectedCount = count($selected);
|
||||
|
||||
for ($i = 0; $i < $selectedCount; $i++) {
|
||||
$current = $selected[$i];
|
||||
$subFromPrefix = mb_substr($current, 0, mb_strlen((string) $fromPrefix));
|
||||
|
||||
if ($subFromPrefix === $fromPrefix) {
|
||||
$newTableName = $toPrefix . mb_substr($current, mb_strlen((string) $fromPrefix));
|
||||
} else {
|
||||
$newTableName = $current;
|
||||
}
|
||||
|
||||
$aQuery = 'ALTER TABLE ' . Util::backquote($selected[$i])
|
||||
. ' RENAME ' . Util::backquote($newTableName);
|
||||
|
||||
$sql_query .= $aQuery . ';' . "\n";
|
||||
$this->dbi->selectDb($db);
|
||||
$this->dbi->query($aQuery);
|
||||
}
|
||||
|
||||
$message = Message::success();
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$_POST['message'] = $message;
|
||||
}
|
||||
|
||||
($this->structureController)();
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database\Structure;
|
||||
|
||||
use PhpMyAdmin\Controllers\Database\AbstractController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
|
||||
final class ShowCreateController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$selected = $_POST['selected_tbl'] ?? [];
|
||||
|
||||
if (empty($selected)) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = $this->getShowCreateTables($selected);
|
||||
|
||||
$showCreate = $this->template->render('database/structure/show_create', ['tables' => $tables]);
|
||||
|
||||
$this->response->addJSON('message', $showCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $selected Selected tables.
|
||||
*
|
||||
* @return array<string, array<int, array<string, string>>>
|
||||
*/
|
||||
private function getShowCreateTables(array $selected): array
|
||||
{
|
||||
$tables = ['tables' => [], 'views' => []];
|
||||
|
||||
foreach ($selected as $table) {
|
||||
$object = $this->dbi->getTable($this->db, $table);
|
||||
|
||||
$tables[$object->isView() ? 'views' : 'tables'][] = [
|
||||
'name' => Core::mimeDefaultFunction($table),
|
||||
'show_create' => Core::mimeDefaultFunction($object->showCreate()),
|
||||
];
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
}
|
|
@ -1,918 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\FlashMessages;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Operations;
|
||||
use PhpMyAdmin\RecentFavoriteTable;
|
||||
use PhpMyAdmin\Replication;
|
||||
use PhpMyAdmin\ReplicationInfo;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Tracker;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_search;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function htmlspecialchars;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function max;
|
||||
use function mb_substr;
|
||||
use function md5;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function strtotime;
|
||||
use function urlencode;
|
||||
|
||||
/**
|
||||
* Handles database structure logic
|
||||
*/
|
||||
class StructureController extends AbstractController
|
||||
{
|
||||
/** @var int Number of tables */
|
||||
protected $numTables;
|
||||
|
||||
/** @var int Current position in the list */
|
||||
protected $position;
|
||||
|
||||
/** @var bool DB is information_schema */
|
||||
protected $dbIsSystemSchema;
|
||||
|
||||
/** @var int Number of tables */
|
||||
protected $totalNumTables;
|
||||
|
||||
/** @var array Tables in the database */
|
||||
protected $tables;
|
||||
|
||||
/** @var bool whether stats show or not */
|
||||
protected $isShowStats;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Replication */
|
||||
private $replication;
|
||||
|
||||
/** @var RelationCleanup */
|
||||
private $relationCleanup;
|
||||
|
||||
/** @var Operations */
|
||||
private $operations;
|
||||
|
||||
/** @var ReplicationInfo */
|
||||
private $replicationInfo;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var FlashMessages */
|
||||
private $flash;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Relation $relation,
|
||||
Replication $replication,
|
||||
RelationCleanup $relationCleanup,
|
||||
Operations $operations,
|
||||
DatabaseInterface $dbi,
|
||||
FlashMessages $flash
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->relation = $relation;
|
||||
$this->replication = $replication;
|
||||
$this->relationCleanup = $relationCleanup;
|
||||
$this->operations = $operations;
|
||||
$this->dbi = $dbi;
|
||||
$this->flash = $flash;
|
||||
|
||||
$this->replicationInfo = new ReplicationInfo($this->dbi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves database information for further use
|
||||
*
|
||||
* @param string $subPart Page part name
|
||||
*/
|
||||
private function getDatabaseInfo(string $subPart): void
|
||||
{
|
||||
[
|
||||
$tables,
|
||||
$numTables,
|
||||
$totalNumTables,,
|
||||
$isShowStats,
|
||||
$dbIsSystemSchema,,,
|
||||
$position,
|
||||
] = Util::getDbInfo($this->db, $subPart);
|
||||
|
||||
$this->tables = $tables;
|
||||
$this->numTables = $numTables;
|
||||
$this->position = $position;
|
||||
$this->dbIsSystemSchema = $dbIsSystemSchema;
|
||||
$this->totalNumTables = $totalNumTables;
|
||||
$this->isShowStats = $isShowStats;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db, $errorUrl;
|
||||
|
||||
$parameters = [
|
||||
'sort' => $_REQUEST['sort'] ?? null,
|
||||
'sort_order' => $_REQUEST['sort_order'] ?? null,
|
||||
];
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['database/structure.js', 'table/change.js']);
|
||||
|
||||
// Gets the database structure
|
||||
$this->getDatabaseInfo('_structure');
|
||||
|
||||
// Checks if there are any tables to be shown on current page.
|
||||
// If there are no tables, the user is redirected to the last page
|
||||
// having any.
|
||||
if ($this->totalNumTables > 0 && $this->position > $this->totalNumTables) {
|
||||
$this->redirect('/database/structure', [
|
||||
'db' => $this->db,
|
||||
'pos' => max(0, $this->totalNumTables - $cfg['MaxTableList']),
|
||||
'reload' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->replicationInfo->load($_POST['primary_connection'] ?? null);
|
||||
$replicaInfo = $this->replicationInfo->getReplicaInfo();
|
||||
|
||||
$pageSettings = new PageSettings('DbStructure');
|
||||
$this->response->addHTML($pageSettings->getErrorHTML());
|
||||
$this->response->addHTML($pageSettings->getHTML());
|
||||
|
||||
if ($this->numTables > 0) {
|
||||
$urlParams = [
|
||||
'pos' => $this->position,
|
||||
'db' => $this->db,
|
||||
];
|
||||
if (isset($parameters['sort'])) {
|
||||
$urlParams['sort'] = $parameters['sort'];
|
||||
}
|
||||
|
||||
if (isset($parameters['sort_order'])) {
|
||||
$urlParams['sort_order'] = $parameters['sort_order'];
|
||||
}
|
||||
|
||||
$listNavigator = Generator::getListNavigator(
|
||||
$this->totalNumTables,
|
||||
$this->position,
|
||||
$urlParams,
|
||||
Url::getFromRoute('/database/structure'),
|
||||
'frame_content',
|
||||
$cfg['MaxTableList']
|
||||
);
|
||||
|
||||
$tableList = $this->displayTableList($replicaInfo);
|
||||
}
|
||||
|
||||
$createTable = '';
|
||||
if (empty($this->dbIsSystemSchema)) {
|
||||
$checkUserPrivileges = new CheckUserPrivileges($this->dbi);
|
||||
$checkUserPrivileges->getPrivileges();
|
||||
|
||||
$createTable = $this->template->render('database/create_table', ['db' => $this->db]);
|
||||
}
|
||||
|
||||
$this->render('database/structure/index', [
|
||||
'database' => $this->db,
|
||||
'has_tables' => $this->numTables > 0,
|
||||
'list_navigator_html' => $listNavigator ?? '',
|
||||
'table_list_html' => $tableList ?? '',
|
||||
'is_system_schema' => ! empty($this->dbIsSystemSchema),
|
||||
'create_table_html' => $createTable,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $replicaInfo
|
||||
*/
|
||||
protected function displayTableList($replicaInfo): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
// filtering
|
||||
$html .= $this->template->render('filter', ['filter_value' => '']);
|
||||
|
||||
$i = $sumEntries = 0;
|
||||
$overheadCheck = false;
|
||||
$createTimeAll = '';
|
||||
$updateTimeAll = '';
|
||||
$checkTimeAll = '';
|
||||
$numColumns = $GLOBALS['cfg']['PropertiesNumColumns'] > 1
|
||||
? ceil($this->numTables / $GLOBALS['cfg']['PropertiesNumColumns']) + 1
|
||||
: 0;
|
||||
$rowCount = 0;
|
||||
$sumSize = 0;
|
||||
$overheadSize = 0;
|
||||
|
||||
$hiddenFields = [];
|
||||
$overallApproxRows = false;
|
||||
$structureTableRows = [];
|
||||
foreach ($this->tables as $currentTable) {
|
||||
// Get valid statistics whatever is the table type
|
||||
|
||||
$dropQuery = '';
|
||||
$dropMessage = '';
|
||||
$overhead = '';
|
||||
$inputClass = ['checkall'];
|
||||
|
||||
// Sets parameters for links
|
||||
$tableUrlParams = [
|
||||
'db' => $this->db,
|
||||
'table' => $currentTable['TABLE_NAME'],
|
||||
];
|
||||
// do not list the previous table's size info for a view
|
||||
|
||||
[
|
||||
$currentTable,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$formattedOverhead,
|
||||
$overheadUnit,
|
||||
$overheadSize,
|
||||
$tableIsView,
|
||||
$sumSize,
|
||||
] = $this->getStuffForEngineTypeTable($currentTable, $sumSize, $overheadSize);
|
||||
|
||||
$curTable = $this->dbi
|
||||
->getTable($this->db, $currentTable['TABLE_NAME']);
|
||||
if (! $curTable->isMerge()) {
|
||||
$sumEntries += $currentTable['TABLE_ROWS'];
|
||||
}
|
||||
|
||||
$collationDefinition = '---';
|
||||
if (isset($currentTable['Collation'])) {
|
||||
$tableCollation = Charsets::findCollationByName(
|
||||
$this->dbi,
|
||||
$GLOBALS['cfg']['Server']['DisableIS'],
|
||||
$currentTable['Collation']
|
||||
);
|
||||
if ($tableCollation !== null) {
|
||||
$collationDefinition = $this->template->render('database/structure/collation_definition', [
|
||||
'valueTitle' => $tableCollation->getDescription(),
|
||||
'value' => $tableCollation->getName(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isShowStats) {
|
||||
$overhead = '-';
|
||||
if ($formattedOverhead != '') {
|
||||
$overhead = $this->template->render('database/structure/overhead', [
|
||||
'table_url_params' => $tableUrlParams,
|
||||
'formatted_overhead' => $formattedOverhead,
|
||||
'overhead_unit' => $overheadUnit,
|
||||
]);
|
||||
$overheadCheck = true;
|
||||
$inputClass[] = 'tbl-overhead';
|
||||
}
|
||||
}
|
||||
|
||||
if ($GLOBALS['cfg']['ShowDbStructureCharset']) {
|
||||
$charset = '';
|
||||
if (isset($tableCollation)) {
|
||||
$charset = $tableCollation->getCharset();
|
||||
}
|
||||
}
|
||||
|
||||
if ($GLOBALS['cfg']['ShowDbStructureCreation']) {
|
||||
$createTime = $currentTable['Create_time'] ?? '';
|
||||
if ($createTime && (! $createTimeAll || $createTime < $createTimeAll)) {
|
||||
$createTimeAll = $createTime;
|
||||
}
|
||||
}
|
||||
|
||||
if ($GLOBALS['cfg']['ShowDbStructureLastUpdate']) {
|
||||
$updateTime = $currentTable['Update_time'] ?? '';
|
||||
if ($updateTime && (! $updateTimeAll || $updateTime < $updateTimeAll)) {
|
||||
$updateTimeAll = $updateTime;
|
||||
}
|
||||
}
|
||||
|
||||
if ($GLOBALS['cfg']['ShowDbStructureLastCheck']) {
|
||||
$checkTime = $currentTable['Check_time'] ?? '';
|
||||
if ($checkTime && (! $checkTimeAll || $checkTime < $checkTimeAll)) {
|
||||
$checkTimeAll = $checkTime;
|
||||
}
|
||||
}
|
||||
|
||||
$truename = $currentTable['TABLE_NAME'];
|
||||
|
||||
$i++;
|
||||
|
||||
$rowCount++;
|
||||
if ($tableIsView) {
|
||||
$hiddenFields[] = '<input type="hidden" name="views[]" value="'
|
||||
. htmlspecialchars($currentTable['TABLE_NAME']) . '">';
|
||||
}
|
||||
|
||||
/*
|
||||
* Always activate links for Browse, Search and Empty, even if
|
||||
* the icons are greyed, because
|
||||
* 1. for views, we don't know the number of rows at this point
|
||||
* 2. for tables, another source could have populated them since the
|
||||
* page was generated
|
||||
*
|
||||
* I could have used the PHP ternary conditional operator but I find
|
||||
* the code easier to read without this operator.
|
||||
*/
|
||||
$mayHaveRows = $currentTable['TABLE_ROWS'] > 0 || $tableIsView;
|
||||
|
||||
if (! $this->dbIsSystemSchema) {
|
||||
$dropQuery = sprintf(
|
||||
'DROP %s %s',
|
||||
$tableIsView || $currentTable['ENGINE'] == null ? 'VIEW'
|
||||
: 'TABLE',
|
||||
Util::backquote(
|
||||
$currentTable['TABLE_NAME']
|
||||
)
|
||||
);
|
||||
$dropMessage = sprintf(
|
||||
($tableIsView || $currentTable['ENGINE'] == null
|
||||
? __('View %s has been dropped.')
|
||||
: __('Table %s has been dropped.')),
|
||||
str_replace(
|
||||
' ',
|
||||
' ',
|
||||
htmlspecialchars($currentTable['TABLE_NAME'])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($numColumns > 0 && $this->numTables > $numColumns && ($rowCount % $numColumns) == 0) {
|
||||
$rowCount = 1;
|
||||
|
||||
$html .= $this->template->render('database/structure/table_header', [
|
||||
'db' => $this->db,
|
||||
'db_is_system_schema' => $this->dbIsSystemSchema,
|
||||
'replication' => $replicaInfo['status'],
|
||||
'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'],
|
||||
'is_show_stats' => $this->isShowStats,
|
||||
'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'],
|
||||
'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'],
|
||||
'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'],
|
||||
'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'],
|
||||
'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'],
|
||||
'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'],
|
||||
'structure_table_rows' => $structureTableRows,
|
||||
]);
|
||||
$structureTableRows = [];
|
||||
}
|
||||
|
||||
[$approxRows, $showSuperscript] = $this->isRowCountApproximated($currentTable, $tableIsView);
|
||||
|
||||
[$do, $ignored] = $this->getReplicationStatus($replicaInfo, $truename);
|
||||
|
||||
$structureTableRows[] = [
|
||||
'table_name_hash' => md5($currentTable['TABLE_NAME']),
|
||||
'db_table_name_hash' => md5($this->db . '.' . $currentTable['TABLE_NAME']),
|
||||
'db' => $this->db,
|
||||
'curr' => $i,
|
||||
'input_class' => implode(' ', $inputClass),
|
||||
'table_is_view' => $tableIsView,
|
||||
'current_table' => $currentTable,
|
||||
'may_have_rows' => $mayHaveRows,
|
||||
'browse_table_label_title' => htmlspecialchars($currentTable['TABLE_COMMENT']),
|
||||
'browse_table_label_truename' => $truename,
|
||||
'empty_table_sql_query' => 'TRUNCATE ' . Util::backquote($currentTable['TABLE_NAME']),
|
||||
'empty_table_message_to_show' => urlencode(
|
||||
sprintf(
|
||||
__('Table %s has been emptied.'),
|
||||
htmlspecialchars(
|
||||
$currentTable['TABLE_NAME']
|
||||
)
|
||||
)
|
||||
),
|
||||
'tracking_icon' => $this->getTrackingIcon($truename),
|
||||
'server_replica_status' => $replicaInfo['status'],
|
||||
'table_url_params' => $tableUrlParams,
|
||||
'db_is_system_schema' => $this->dbIsSystemSchema,
|
||||
'drop_query' => $dropQuery,
|
||||
'drop_message' => $dropMessage,
|
||||
'collation' => $collationDefinition,
|
||||
'formatted_size' => $formattedSize,
|
||||
'unit' => $unit,
|
||||
'overhead' => $overhead,
|
||||
'create_time' => isset($createTime) && $createTime
|
||||
? Util::localisedDate(strtotime($createTime)) : '-',
|
||||
'update_time' => isset($updateTime) && $updateTime
|
||||
? Util::localisedDate(strtotime($updateTime)) : '-',
|
||||
'check_time' => isset($checkTime) && $checkTime
|
||||
? Util::localisedDate(strtotime($checkTime)) : '-',
|
||||
'charset' => $charset ?? '',
|
||||
'is_show_stats' => $this->isShowStats,
|
||||
'ignored' => $ignored,
|
||||
'do' => $do,
|
||||
'approx_rows' => $approxRows,
|
||||
'show_superscript' => $showSuperscript,
|
||||
'already_favorite' => $this->checkFavoriteTable($currentTable['TABLE_NAME']),
|
||||
'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'],
|
||||
'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'],
|
||||
'limit_chars' => $GLOBALS['cfg']['LimitChars'],
|
||||
'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'],
|
||||
'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'],
|
||||
'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'],
|
||||
'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'],
|
||||
'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'],
|
||||
];
|
||||
|
||||
$overallApproxRows = $overallApproxRows || $approxRows;
|
||||
}
|
||||
|
||||
$databaseCollation = [];
|
||||
$databaseCharset = '';
|
||||
$collation = Charsets::findCollationByName(
|
||||
$this->dbi,
|
||||
$GLOBALS['cfg']['Server']['DisableIS'],
|
||||
$this->dbi->getDbCollation($this->db)
|
||||
);
|
||||
if ($collation !== null) {
|
||||
$databaseCollation = [
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
];
|
||||
$databaseCharset = $collation->getCharset();
|
||||
}
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
return $html . $this->template->render('database/structure/table_header', [
|
||||
'db' => $this->db,
|
||||
'db_is_system_schema' => $this->dbIsSystemSchema,
|
||||
'replication' => $replicaInfo['status'],
|
||||
'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'],
|
||||
'is_show_stats' => $this->isShowStats,
|
||||
'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'],
|
||||
'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'],
|
||||
'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'],
|
||||
'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'],
|
||||
'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'],
|
||||
'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'],
|
||||
'structure_table_rows' => $structureTableRows,
|
||||
'body_for_table_summary' => [
|
||||
'num_tables' => $this->numTables,
|
||||
'server_replica_status' => $replicaInfo['status'],
|
||||
'db_is_system_schema' => $this->dbIsSystemSchema,
|
||||
'sum_entries' => $sumEntries,
|
||||
'database_collation' => $databaseCollation,
|
||||
'is_show_stats' => $this->isShowStats,
|
||||
'database_charset' => $databaseCharset,
|
||||
'sum_size' => $sumSize,
|
||||
'overhead_size' => $overheadSize,
|
||||
'create_time_all' => $createTimeAll ? Util::localisedDate(strtotime($createTimeAll)) : '-',
|
||||
'update_time_all' => $updateTimeAll ? Util::localisedDate(strtotime($updateTimeAll)) : '-',
|
||||
'check_time_all' => $checkTimeAll ? Util::localisedDate(strtotime($checkTimeAll)) : '-',
|
||||
'approx_rows' => $overallApproxRows,
|
||||
'num_favorite_tables' => $GLOBALS['cfg']['NumFavoriteTables'],
|
||||
'db' => $GLOBALS['db'],
|
||||
'properties_num_columns' => $GLOBALS['cfg']['PropertiesNumColumns'],
|
||||
'dbi' => $this->dbi,
|
||||
'show_charset' => $GLOBALS['cfg']['ShowDbStructureCharset'],
|
||||
'show_comment' => $GLOBALS['cfg']['ShowDbStructureComment'],
|
||||
'show_creation' => $GLOBALS['cfg']['ShowDbStructureCreation'],
|
||||
'show_last_update' => $GLOBALS['cfg']['ShowDbStructureLastUpdate'],
|
||||
'show_last_check' => $GLOBALS['cfg']['ShowDbStructureLastCheck'],
|
||||
],
|
||||
'check_all_tables' => [
|
||||
'text_dir' => $GLOBALS['text_dir'],
|
||||
'overhead_check' => $overheadCheck,
|
||||
'db_is_system_schema' => $this->dbIsSystemSchema,
|
||||
'hidden_fields' => $hiddenFields,
|
||||
'disable_multi_table' => $GLOBALS['cfg']['DisableMultiTableMaintenance'],
|
||||
'central_columns_work' => $relationParameters->centralColumnsFeature !== null,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tracking icon if the table is tracked
|
||||
*
|
||||
* @param string $table table name
|
||||
*
|
||||
* @return string HTML for tracking icon
|
||||
*/
|
||||
protected function getTrackingIcon(string $table): string
|
||||
{
|
||||
$trackingIcon = '';
|
||||
if (Tracker::isActive()) {
|
||||
$isTracked = Tracker::isTracked($this->db, $table);
|
||||
if ($isTracked || Tracker::getVersion($this->db, $table) > 0) {
|
||||
$trackingIcon = $this->template->render('database/structure/tracking_icon', [
|
||||
'db' => $this->db,
|
||||
'table' => $table,
|
||||
'is_tracked' => $isTracked,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $trackingIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the row count is approximated
|
||||
*
|
||||
* @param array $currentTable array containing details about the table
|
||||
* @param bool $tableIsView whether the table is a view
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function isRowCountApproximated(
|
||||
array $currentTable,
|
||||
bool $tableIsView
|
||||
): array {
|
||||
$approxRows = false;
|
||||
$showSuperscript = '';
|
||||
|
||||
// there is a null value in the ENGINE
|
||||
// - when the table needs to be repaired, or
|
||||
// - when it's a view
|
||||
// so ensure that we'll display "in use" below for a table
|
||||
// that needs to be repaired
|
||||
if (isset($currentTable['TABLE_ROWS']) && ($currentTable['ENGINE'] != null || $tableIsView)) {
|
||||
// InnoDB/TokuDB table: we did not get an accurate row count
|
||||
$approxRows = ! $tableIsView
|
||||
&& in_array($currentTable['ENGINE'], ['InnoDB', 'TokuDB'])
|
||||
&& ! $currentTable['COUNTED'];
|
||||
|
||||
if ($tableIsView && $currentTable['TABLE_ROWS'] >= $GLOBALS['cfg']['MaxExactCountViews']) {
|
||||
$approxRows = true;
|
||||
$showSuperscript = Generator::showHint(
|
||||
Sanitize::sanitizeMessage(
|
||||
sprintf(
|
||||
__(
|
||||
'This view has at least this number of rows. Please refer to %sdocumentation%s.'
|
||||
),
|
||||
'[doc@cfg_MaxExactCountViews]',
|
||||
'[/doc]'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$approxRows,
|
||||
$showSuperscript,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the replication status of the table.
|
||||
*
|
||||
* @param array $replicaInfo
|
||||
* @param string $table table name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getReplicationStatus($replicaInfo, string $table): array
|
||||
{
|
||||
$do = $ignored = false;
|
||||
if ($replicaInfo['status']) {
|
||||
$nbServReplicaDoDb = count($replicaInfo['Do_DB']);
|
||||
$nbServReplicaIgnoreDb = count($replicaInfo['Ignore_DB']);
|
||||
$searchDoDBInTruename = array_search($table, $replicaInfo['Do_DB']);
|
||||
$searchDoDBInDB = array_search($this->db, $replicaInfo['Do_DB']);
|
||||
|
||||
$do = (is_string($searchDoDBInTruename) && strlen($searchDoDBInTruename) > 0)
|
||||
|| (is_string($searchDoDBInDB) && strlen($searchDoDBInDB) > 0)
|
||||
|| ($nbServReplicaDoDb == 0 && $nbServReplicaIgnoreDb == 0)
|
||||
|| $this->hasTable($replicaInfo['Wild_Do_Table'], $table);
|
||||
|
||||
$searchDb = array_search($this->db, $replicaInfo['Ignore_DB']);
|
||||
$searchTable = array_search($table, $replicaInfo['Ignore_Table']);
|
||||
$ignored = (is_string($searchTable) && strlen($searchTable) > 0)
|
||||
|| (is_string($searchDb) && strlen($searchDb) > 0)
|
||||
|| $this->hasTable($replicaInfo['Wild_Ignore_Table'], $table);
|
||||
}
|
||||
|
||||
return [
|
||||
$do,
|
||||
$ignored,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check if a table is already in favorite list.
|
||||
*
|
||||
* @param string $currentTable current table
|
||||
*/
|
||||
protected function checkFavoriteTable(string $currentTable): bool
|
||||
{
|
||||
// ensure $_SESSION['tmpval']['favoriteTables'] is initialized
|
||||
RecentFavoriteTable::getInstance('favorite');
|
||||
$favoriteTables = $_SESSION['tmpval']['favoriteTables'][$GLOBALS['server']] ?? [];
|
||||
foreach ($favoriteTables as $value) {
|
||||
if ($value['db'] == $this->db && $value['table'] == $currentTable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find table with truename
|
||||
*
|
||||
* @param array $db DB to look into
|
||||
* @param string $truename Table name
|
||||
*/
|
||||
protected function hasTable(array $db, $truename): bool
|
||||
{
|
||||
foreach ($db as $dbTable) {
|
||||
if (
|
||||
$this->db == $this->replication->extractDbOrTable($dbTable)
|
||||
&& preg_match(
|
||||
'@^' .
|
||||
preg_quote(mb_substr($this->replication->extractDbOrTable($dbTable, 'table'), 0, -1), '@') . '@',
|
||||
$truename
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value set for ENGINE table,
|
||||
*
|
||||
* @internal param bool $table_is_view whether table is view or not
|
||||
*
|
||||
* @param array $currentTable current table
|
||||
* @param int $sumSize total table size
|
||||
* @param int $overheadSize overhead size
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getStuffForEngineTypeTable(
|
||||
array $currentTable,
|
||||
$sumSize,
|
||||
$overheadSize
|
||||
) {
|
||||
$formattedSize = '-';
|
||||
$unit = '';
|
||||
$formattedOverhead = '';
|
||||
$overheadUnit = '';
|
||||
$tableIsView = false;
|
||||
|
||||
switch ($currentTable['ENGINE']) {
|
||||
// MyISAM, ISAM or Heap table: Row count, data size and index size
|
||||
// are accurate; data size is accurate for ARCHIVE
|
||||
case 'MyISAM':
|
||||
case 'ISAM':
|
||||
case 'HEAP':
|
||||
case 'MEMORY':
|
||||
case 'ARCHIVE':
|
||||
case 'Aria':
|
||||
case 'Maria':
|
||||
[
|
||||
$currentTable,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$formattedOverhead,
|
||||
$overheadUnit,
|
||||
$overheadSize,
|
||||
$sumSize,
|
||||
] = $this->getValuesForAriaTable(
|
||||
$currentTable,
|
||||
$sumSize,
|
||||
$overheadSize,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$formattedOverhead,
|
||||
$overheadUnit
|
||||
);
|
||||
break;
|
||||
case 'InnoDB':
|
||||
case 'PBMS':
|
||||
case 'TokuDB':
|
||||
// InnoDB table: Row count is not accurate but data and index sizes are.
|
||||
// PBMS table in Drizzle: TABLE_ROWS is taken from table cache,
|
||||
// so it may be unavailable
|
||||
[$currentTable, $formattedSize, $unit, $sumSize] = $this->getValuesForInnodbTable(
|
||||
$currentTable,
|
||||
$sumSize
|
||||
);
|
||||
break;
|
||||
// Mysql 5.0.x (and lower) uses MRG_MyISAM
|
||||
// and MySQL 5.1.x (and higher) uses MRG_MYISAM
|
||||
// Both are aliases for MERGE
|
||||
case 'MRG_MyISAM':
|
||||
case 'MRG_MYISAM':
|
||||
case 'MERGE':
|
||||
case 'BerkeleyDB':
|
||||
// Merge or BerkleyDB table: Only row count is accurate.
|
||||
if ($this->isShowStats) {
|
||||
$formattedSize = ' - ';
|
||||
$unit = '';
|
||||
}
|
||||
|
||||
break;
|
||||
// for a view, the ENGINE is sometimes reported as null,
|
||||
// or on some servers it's reported as "SYSTEM VIEW"
|
||||
case null:
|
||||
case 'SYSTEM VIEW':
|
||||
// possibly a view, do nothing
|
||||
break;
|
||||
case 'Mroonga':
|
||||
// The idea is to show the size only if Mroonga is available,
|
||||
// in other case the old unknown message will appear
|
||||
if (StorageEngine::hasMroongaEngine()) {
|
||||
[$currentTable, $formattedSize, $unit, $sumSize] = $this->getValuesForMroongaTable(
|
||||
$currentTable,
|
||||
$sumSize
|
||||
);
|
||||
break;
|
||||
}
|
||||
// no break, go to default case
|
||||
default:
|
||||
// Unknown table type.
|
||||
if ($this->isShowStats) {
|
||||
$formattedSize = __('unknown');
|
||||
$unit = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($currentTable['TABLE_TYPE'] === 'VIEW' || $currentTable['TABLE_TYPE'] === 'SYSTEM VIEW') {
|
||||
// countRecords() takes care of $cfg['MaxExactCountViews']
|
||||
$currentTable['TABLE_ROWS'] = $this->dbi
|
||||
->getTable($this->db, $currentTable['TABLE_NAME'])
|
||||
->countRecords(true);
|
||||
$tableIsView = true;
|
||||
}
|
||||
|
||||
return [
|
||||
$currentTable,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$formattedOverhead,
|
||||
$overheadUnit,
|
||||
$overheadSize,
|
||||
$tableIsView,
|
||||
$sumSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values for ARIA/MARIA tables
|
||||
*
|
||||
* @param array $currentTable current table
|
||||
* @param int $sumSize sum size
|
||||
* @param int $overheadSize overhead size
|
||||
* @param int $formattedSize formatted size
|
||||
* @param string $unit unit
|
||||
* @param int $formattedOverhead overhead formatted
|
||||
* @param string $overheadUnit overhead unit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getValuesForAriaTable(
|
||||
array $currentTable,
|
||||
$sumSize,
|
||||
$overheadSize,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$formattedOverhead,
|
||||
$overheadUnit
|
||||
) {
|
||||
if ($this->dbIsSystemSchema) {
|
||||
$currentTable['Rows'] = $this->dbi
|
||||
->getTable($this->db, $currentTable['Name'])
|
||||
->countRecords();
|
||||
}
|
||||
|
||||
if ($this->isShowStats) {
|
||||
/** @var int $tblsize */
|
||||
$tblsize = $currentTable['Data_length']
|
||||
+ $currentTable['Index_length'];
|
||||
$sumSize += $tblsize;
|
||||
[$formattedSize, $unit] = Util::formatByteDown($tblsize, 3, $tblsize > 0 ? 1 : 0);
|
||||
if (isset($currentTable['Data_free']) && $currentTable['Data_free'] > 0) {
|
||||
[$formattedOverhead, $overheadUnit] = Util::formatByteDown(
|
||||
$currentTable['Data_free'],
|
||||
3,
|
||||
($currentTable['Data_free'] > 0 ? 1 : 0)
|
||||
);
|
||||
$overheadSize += $currentTable['Data_free'];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$currentTable,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$formattedOverhead,
|
||||
$overheadUnit,
|
||||
$overheadSize,
|
||||
$sumSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values for InnoDB table
|
||||
*
|
||||
* @param array $currentTable current table
|
||||
* @param int $sumSize sum size
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getValuesForInnodbTable(
|
||||
array $currentTable,
|
||||
$sumSize
|
||||
) {
|
||||
$formattedSize = $unit = '';
|
||||
|
||||
if (
|
||||
(in_array($currentTable['ENGINE'], ['InnoDB', 'TokuDB'])
|
||||
&& $currentTable['TABLE_ROWS'] < $GLOBALS['cfg']['MaxExactCount'])
|
||||
|| ! isset($currentTable['TABLE_ROWS'])
|
||||
) {
|
||||
$currentTable['COUNTED'] = true;
|
||||
$currentTable['TABLE_ROWS'] = $this->dbi
|
||||
->getTable($this->db, $currentTable['TABLE_NAME'])
|
||||
->countRecords(true);
|
||||
} else {
|
||||
$currentTable['COUNTED'] = false;
|
||||
}
|
||||
|
||||
if ($this->isShowStats) {
|
||||
/** @var int $tblsize */
|
||||
$tblsize = $currentTable['Data_length']
|
||||
+ $currentTable['Index_length'];
|
||||
$sumSize += $tblsize;
|
||||
[$formattedSize, $unit] = Util::formatByteDown($tblsize, 3, ($tblsize > 0 ? 1 : 0));
|
||||
}
|
||||
|
||||
return [
|
||||
$currentTable,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$sumSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values for Mroonga table
|
||||
*
|
||||
* @param array $currentTable current table
|
||||
* @param int $sumSize sum size
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getValuesForMroongaTable(
|
||||
array $currentTable,
|
||||
int $sumSize
|
||||
): array {
|
||||
$formattedSize = '';
|
||||
$unit = '';
|
||||
|
||||
if ($this->isShowStats) {
|
||||
/** @var int $tblsize */
|
||||
$tblsize = $currentTable['Data_length'] + $currentTable['Index_length'];
|
||||
$sumSize += $tblsize;
|
||||
[$formattedSize, $unit] = Util::formatByteDown($tblsize, 3, ($tblsize > 0 ? 1 : 0));
|
||||
}
|
||||
|
||||
return [
|
||||
$currentTable,
|
||||
$formattedSize,
|
||||
$unit,
|
||||
$sumSize,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Tracker;
|
||||
use PhpMyAdmin\Tracking;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function htmlspecialchars;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Tracking configuration for database.
|
||||
*/
|
||||
class TrackingController extends AbstractController
|
||||
{
|
||||
/** @var Tracking */
|
||||
private $tracking;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
string $db,
|
||||
Tracking $tracking,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->tracking = $tracking;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $text_dir, $urlParams, $tables, $num_tables;
|
||||
global $total_num_tables, $sub_part, $pos, $data, $cfg;
|
||||
global $tooltip_truename, $tooltip_aliasname, $errorUrl;
|
||||
|
||||
$this->addScriptFiles(['vendor/jquery/jquery.tablesorter.js', 'database/tracking.js']);
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urlParams['goto'] = Url::getFromRoute('/table/tracking');
|
||||
$urlParams['back'] = Url::getFromRoute('/database/tracking');
|
||||
|
||||
// Get the database structure
|
||||
$sub_part = '_structure';
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,
|
||||
$isSystemSchema,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part);
|
||||
|
||||
if (isset($_POST['delete_tracking'], $_POST['table'])) {
|
||||
Tracker::deleteTracking($db, $_POST['table']);
|
||||
echo Message::success(
|
||||
__('Tracking data deleted successfully.')
|
||||
)->getDisplay();
|
||||
} elseif (isset($_POST['submit_create_version'])) {
|
||||
$this->tracking->createTrackingForMultipleTables($db, $_POST['selected']);
|
||||
echo Message::success(
|
||||
sprintf(
|
||||
__(
|
||||
'Version %1$s was created for selected tables, tracking is active for them.'
|
||||
),
|
||||
htmlspecialchars($_POST['version'])
|
||||
)
|
||||
)->getDisplay();
|
||||
} elseif (isset($_POST['submit_mult'])) {
|
||||
if (! empty($_POST['selected_tbl'])) {
|
||||
if ($_POST['submit_mult'] === 'delete_tracking') {
|
||||
foreach ($_POST['selected_tbl'] as $table) {
|
||||
Tracker::deleteTracking($db, $table);
|
||||
}
|
||||
|
||||
echo Message::success(
|
||||
__('Tracking data deleted successfully.')
|
||||
)->getDisplay();
|
||||
} elseif ($_POST['submit_mult'] === 'track') {
|
||||
echo $this->template->render('create_tracking_version', [
|
||||
'route' => '/database/tracking',
|
||||
'url_params' => $urlParams,
|
||||
'last_version' => 0,
|
||||
'db' => $db,
|
||||
'selected' => $_POST['selected_tbl'],
|
||||
'type' => 'both',
|
||||
'default_statements' => $cfg['Server']['tracking_default_statements'],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
echo Message::notice(
|
||||
__('No tables selected.')
|
||||
)->getDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
// Get tracked data about the database
|
||||
$data = Tracker::getTrackedData($db, '', '1');
|
||||
|
||||
// No tables present and no log exist
|
||||
if ($num_tables == 0 && count($data['ddlog']) === 0) {
|
||||
echo '<p>' , __('No tables found in database.') , '</p>' , "\n";
|
||||
|
||||
if (empty($isSystemSchema)) {
|
||||
$checkUserPrivileges = new CheckUserPrivileges($this->dbi);
|
||||
$checkUserPrivileges->getPrivileges();
|
||||
|
||||
echo $this->template->render('database/create_table', ['db' => $db]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
echo $this->tracking->getHtmlForDbTrackingTables($db, $urlParams, $text_dir);
|
||||
|
||||
// If available print out database log
|
||||
if (count($data['ddlog']) <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$log = '';
|
||||
foreach ($data['ddlog'] as $entry) {
|
||||
$log .= '# ' . $entry['date'] . ' ' . $entry['username'] . "\n"
|
||||
. $entry['statement'] . "\n";
|
||||
}
|
||||
|
||||
echo Generator::getMessage(__('Database Log'), $log);
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Database;
|
||||
|
||||
use PhpMyAdmin\Database\Triggers;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\DbTableExists;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function in_array;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* Triggers management.
|
||||
*/
|
||||
class TriggersController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, string $db, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template, $db);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $tables, $num_tables, $total_num_tables, $sub_part;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos;
|
||||
global $errors, $urlParams, $errorUrl, $cfg;
|
||||
|
||||
$this->addScriptFiles(['database/triggers.js']);
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
/**
|
||||
* Displays the header and tabs
|
||||
*/
|
||||
if (! empty($table) && in_array($table, $this->dbi->getTables($db))) {
|
||||
Util::checkParameters(['db', 'table']);
|
||||
|
||||
$urlParams = ['db' => $db, 'table' => $table];
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table');
|
||||
$errorUrl .= Url::getCommon($urlParams, '&');
|
||||
|
||||
DbTableExists::check();
|
||||
} else {
|
||||
$table = '';
|
||||
|
||||
Util::checkParameters(['db']);
|
||||
|
||||
$errorUrl = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$errorUrl .= Url::getCommon(['db' => $db], '&');
|
||||
|
||||
if (! $this->hasDatabase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part ?? '');
|
||||
}
|
||||
} elseif (strlen($db) > 0) {
|
||||
$this->dbi->selectDb($db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep a list of errors that occurred while
|
||||
* processing an 'Add' or 'Edit' operation.
|
||||
*/
|
||||
$errors = [];
|
||||
|
||||
$triggers = new Triggers($this->dbi, $this->template, $this->response);
|
||||
$triggers->main();
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
final class DatabaseController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $dblist;
|
||||
|
||||
$this->response->addJSON(['databases' => $dblist->databases]);
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Handle error report submission
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\ErrorHandler;
|
||||
use PhpMyAdmin\ErrorReport;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* Handle error report submission
|
||||
*/
|
||||
class ErrorReportController extends AbstractController
|
||||
{
|
||||
/** @var ErrorReport */
|
||||
private $errorReport;
|
||||
|
||||
/** @var ErrorHandler */
|
||||
private $errorHandler;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
ErrorReport $errorReport,
|
||||
ErrorHandler $errorHandler
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->errorReport = $errorReport;
|
||||
$this->errorHandler = $errorHandler;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
/** @var string $exceptionType */
|
||||
$exceptionType = $request->getParsedBodyParam('exception_type', '');
|
||||
/** @var string|null $sendErrorReport */
|
||||
$sendErrorReport = $request->getParsedBodyParam('send_error_report');
|
||||
/** @var string|null $automatic */
|
||||
$automatic = $request->getParsedBodyParam('automatic');
|
||||
/** @var string|null $alwaysSend */
|
||||
$alwaysSend = $request->getParsedBodyParam('always_send');
|
||||
/** @var string|null $getSettings */
|
||||
$getSettings = $request->getParsedBodyParam('get_settings');
|
||||
|
||||
if (! in_array($exceptionType, ['js', 'php'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($sendErrorReport) {
|
||||
if ($exceptionType === 'php') {
|
||||
/**
|
||||
* Prevent infinite error submission.
|
||||
* Happens in case error submissions fails.
|
||||
* If reporting is done in some time interval,
|
||||
* just clear them & clear json data too.
|
||||
*/
|
||||
if (
|
||||
isset($_SESSION['prev_error_subm_time'], $_SESSION['error_subm_count'])
|
||||
&& $_SESSION['error_subm_count'] >= 3
|
||||
&& ($_SESSION['prev_error_subm_time'] - time()) <= 3000
|
||||
) {
|
||||
$_SESSION['error_subm_count'] = 0;
|
||||
$_SESSION['prev_errors'] = '';
|
||||
$this->response->addJSON('stopErrorReportLoop', '1');
|
||||
} else {
|
||||
$_SESSION['prev_error_subm_time'] = time();
|
||||
$_SESSION['error_subm_count'] = isset($_SESSION['error_subm_count'])
|
||||
? $_SESSION['error_subm_count'] + 1
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
$reportData = $this->errorReport->getData($exceptionType);
|
||||
// report if and only if there were 'actual' errors.
|
||||
if (count($reportData) > 0) {
|
||||
$server_response = $this->errorReport->send($reportData);
|
||||
if (! is_string($server_response)) {
|
||||
$success = false;
|
||||
} else {
|
||||
$decoded_response = json_decode($server_response, true);
|
||||
$success = ! empty($decoded_response) ?
|
||||
$decoded_response['success'] : false;
|
||||
}
|
||||
|
||||
/* Message to show to the user */
|
||||
if ($success) {
|
||||
if ($automatic === 'true' || $cfg['SendErrorReports'] === 'always') {
|
||||
$msg = __(
|
||||
'An error has been detected and an error report has been '
|
||||
. 'automatically submitted based on your settings.'
|
||||
);
|
||||
} else {
|
||||
$msg = __('Thank you for submitting this report.');
|
||||
}
|
||||
} else {
|
||||
$msg = __(
|
||||
'An error has been detected and an error report has been generated but failed to be sent.'
|
||||
);
|
||||
$msg .= ' ';
|
||||
$msg .= __('If you experience any problems please submit a bug report manually.');
|
||||
}
|
||||
|
||||
$msg .= ' ' . __('You may want to refresh the page.');
|
||||
|
||||
/* Create message object */
|
||||
if ($success) {
|
||||
$msg = Message::notice($msg);
|
||||
} else {
|
||||
$msg = Message::error($msg);
|
||||
}
|
||||
|
||||
/* Add message to response */
|
||||
if ($this->response->isAjax()) {
|
||||
if ($exceptionType === 'js') {
|
||||
$this->response->addJSON('message', $msg);
|
||||
} else {
|
||||
$this->response->addJSON('errSubmitMsg', $msg);
|
||||
}
|
||||
} elseif ($exceptionType === 'php') {
|
||||
$jsCode = 'Functions.ajaxShowMessage(\'<div class="alert alert-danger" role="alert">'
|
||||
. $msg
|
||||
. '</div>\', false);';
|
||||
$this->response->getFooter()->getScripts()->addCode($jsCode);
|
||||
}
|
||||
|
||||
if ($exceptionType === 'php') {
|
||||
// clear previous errors & save new ones.
|
||||
$this->errorHandler->savePreviousErrors();
|
||||
}
|
||||
|
||||
/* Persist always send settings */
|
||||
if ($alwaysSend === 'true') {
|
||||
$userPreferences = new UserPreferences();
|
||||
$userPreferences->persistOption('SendErrorReports', 'always', 'ask');
|
||||
}
|
||||
}
|
||||
} elseif ($getSettings) {
|
||||
$this->response->addJSON('report_setting', $cfg['SendErrorReports']);
|
||||
} elseif ($exceptionType === 'js') {
|
||||
$this->response->addJSON('report_modal', $this->errorReport->getEmptyModal());
|
||||
$this->response->addHTML($this->errorReport->getForm());
|
||||
} else {
|
||||
// clear previous errors & save new ones.
|
||||
$this->errorHandler->savePreviousErrors();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
|
||||
final class CheckTimeOutController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
$this->response->setAjax(true);
|
||||
|
||||
if (isset($_SESSION['pma_export_error'])) {
|
||||
unset($_SESSION['pma_export_error']);
|
||||
$this->response->addJSON('message', 'timeout');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON('message', 'success');
|
||||
}
|
||||
}
|
|
@ -1,682 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\ExportController as DatabaseExportController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\Exceptions\ExportException;
|
||||
use PhpMyAdmin\Export;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\SqlParser\Parser;
|
||||
use PhpMyAdmin\SqlParser\Statements\SelectStatement;
|
||||
use PhpMyAdmin\SqlParser\Utils\Misc;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function function_exists;
|
||||
use function in_array;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function ob_end_clean;
|
||||
use function ob_get_length;
|
||||
use function ob_get_level;
|
||||
use function register_shutdown_function;
|
||||
use function strlen;
|
||||
use function time;
|
||||
|
||||
use const PHP_EOL;
|
||||
|
||||
final class ExportController extends AbstractController
|
||||
{
|
||||
/** @var Export */
|
||||
private $export;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Export $export)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->export = $export;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $containerBuilder, $db, $export_type, $filename_template, $sql_query, $errorUrl, $message;
|
||||
global $compression, $crlf, $asfile, $buffer_needed, $save_on_server, $file_handle, $separate_files;
|
||||
global $output_charset_conversion, $output_kanji_conversion, $table, $what, $export_plugin, $single_table;
|
||||
global $compression_methods, $onserver, $back_button, $refreshButton, $save_filename, $filename;
|
||||
global $quick_export, $cfg, $tables, $table_select, $aliases;
|
||||
global $time_start, $charset, $remember_template, $mime_type, $num_tables;
|
||||
global $active_page, $do_relation, $do_comments, $do_mime, $do_dates, $whatStrucOrData, $db_select;
|
||||
global $table_structure, $table_data, $lock_tables, $allrows, $limit_to, $limit_from;
|
||||
|
||||
/** @var array<string, string> $postParams */
|
||||
$postParams = $request->getParsedBody();
|
||||
|
||||
/** @var string $whatParam */
|
||||
$whatParam = $request->getParsedBodyParam('what', '');
|
||||
/** @var string|null $quickOrCustom */
|
||||
$quickOrCustom = $request->getParsedBodyParam('quick_or_custom');
|
||||
/** @var string|null $outputFormat */
|
||||
$outputFormat = $request->getParsedBodyParam('output_format');
|
||||
/** @var string $compressionParam */
|
||||
$compressionParam = $request->getParsedBodyParam('compression', '');
|
||||
/** @var string|null $asSeparateFiles */
|
||||
$asSeparateFiles = $request->getParsedBodyParam('as_separate_files');
|
||||
/** @var string|null $quickExportOnServer */
|
||||
$quickExportOnServer = $request->getParsedBodyParam('quick_export_onserver');
|
||||
/** @var string|null $onServerParam */
|
||||
$onServerParam = $request->getParsedBodyParam('onserver');
|
||||
/** @var array|null $aliasesParam */
|
||||
$aliasesParam = $request->getParsedBodyParam('aliases');
|
||||
/** @var string|null $structureOrDataForced */
|
||||
$structureOrDataForced = $request->getParsedBodyParam('structure_or_data_forced');
|
||||
|
||||
$this->addScriptFiles(['export_output.js']);
|
||||
|
||||
/**
|
||||
* Sets globals from $_POST
|
||||
*
|
||||
* - Please keep the parameters in order of their appearance in the form
|
||||
* - Some of these parameters are not used, as the code below directly
|
||||
* verifies from the superglobal $_POST or $_REQUEST
|
||||
* TODO: this should be removed to avoid passing user input to GLOBALS
|
||||
* without checking
|
||||
*/
|
||||
$allowedPostParams = [
|
||||
'db',
|
||||
'table',
|
||||
'what',
|
||||
'single_table',
|
||||
'export_type',
|
||||
'export_method',
|
||||
'quick_or_custom',
|
||||
'db_select',
|
||||
'table_select',
|
||||
'table_structure',
|
||||
'table_data',
|
||||
'limit_to',
|
||||
'limit_from',
|
||||
'allrows',
|
||||
'lock_tables',
|
||||
'output_format',
|
||||
'filename_template',
|
||||
'maxsize',
|
||||
'remember_template',
|
||||
'charset',
|
||||
'compression',
|
||||
'as_separate_files',
|
||||
'knjenc',
|
||||
'xkana',
|
||||
'htmlword_structure_or_data',
|
||||
'htmlword_null',
|
||||
'htmlword_columns',
|
||||
'mediawiki_headers',
|
||||
'mediawiki_structure_or_data',
|
||||
'mediawiki_caption',
|
||||
'pdf_structure_or_data',
|
||||
'odt_structure_or_data',
|
||||
'odt_relation',
|
||||
'odt_comments',
|
||||
'odt_mime',
|
||||
'odt_columns',
|
||||
'odt_null',
|
||||
'codegen_structure_or_data',
|
||||
'codegen_format',
|
||||
'excel_null',
|
||||
'excel_removeCRLF',
|
||||
'excel_columns',
|
||||
'excel_edition',
|
||||
'excel_structure_or_data',
|
||||
'yaml_structure_or_data',
|
||||
'ods_null',
|
||||
'ods_structure_or_data',
|
||||
'ods_columns',
|
||||
'json_structure_or_data',
|
||||
'json_pretty_print',
|
||||
'json_unicode',
|
||||
'xml_structure_or_data',
|
||||
'xml_export_events',
|
||||
'xml_export_functions',
|
||||
'xml_export_procedures',
|
||||
'xml_export_tables',
|
||||
'xml_export_triggers',
|
||||
'xml_export_views',
|
||||
'xml_export_contents',
|
||||
'texytext_structure_or_data',
|
||||
'texytext_columns',
|
||||
'texytext_null',
|
||||
'phparray_structure_or_data',
|
||||
'sql_include_comments',
|
||||
'sql_header_comment',
|
||||
'sql_dates',
|
||||
'sql_relation',
|
||||
'sql_mime',
|
||||
'sql_use_transaction',
|
||||
'sql_disable_fk',
|
||||
'sql_compatibility',
|
||||
'sql_structure_or_data',
|
||||
'sql_create_database',
|
||||
'sql_drop_table',
|
||||
'sql_procedure_function',
|
||||
'sql_create_table',
|
||||
'sql_create_view',
|
||||
'sql_create_trigger',
|
||||
'sql_view_current_user',
|
||||
'sql_simple_view_export',
|
||||
'sql_if_not_exists',
|
||||
'sql_or_replace_view',
|
||||
'sql_auto_increment',
|
||||
'sql_backquotes',
|
||||
'sql_truncate',
|
||||
'sql_delayed',
|
||||
'sql_ignore',
|
||||
'sql_type',
|
||||
'sql_insert_syntax',
|
||||
'sql_max_query_size',
|
||||
'sql_hex_for_binary',
|
||||
'sql_utc_time',
|
||||
'sql_drop_database',
|
||||
'sql_views_as_tables',
|
||||
'sql_metadata',
|
||||
'csv_separator',
|
||||
'csv_enclosed',
|
||||
'csv_escaped',
|
||||
'csv_terminated',
|
||||
'csv_null',
|
||||
'csv_removeCRLF',
|
||||
'csv_columns',
|
||||
'csv_structure_or_data',
|
||||
// csv_replace should have been here but we use it directly from $_POST
|
||||
'latex_caption',
|
||||
'latex_structure_or_data',
|
||||
'latex_structure_caption',
|
||||
'latex_structure_continued_caption',
|
||||
'latex_structure_label',
|
||||
'latex_relation',
|
||||
'latex_comments',
|
||||
'latex_mime',
|
||||
'latex_columns',
|
||||
'latex_data_caption',
|
||||
'latex_data_continued_caption',
|
||||
'latex_data_label',
|
||||
'latex_null',
|
||||
'aliases',
|
||||
];
|
||||
|
||||
foreach ($allowedPostParams as $param) {
|
||||
if (! isset($postParams[$param])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$GLOBALS[$param] = $postParams[$param];
|
||||
}
|
||||
|
||||
Util::checkParameters(['what', 'export_type']);
|
||||
|
||||
// sanitize this parameter which will be used below in a file inclusion
|
||||
$what = Core::securePath($whatParam);
|
||||
|
||||
// export class instance, not array of properties, as before
|
||||
/** @var ExportPlugin $export_plugin */
|
||||
$export_plugin = Plugins::getPlugin('export', $what, [
|
||||
'export_type' => (string) $export_type,
|
||||
'single_table' => isset($single_table),
|
||||
]);
|
||||
|
||||
// Check export type
|
||||
if (empty($export_plugin)) {
|
||||
Core::fatalError(__('Bad type!'));
|
||||
}
|
||||
|
||||
/**
|
||||
* valid compression methods
|
||||
*/
|
||||
$compression_methods = [];
|
||||
if ($GLOBALS['cfg']['ZipDump'] && function_exists('gzcompress')) {
|
||||
$compression_methods[] = 'zip';
|
||||
}
|
||||
|
||||
if ($GLOBALS['cfg']['GZipDump'] && function_exists('gzencode')) {
|
||||
$compression_methods[] = 'gzip';
|
||||
}
|
||||
|
||||
/**
|
||||
* init and variable checking
|
||||
*/
|
||||
$compression = '';
|
||||
$onserver = false;
|
||||
$save_on_server = false;
|
||||
$buffer_needed = false;
|
||||
$back_button = '';
|
||||
$refreshButton = '';
|
||||
$save_filename = '';
|
||||
$file_handle = '';
|
||||
$errorUrl = '';
|
||||
$filename = '';
|
||||
$separate_files = '';
|
||||
|
||||
// Is it a quick or custom export?
|
||||
if ($quickOrCustom === 'quick') {
|
||||
$quick_export = true;
|
||||
} else {
|
||||
$quick_export = false;
|
||||
}
|
||||
|
||||
if ($outputFormat === 'astext') {
|
||||
$asfile = false;
|
||||
} else {
|
||||
$asfile = true;
|
||||
if ($asSeparateFiles && $compressionParam === 'zip') {
|
||||
$separate_files = $asSeparateFiles;
|
||||
}
|
||||
|
||||
if (in_array($compressionParam, $compression_methods)) {
|
||||
$compression = $compressionParam;
|
||||
$buffer_needed = true;
|
||||
}
|
||||
|
||||
if (($quick_export && $quickExportOnServer) || (! $quick_export && $onServerParam)) {
|
||||
if ($quick_export) {
|
||||
$onserver = $quickExportOnServer;
|
||||
} else {
|
||||
$onserver = $onServerParam;
|
||||
}
|
||||
|
||||
// Will we save dump on server?
|
||||
$save_on_server = ! empty($cfg['SaveDir']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are sending the export file (as opposed to just displaying it
|
||||
* as text), we have to bypass the usual PhpMyAdmin\Response mechanism
|
||||
*/
|
||||
if ($outputFormat === 'sendit' && ! $save_on_server) {
|
||||
$this->response->disable();
|
||||
//Disable all active buffers (see: ob_get_status(true) at this point)
|
||||
do {
|
||||
if (ob_get_length() > 0 || ob_get_level() > 0) {
|
||||
$hasBuffer = ob_end_clean();
|
||||
} else {
|
||||
$hasBuffer = false;
|
||||
}
|
||||
} while ($hasBuffer);
|
||||
}
|
||||
|
||||
$tables = [];
|
||||
// Generate error url and check for needed variables
|
||||
if ($export_type === 'server') {
|
||||
$errorUrl = Url::getFromRoute('/server/export');
|
||||
} elseif ($export_type === 'database' && strlen($db) > 0) {
|
||||
$errorUrl = Url::getFromRoute('/database/export', ['db' => $db]);
|
||||
// Check if we have something to export
|
||||
$tables = $table_select ?? [];
|
||||
} elseif ($export_type === 'table' && strlen($db) > 0 && strlen($table) > 0) {
|
||||
$errorUrl = Url::getFromRoute('/table/export', [
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
]);
|
||||
} elseif ($export_type === 'raw') {
|
||||
$errorUrl = Url::getFromRoute('/server/export', ['sql_query' => $sql_query]);
|
||||
} else {
|
||||
Core::fatalError(__('Bad parameters!'));
|
||||
}
|
||||
|
||||
// Merge SQL Query aliases with Export aliases from
|
||||
// export page, Export page aliases are given more
|
||||
// preference over SQL Query aliases.
|
||||
$parser = new Parser($sql_query);
|
||||
$aliases = [];
|
||||
if (! empty($parser->statements[0]) && ($parser->statements[0] instanceof SelectStatement)) {
|
||||
$aliases = Misc::getAliases($parser->statements[0], $db);
|
||||
}
|
||||
|
||||
if (! empty($aliasesParam)) {
|
||||
$aliases = $this->export->mergeAliases($aliases, $aliasesParam);
|
||||
$_SESSION['tmpval']['aliases'] = $aliasesParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase time limit for script execution and initializes some variables
|
||||
*/
|
||||
Util::setTimeLimit();
|
||||
if (! empty($cfg['MemoryLimit'])) {
|
||||
ini_set('memory_limit', $cfg['MemoryLimit']);
|
||||
}
|
||||
|
||||
register_shutdown_function([$this->export, 'shutdown']);
|
||||
// Start with empty buffer
|
||||
$this->export->dumpBuffer = '';
|
||||
$this->export->dumpBufferLength = 0;
|
||||
|
||||
// Array of dump buffers - used in separate file exports
|
||||
$this->export->dumpBufferObjects = [];
|
||||
|
||||
// We send fake headers to avoid browser timeout when buffering
|
||||
$time_start = time();
|
||||
|
||||
// Defines the default <CR><LF> format.
|
||||
// For SQL always use \n as MySQL wants this on all platforms.
|
||||
if ($what === 'sql') {
|
||||
$crlf = "\n";
|
||||
} else {
|
||||
$crlf = PHP_EOL;
|
||||
}
|
||||
|
||||
$output_kanji_conversion = Encoding::canConvertKanji();
|
||||
|
||||
// Do we need to convert charset?
|
||||
$output_charset_conversion = $asfile
|
||||
&& Encoding::isSupported()
|
||||
&& isset($charset) && $charset !== 'utf-8';
|
||||
|
||||
// Use on the fly compression?
|
||||
$GLOBALS['onfly_compression'] = $GLOBALS['cfg']['CompressOnFly']
|
||||
&& $compression === 'gzip';
|
||||
if ($GLOBALS['onfly_compression']) {
|
||||
$GLOBALS['memory_limit'] = $this->export->getMemoryLimit();
|
||||
}
|
||||
|
||||
// Generate filename and mime type if needed
|
||||
if ($asfile) {
|
||||
if (empty($remember_template)) {
|
||||
$remember_template = '';
|
||||
}
|
||||
|
||||
[$filename, $mime_type] = $this->export->getFilenameAndMimetype(
|
||||
$export_type,
|
||||
$remember_template,
|
||||
$export_plugin,
|
||||
$compression,
|
||||
$filename_template
|
||||
);
|
||||
} else {
|
||||
$mime_type = '';
|
||||
}
|
||||
|
||||
// For raw query export, filename will be export.extension
|
||||
if ($export_type === 'raw') {
|
||||
[$filename] = $this->export->getFinalFilenameAndMimetypeForFilename($export_plugin, $compression, 'export');
|
||||
}
|
||||
|
||||
// Open file on server if needed
|
||||
if ($save_on_server) {
|
||||
[$save_filename, $message, $file_handle] = $this->export->openFile($filename, $quick_export);
|
||||
|
||||
// problem opening export file on server?
|
||||
if (! empty($message)) {
|
||||
$this->export->showPage($export_type);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Send headers depending on whether the user chose to download a dump file
|
||||
* or not
|
||||
*/
|
||||
if ($asfile) {
|
||||
// Download
|
||||
// (avoid rewriting data containing HTML with anchors and forms;
|
||||
// this was reported to happen under Plesk)
|
||||
ini_set('url_rewriter.tags', '');
|
||||
$filename = Sanitize::sanitizeFilename($filename);
|
||||
|
||||
Core::downloadHeader($filename, $mime_type);
|
||||
} else {
|
||||
// HTML
|
||||
if ($export_type === 'database') {
|
||||
$num_tables = count($tables);
|
||||
if ($num_tables === 0) {
|
||||
$message = Message::error(
|
||||
__('No tables found in database.')
|
||||
);
|
||||
$active_page = Url::getFromRoute('/database/export');
|
||||
/** @var DatabaseExportController $controller */
|
||||
$controller = $containerBuilder->get(DatabaseExportController::class);
|
||||
$controller();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
[$html, $back_button, $refreshButton] = $this->export->getHtmlForDisplayedExportHeader(
|
||||
$export_type,
|
||||
$db,
|
||||
$table
|
||||
);
|
||||
echo $html;
|
||||
unset($html);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Re - initialize
|
||||
$this->export->dumpBuffer = '';
|
||||
$this->export->dumpBufferLength = 0;
|
||||
|
||||
// Add possibly some comments to export
|
||||
if (! $export_plugin->exportHeader()) {
|
||||
throw new ExportException('Failure during header export.');
|
||||
}
|
||||
|
||||
// Will we need relation & co. setup?
|
||||
$do_relation = isset($GLOBALS[$what . '_relation']);
|
||||
$do_comments = isset($GLOBALS[$what . '_include_comments'])
|
||||
|| isset($GLOBALS[$what . '_comments']);
|
||||
$do_mime = isset($GLOBALS[$what . '_mime']);
|
||||
|
||||
// Include dates in export?
|
||||
$do_dates = isset($GLOBALS[$what . '_dates']);
|
||||
|
||||
$whatStrucOrData = $GLOBALS[$what . '_structure_or_data'];
|
||||
|
||||
if ($export_type === 'raw') {
|
||||
$whatStrucOrData = 'raw';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the dump
|
||||
*/
|
||||
if ($export_type === 'server') {
|
||||
if (! isset($db_select)) {
|
||||
$db_select = '';
|
||||
}
|
||||
|
||||
$this->export->exportServer(
|
||||
$db_select,
|
||||
$whatStrucOrData,
|
||||
$export_plugin,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$export_type,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$do_dates,
|
||||
$aliases,
|
||||
$separate_files
|
||||
);
|
||||
} elseif ($export_type === 'database') {
|
||||
if (! isset($table_structure) || ! is_array($table_structure)) {
|
||||
$table_structure = [];
|
||||
}
|
||||
|
||||
if (! isset($table_data) || ! is_array($table_data)) {
|
||||
$table_data = [];
|
||||
}
|
||||
|
||||
if ($structureOrDataForced) {
|
||||
$table_structure = $tables;
|
||||
$table_data = $tables;
|
||||
}
|
||||
|
||||
if (isset($lock_tables)) {
|
||||
$this->export->lockTables($db, $tables, 'READ');
|
||||
try {
|
||||
$this->export->exportDatabase(
|
||||
$db,
|
||||
$tables,
|
||||
$whatStrucOrData,
|
||||
$table_structure,
|
||||
$table_data,
|
||||
$export_plugin,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$export_type,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$do_dates,
|
||||
$aliases,
|
||||
$separate_files
|
||||
);
|
||||
} finally {
|
||||
$this->export->unlockTables();
|
||||
}
|
||||
} else {
|
||||
$this->export->exportDatabase(
|
||||
$db,
|
||||
$tables,
|
||||
$whatStrucOrData,
|
||||
$table_structure,
|
||||
$table_data,
|
||||
$export_plugin,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$export_type,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$do_dates,
|
||||
$aliases,
|
||||
$separate_files
|
||||
);
|
||||
}
|
||||
} elseif ($export_type === 'raw') {
|
||||
Export::exportRaw($whatStrucOrData, $export_plugin, $crlf, $errorUrl, $db, $sql_query, $export_type);
|
||||
} else {
|
||||
// We export just one table
|
||||
// $allrows comes from the form when "Dump all rows" has been selected
|
||||
if (! isset($allrows)) {
|
||||
$allrows = '';
|
||||
}
|
||||
|
||||
if (! isset($limit_to)) {
|
||||
$limit_to = '0';
|
||||
}
|
||||
|
||||
if (! isset($limit_from)) {
|
||||
$limit_from = '0';
|
||||
}
|
||||
|
||||
if (isset($lock_tables)) {
|
||||
try {
|
||||
$this->export->lockTables($db, [$table], 'READ');
|
||||
$this->export->exportTable(
|
||||
$db,
|
||||
$table,
|
||||
$whatStrucOrData,
|
||||
$export_plugin,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$export_type,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$do_dates,
|
||||
$allrows,
|
||||
$limit_to,
|
||||
$limit_from,
|
||||
$sql_query,
|
||||
$aliases
|
||||
);
|
||||
} finally {
|
||||
$this->export->unlockTables();
|
||||
}
|
||||
} else {
|
||||
$this->export->exportTable(
|
||||
$db,
|
||||
$table,
|
||||
$whatStrucOrData,
|
||||
$export_plugin,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$export_type,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$do_dates,
|
||||
$allrows,
|
||||
$limit_to,
|
||||
$limit_from,
|
||||
$sql_query,
|
||||
$aliases
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! $export_plugin->exportFooter()) {
|
||||
throw new ExportException('Failure during footer export.');
|
||||
}
|
||||
} catch (ExportException $e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
if ($save_on_server && ! empty($message)) {
|
||||
$this->export->showPage($export_type);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the dump as a file...
|
||||
*/
|
||||
if (empty($asfile)) {
|
||||
echo $this->export->getHtmlForDisplayedExportFooter($back_button, $refreshButton);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the charset if required.
|
||||
if ($output_charset_conversion) {
|
||||
$this->export->dumpBuffer = Encoding::convertString(
|
||||
'utf-8',
|
||||
$GLOBALS['charset'],
|
||||
$this->export->dumpBuffer
|
||||
);
|
||||
}
|
||||
|
||||
// Compression needed?
|
||||
if ($compression) {
|
||||
if (! empty($separate_files)) {
|
||||
$this->export->dumpBuffer = $this->export->compress(
|
||||
$this->export->dumpBufferObjects,
|
||||
$compression,
|
||||
$filename
|
||||
);
|
||||
} else {
|
||||
$this->export->dumpBuffer = $this->export->compress($this->export->dumpBuffer, $compression, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we saved on server, we have to close file now */
|
||||
if ($save_on_server) {
|
||||
$message = $this->export->closeFile($file_handle, $this->export->dumpBuffer, $save_filename);
|
||||
$this->export->showPage($export_type);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
echo $this->export->dumpBuffer;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\ExportController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
|
||||
final class TablesController extends AbstractController
|
||||
{
|
||||
/** @var ExportController */
|
||||
private $exportController;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, ExportController $exportController)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->exportController = $exportController;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
if (empty($_POST['selected_tbl'])) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', __('No table selected.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
($this->exportController)();
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export\Template;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Export\Template as ExportTemplate;
|
||||
use PhpMyAdmin\Export\TemplateModel;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function is_array;
|
||||
|
||||
final class CreateController extends AbstractController
|
||||
{
|
||||
/** @var TemplateModel */
|
||||
private $model;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
TemplateModel $model,
|
||||
Relation $relation
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->model = $model;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
/** @var string $exportType */
|
||||
$exportType = $request->getParsedBodyParam('exportType', '');
|
||||
/** @var string $templateName */
|
||||
$templateName = $request->getParsedBodyParam('templateName', '');
|
||||
/** @var string $templateData */
|
||||
$templateData = $request->getParsedBodyParam('templateData', '');
|
||||
/** @var string|null $templateId */
|
||||
$templateId = $request->getParsedBodyParam('template_id');
|
||||
|
||||
$exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature;
|
||||
if ($exportTemplatesFeature === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$template = ExportTemplate::fromArray([
|
||||
'username' => $cfg['Server']['user'],
|
||||
'exportType' => $exportType,
|
||||
'name' => $templateName,
|
||||
'data' => $templateData,
|
||||
]);
|
||||
$result = $this->model->create(
|
||||
$exportTemplatesFeature->database,
|
||||
$exportTemplatesFeature->exportTemplates,
|
||||
$template
|
||||
);
|
||||
|
||||
if ($result !== '') {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$templates = $this->model->getAll(
|
||||
$exportTemplatesFeature->database,
|
||||
$exportTemplatesFeature->exportTemplates,
|
||||
$template->getUsername(),
|
||||
$template->getExportType()
|
||||
);
|
||||
|
||||
$this->response->setRequestStatus(true);
|
||||
$this->response->addJSON(
|
||||
'data',
|
||||
$this->template->render('export/template_options', [
|
||||
'templates' => is_array($templates) ? $templates : [],
|
||||
'selected_template' => $templateId,
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export\Template;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Export\TemplateModel;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
final class DeleteController extends AbstractController
|
||||
{
|
||||
/** @var TemplateModel */
|
||||
private $model;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
TemplateModel $model,
|
||||
Relation $relation
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->model = $model;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$templateId = (int) $request->getParsedBodyParam('templateId');
|
||||
|
||||
$exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature;
|
||||
if ($exportTemplatesFeature === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->model->delete(
|
||||
$exportTemplatesFeature->database,
|
||||
$exportTemplatesFeature->exportTemplates,
|
||||
$cfg['Server']['user'],
|
||||
$templateId
|
||||
);
|
||||
|
||||
if ($result !== '') {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->setRequestStatus(true);
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export\Template;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Export\Template as ExportTemplate;
|
||||
use PhpMyAdmin\Export\TemplateModel;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
final class LoadController extends AbstractController
|
||||
{
|
||||
/** @var TemplateModel */
|
||||
private $model;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
TemplateModel $model,
|
||||
Relation $relation
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->model = $model;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$templateId = (int) $request->getParsedBodyParam('templateId');
|
||||
|
||||
$exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature;
|
||||
if ($exportTemplatesFeature === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$template = $this->model->load(
|
||||
$exportTemplatesFeature->database,
|
||||
$exportTemplatesFeature->exportTemplates,
|
||||
$cfg['Server']['user'],
|
||||
$templateId
|
||||
);
|
||||
|
||||
if (! $template instanceof ExportTemplate) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $template);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->setRequestStatus(true);
|
||||
$this->response->addJSON('data', $template->getData());
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Export\Template;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Export\Template as ExportTemplate;
|
||||
use PhpMyAdmin\Export\TemplateModel;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
final class UpdateController extends AbstractController
|
||||
{
|
||||
/** @var TemplateModel */
|
||||
private $model;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
TemplateModel $model,
|
||||
Relation $relation
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->model = $model;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$templateId = (int) $request->getParsedBodyParam('templateId');
|
||||
/** @var string $templateData */
|
||||
$templateData = $request->getParsedBodyParam('templateData', '');
|
||||
|
||||
$exportTemplatesFeature = $this->relation->getRelationParameters()->exportTemplatesFeature;
|
||||
if ($exportTemplatesFeature === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$template = ExportTemplate::fromArray([
|
||||
'id' => $templateId,
|
||||
'username' => $cfg['Server']['user'],
|
||||
'data' => $templateData,
|
||||
]);
|
||||
$result = $this->model->update(
|
||||
$exportTemplatesFeature->database,
|
||||
$exportTemplatesFeature->exportTemplates,
|
||||
$template
|
||||
);
|
||||
|
||||
if ($result !== '') {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->setRequestStatus(true);
|
||||
}
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Editor for Geometry data types.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Gis\GisFactory;
|
||||
use PhpMyAdmin\Gis\GisVisualization;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
|
||||
use function array_merge;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function mb_strpos;
|
||||
use function mb_strtoupper;
|
||||
use function mb_substr;
|
||||
use function substr;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Editor for Geometry data types.
|
||||
*/
|
||||
class GisDataEditorController extends AbstractController
|
||||
{
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
global $gis_data, $gis_types, $start, $geom_type, $gis_obj, $srid, $wkt, $wkt_with_zero;
|
||||
global $result, $visualizationSettings, $data, $visualization, $open_layers, $geom_count, $dbi;
|
||||
|
||||
/** @var string|null $field */
|
||||
$field = $request->getParsedBodyParam('field');
|
||||
/** @var array|null $gisDataParam */
|
||||
$gisDataParam = $request->getParsedBodyParam('gis_data');
|
||||
/** @var string $type */
|
||||
$type = $request->getParsedBodyParam('type', '');
|
||||
/** @var string|null $value */
|
||||
$value = $request->getParsedBodyParam('value');
|
||||
/** @var string|null $generate */
|
||||
$generate = $request->getParsedBodyParam('generate');
|
||||
/** @var string|null $inputName */
|
||||
$inputName = $request->getParsedBodyParam('input_name');
|
||||
|
||||
if (! isset($field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get data if any posted
|
||||
$gis_data = [];
|
||||
if (is_array($gisDataParam)) {
|
||||
$gis_data = $gisDataParam;
|
||||
}
|
||||
|
||||
$gis_types = [
|
||||
'POINT',
|
||||
'MULTIPOINT',
|
||||
'LINESTRING',
|
||||
'MULTILINESTRING',
|
||||
'POLYGON',
|
||||
'MULTIPOLYGON',
|
||||
'GEOMETRYCOLLECTION',
|
||||
];
|
||||
|
||||
// Extract type from the initial call and make sure that it's a valid one.
|
||||
// Extract from field's values if available, if not use the column type passed.
|
||||
if (! isset($gis_data['gis_type'])) {
|
||||
if ($type !== '') {
|
||||
$gis_data['gis_type'] = mb_strtoupper($type);
|
||||
}
|
||||
|
||||
if (isset($value) && trim($value) !== '') {
|
||||
$start = substr($value, 0, 1) == "'" ? 1 : 0;
|
||||
$gis_data['gis_type'] = mb_substr($value, $start, (int) mb_strpos($value, '(') - $start);
|
||||
}
|
||||
|
||||
if (! isset($gis_data['gis_type']) || (! in_array($gis_data['gis_type'], $gis_types))) {
|
||||
$gis_data['gis_type'] = $gis_types[0];
|
||||
}
|
||||
}
|
||||
|
||||
$geom_type = $gis_data['gis_type'];
|
||||
|
||||
// Generate parameters from value passed.
|
||||
$gis_obj = GisFactory::factory($geom_type);
|
||||
if ($gis_obj === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($value)) {
|
||||
$gis_data = array_merge(
|
||||
$gis_data,
|
||||
$gis_obj->generateParams($value)
|
||||
);
|
||||
}
|
||||
|
||||
// Generate Well Known Text
|
||||
$srid = isset($gis_data['srid']) && $gis_data['srid'] != '' ? (int) $gis_data['srid'] : 0;
|
||||
$wkt = $gis_obj->generateWkt($gis_data, 0);
|
||||
$wkt_with_zero = $gis_obj->generateWkt($gis_data, 0, '0');
|
||||
$result = "'" . $wkt . "'," . $srid;
|
||||
|
||||
// Generate SVG based visualization
|
||||
$visualizationSettings = [
|
||||
'width' => 450,
|
||||
'height' => 300,
|
||||
'spatialColumn' => 'wkt',
|
||||
'mysqlVersion' => $dbi->getVersion(),
|
||||
'isMariaDB' => $dbi->isMariaDB(),
|
||||
];
|
||||
$data = [
|
||||
[
|
||||
'wkt' => $wkt_with_zero,
|
||||
'srid' => $srid,
|
||||
],
|
||||
];
|
||||
$visualization = GisVisualization::getByData($data, $visualizationSettings)
|
||||
->toImage('svg');
|
||||
|
||||
$open_layers = GisVisualization::getByData($data, $visualizationSettings)
|
||||
->asOl();
|
||||
|
||||
// If the call is to update the WKT and visualization make an AJAX response
|
||||
if ($generate) {
|
||||
$this->response->addJSON([
|
||||
'result' => $result,
|
||||
'visualization' => $visualization,
|
||||
'openLayers' => $open_layers,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$geom_count = 1;
|
||||
if ($geom_type === 'GEOMETRYCOLLECTION') {
|
||||
$geom_count = isset($gis_data[$geom_type]['geom_count'])
|
||||
? intval($gis_data[$geom_type]['geom_count']) : 1;
|
||||
if (isset($gis_data[$geom_type]['add_geom'])) {
|
||||
$geom_count++;
|
||||
}
|
||||
}
|
||||
|
||||
$templateOutput = $this->template->render('gis_data_editor_form', [
|
||||
'width' => $visualizationSettings['width'],
|
||||
'height' => $visualizationSettings['height'],
|
||||
'field' => $field,
|
||||
'input_name' => $inputName,
|
||||
'srid' => $srid,
|
||||
'visualization' => $visualization,
|
||||
'open_layers' => $open_layers,
|
||||
'gis_types' => $gis_types,
|
||||
'geom_type' => $geom_type,
|
||||
'geom_count' => $geom_count,
|
||||
'gis_data' => $gis_data,
|
||||
'result' => $result,
|
||||
]);
|
||||
|
||||
$this->response->addJSON(['gis_editor' => $templateOutput]);
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Git;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function strtotime;
|
||||
|
||||
final class GitInfoController extends AbstractController
|
||||
{
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Config $config)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$git = new Git($this->config->get('ShowGitRevision') ?? true);
|
||||
|
||||
if (! $git->isGitRevision()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$commit = $git->checkGitRevision();
|
||||
|
||||
if (! $git->hasGitInformation() || $commit === null) {
|
||||
$this->response->setRequestStatus(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$commit['author']['date'] = Util::localisedDate(strtotime($commit['author']['date']));
|
||||
$commit['committer']['date'] = Util::localisedDate(strtotime($commit['committer']['date']));
|
||||
|
||||
$this->render('home/git_info', $commit);
|
||||
}
|
||||
}
|
|
@ -1,463 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Git;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\LanguageManager;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\RecentFavoriteTable;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Select;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\ThemeManager;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Version;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function extension_loaded;
|
||||
use function file_exists;
|
||||
use function ini_get;
|
||||
use function mb_strlen;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
|
||||
use const PHP_VERSION;
|
||||
use const SODIUM_CRYPTO_SECRETBOX_KEYBYTES;
|
||||
|
||||
class HomeController extends AbstractController
|
||||
{
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
/** @var ThemeManager */
|
||||
private $themeManager;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* @var array<int, array<string, string>>
|
||||
* @psalm-var list<array{message: string, severity: 'warning'|'notice'}>
|
||||
*/
|
||||
private $errors = [];
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Config $config,
|
||||
ThemeManager $themeManager,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->config = $config;
|
||||
$this->themeManager = $themeManager;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $server, $collation_connection, $message, $show_query, $db, $table, $errorUrl;
|
||||
|
||||
if ($this->response->isAjax() && ! empty($_REQUEST['access_time'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['home.js']);
|
||||
|
||||
// This is for $cfg['ShowDatabasesNavigationAsTree'] = false;
|
||||
// See: https://github.com/phpmyadmin/phpmyadmin/issues/16520
|
||||
// The DB is defined here and sent to the JS front-end to refresh the DB tree
|
||||
$db = $_POST['db'] ?? '';
|
||||
$table = '';
|
||||
$show_query = '1';
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($server > 0 && $this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$languageManager = LanguageManager::getInstance();
|
||||
|
||||
if (! empty($message)) {
|
||||
$displayMessage = Generator::getMessage($message);
|
||||
unset($message);
|
||||
}
|
||||
|
||||
if (isset($_SESSION['partial_logout'])) {
|
||||
$partialLogout = Message::success(__(
|
||||
'You were logged out from one server, to logout completely '
|
||||
. 'from phpMyAdmin, you need to logout from all servers.'
|
||||
))->getDisplay();
|
||||
unset($_SESSION['partial_logout']);
|
||||
}
|
||||
|
||||
$syncFavoriteTables = RecentFavoriteTable::getInstance('favorite')
|
||||
->getHtmlSyncFavoriteTables();
|
||||
|
||||
$hasServer = $server > 0 || count($cfg['Servers']) > 1;
|
||||
if ($hasServer) {
|
||||
$hasServerSelection = $cfg['ServerDefault'] == 0
|
||||
|| (! $cfg['NavigationDisplayServers']
|
||||
&& (count($cfg['Servers']) > 1
|
||||
|| ($server == 0 && count($cfg['Servers']) === 1)));
|
||||
if ($hasServerSelection) {
|
||||
$serverSelection = Select::render(true, true);
|
||||
}
|
||||
|
||||
if ($server > 0) {
|
||||
$checkUserPrivileges = new CheckUserPrivileges($this->dbi);
|
||||
$checkUserPrivileges->getPrivileges();
|
||||
|
||||
$charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$charsetsList = [];
|
||||
foreach ($charsets as $charset) {
|
||||
$collationsList = [];
|
||||
foreach ($collations[$charset->getName()] as $collation) {
|
||||
$collationsList[] = [
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
'is_selected' => $collation_connection === $collation->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
$charsetsList[] = [
|
||||
'name' => $charset->getName(),
|
||||
'description' => $charset->getDescription(),
|
||||
'collations' => $collationsList,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$availableLanguages = [];
|
||||
if (empty($cfg['Lang']) && $languageManager->hasChoice()) {
|
||||
$availableLanguages = $languageManager->sortedLanguages();
|
||||
}
|
||||
|
||||
$databaseServer = [];
|
||||
if ($server > 0 && $cfg['ShowServerInfo']) {
|
||||
$hostInfo = '';
|
||||
if (! empty($cfg['Server']['verbose'])) {
|
||||
$hostInfo .= $cfg['Server']['verbose'];
|
||||
$hostInfo .= ' (';
|
||||
}
|
||||
|
||||
$hostInfo .= $this->dbi->getHostInfo();
|
||||
|
||||
if (! empty($cfg['Server']['verbose'])) {
|
||||
$hostInfo .= ')';
|
||||
}
|
||||
|
||||
$serverCharset = Charsets::getServerCharset($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$databaseServer = [
|
||||
'host' => $hostInfo,
|
||||
'type' => Util::getServerType(),
|
||||
'connection' => Generator::getServerSSL(),
|
||||
'version' => $this->dbi->getVersionString() . ' - ' . $this->dbi->getVersionComment(),
|
||||
'protocol' => $this->dbi->getProtoInfo(),
|
||||
'user' => $this->dbi->fetchValue('SELECT USER();'),
|
||||
'charset' => $serverCharset->getDescription() . ' (' . $serverCharset->getName() . ')',
|
||||
];
|
||||
}
|
||||
|
||||
$webServer = [];
|
||||
if ($cfg['ShowServerInfo']) {
|
||||
$webServer['software'] = $_SERVER['SERVER_SOFTWARE'] ?? null;
|
||||
|
||||
if ($server > 0) {
|
||||
$clientVersion = $this->dbi->getClientInfo();
|
||||
if (preg_match('#\d+\.\d+\.\d+#', $clientVersion)) {
|
||||
$clientVersion = 'libmysql - ' . $clientVersion;
|
||||
}
|
||||
|
||||
$webServer['database'] = $clientVersion;
|
||||
$webServer['php_extensions'] = Util::listPHPExtensions();
|
||||
$webServer['php_version'] = PHP_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
$relation = new Relation($this->dbi);
|
||||
if ($server > 0) {
|
||||
$relationParameters = $relation->getRelationParameters();
|
||||
if (! $relationParameters->hasAllFeatures() && $cfg['PmaNoRelation_DisableWarning'] == false) {
|
||||
$messageText = __(
|
||||
'The phpMyAdmin configuration storage is not completely '
|
||||
. 'configured, some extended features have been deactivated. '
|
||||
. '%sFind out why%s. '
|
||||
);
|
||||
if ($cfg['ZeroConf'] == true) {
|
||||
$messageText .= '<br>' .
|
||||
__('Or alternately go to \'Operations\' tab of any database to set it up there.');
|
||||
}
|
||||
|
||||
$messageInstance = Message::notice($messageText);
|
||||
$messageInstance->addParamHtml(
|
||||
'<a href="' . Url::getFromRoute('/check-relations')
|
||||
. '" data-post="' . Url::getCommon() . '">'
|
||||
);
|
||||
$messageInstance->addParamHtml('</a>');
|
||||
/* Show error if user has configured something, notice elsewhere */
|
||||
if (! empty($cfg['Servers'][$server]['pmadb'])) {
|
||||
$messageInstance->isError(true);
|
||||
}
|
||||
|
||||
$configStorageMessage = $messageInstance->getDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
$this->checkRequirements();
|
||||
|
||||
$git = new Git($this->config->get('ShowGitRevision') ?? true);
|
||||
|
||||
$this->render('home/index', [
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'message' => $displayMessage ?? '',
|
||||
'partial_logout' => $partialLogout ?? '',
|
||||
'is_git_revision' => $git->isGitRevision(),
|
||||
'server' => $server,
|
||||
'sync_favorite_tables' => $syncFavoriteTables,
|
||||
'has_server' => $hasServer,
|
||||
'is_demo' => $cfg['DBG']['demo'],
|
||||
'has_server_selection' => $hasServerSelection ?? false,
|
||||
'server_selection' => $serverSelection ?? '',
|
||||
'has_change_password_link' => ($cfg['Server']['auth_type'] ?? '') !== 'config' && $cfg['ShowChgPassword'],
|
||||
'charsets' => $charsetsList ?? [],
|
||||
'available_languages' => $availableLanguages,
|
||||
'database_server' => $databaseServer,
|
||||
'web_server' => $webServer,
|
||||
'show_php_info' => $cfg['ShowPhpInfo'],
|
||||
'is_version_checked' => $cfg['VersionCheck'],
|
||||
'phpmyadmin_version' => Version::VERSION,
|
||||
'phpmyadmin_major_version' => Version::SERIES,
|
||||
'config_storage_message' => $configStorageMessage ?? '',
|
||||
'has_theme_manager' => $cfg['ThemeManager'],
|
||||
'themes' => $this->themeManager->getThemesArray(),
|
||||
'errors' => $this->errors,
|
||||
]);
|
||||
}
|
||||
|
||||
private function checkRequirements(): void
|
||||
{
|
||||
global $cfg, $server;
|
||||
|
||||
$this->checkPhpExtensionsRequirements();
|
||||
|
||||
if ($cfg['LoginCookieValidityDisableWarning'] == false) {
|
||||
/**
|
||||
* Check whether session.gc_maxlifetime limits session validity.
|
||||
*/
|
||||
$gc_time = (int) ini_get('session.gc_maxlifetime');
|
||||
if ($gc_time < $cfg['LoginCookieValidity']) {
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'Your PHP parameter [a@https://www.php.net/manual/en/session.' .
|
||||
'configuration.php#ini.session.gc-maxlifetime@_blank]session.' .
|
||||
'gc_maxlifetime[/a] is lower than cookie validity configured ' .
|
||||
'in phpMyAdmin, because of this, your login might expire sooner ' .
|
||||
'than configured in phpMyAdmin.'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether LoginCookieValidity is limited by LoginCookieStore.
|
||||
*/
|
||||
if ($cfg['LoginCookieStore'] != 0 && $cfg['LoginCookieStore'] < $cfg['LoginCookieValidity']) {
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'Login cookie store is lower than cookie validity configured in ' .
|
||||
'phpMyAdmin, because of this, your login will expire sooner than ' .
|
||||
'configured in phpMyAdmin.'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning if using the default MySQL controluser account
|
||||
*/
|
||||
if (
|
||||
isset($cfg['Server']['controluser'], $cfg['Server']['controlpass'])
|
||||
&& $server != 0
|
||||
&& $cfg['Server']['controluser'] === 'pma'
|
||||
&& $cfg['Server']['controlpass'] === 'pmapass'
|
||||
) {
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'Your server is running with default values for the ' .
|
||||
'controluser and password (controlpass) and is open to ' .
|
||||
'intrusion; you really should fix this security weakness' .
|
||||
' by changing the password for controluser \'pma\'.'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user does not have defined blowfish secret and it is being used.
|
||||
*/
|
||||
if (! empty($_SESSION['encryption_key'])) {
|
||||
$encryptionKeyLength = mb_strlen($cfg['blowfish_secret'], '8bit');
|
||||
if ($encryptionKeyLength < SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'The configuration file needs a valid key for cookie encryption.'
|
||||
. ' A temporary key was automatically generated for you.'
|
||||
. ' Please refer to the [doc@cfg_blowfish_secret]documentation[/doc].'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
} elseif ($encryptionKeyLength > SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
|
||||
$this->errors[] = [
|
||||
'message' => sprintf(
|
||||
__(
|
||||
'The cookie encryption key in the configuration file is longer than necessary.'
|
||||
. ' It should only be %d bytes long.'
|
||||
. ' Please refer to the [doc@cfg_blowfish_secret]documentation[/doc].'
|
||||
),
|
||||
SODIUM_CRYPTO_SECRETBOX_KEYBYTES
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for existence of config directory which should not exist in
|
||||
* production environment.
|
||||
*/
|
||||
if (@file_exists(ROOT_PATH . 'config')) {
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'Directory [code]config[/code], which is used by the setup script, ' .
|
||||
'still exists in your phpMyAdmin directory. It is strongly ' .
|
||||
'recommended to remove it once phpMyAdmin has been configured. ' .
|
||||
'Otherwise the security of your server may be compromised by ' .
|
||||
'unauthorized people downloading your configuration.'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning about Suhosin only if its simulation mode is not enabled
|
||||
*/
|
||||
if (
|
||||
$cfg['SuhosinDisableWarning'] == false
|
||||
&& ini_get('suhosin.request.max_value_length')
|
||||
&& ini_get('suhosin.simulation') == '0'
|
||||
) {
|
||||
$this->errors[] = [
|
||||
'message' => sprintf(
|
||||
__(
|
||||
'Server running with Suhosin. Please refer to %sdocumentation%s for possible issues.'
|
||||
),
|
||||
'[doc@faq1-38]',
|
||||
'[/doc]'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
/* Missing template cache */
|
||||
if ($this->config->getTempDir('twig') === null) {
|
||||
$this->errors[] = [
|
||||
'message' => sprintf(
|
||||
__(
|
||||
'The $cfg[\'TempDir\'] (%s) is not accessible. ' .
|
||||
'phpMyAdmin is not able to cache templates and will ' .
|
||||
'be slow because of this.'
|
||||
),
|
||||
$this->config->get('TempDir')
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
$this->checkLanguageStats();
|
||||
}
|
||||
|
||||
private function checkLanguageStats(): void
|
||||
{
|
||||
global $cfg, $lang;
|
||||
|
||||
/**
|
||||
* Warning about incomplete translations.
|
||||
*
|
||||
* The data file is created while creating release by ./scripts/remove-incomplete-mo
|
||||
*/
|
||||
if (! @file_exists(ROOT_PATH . 'libraries/language_stats.inc.php')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @psalm-suppress MissingFile */
|
||||
include ROOT_PATH . 'libraries/language_stats.inc.php';
|
||||
/*
|
||||
* This message is intentionally not translated, because we're
|
||||
* handling incomplete translations here and focus on english
|
||||
* speaking users.
|
||||
*/
|
||||
if (
|
||||
! isset($GLOBALS['language_stats'][$lang])
|
||||
|| $GLOBALS['language_stats'][$lang] >= $cfg['TranslationWarningThreshold']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->errors[] = [
|
||||
'message' => 'You are using an incomplete translation, please help to make it '
|
||||
. 'better by [a@https://www.phpmyadmin.net/translate/'
|
||||
. '@_blank]contributing[/a].',
|
||||
'severity' => 'notice',
|
||||
];
|
||||
}
|
||||
|
||||
private function checkPhpExtensionsRequirements(): void
|
||||
{
|
||||
/**
|
||||
* mbstring is used for handling multibytes inside parser, so it is good
|
||||
* to tell user something might be broken without it, see bug #1063149.
|
||||
*/
|
||||
if (! extension_loaded('mbstring')) {
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'The mbstring PHP extension was not found and you seem to be using'
|
||||
. ' a multibyte charset. Without the mbstring extension phpMyAdmin'
|
||||
. ' is unable to split strings correctly and it may result in'
|
||||
. ' unexpected results.'
|
||||
),
|
||||
'severity' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Missing functionality
|
||||
*/
|
||||
if (extension_loaded('curl') || ini_get('allow_url_fopen')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->errors[] = [
|
||||
'message' => __(
|
||||
'The curl extension was not found and allow_url_fopen is '
|
||||
. 'disabled. Due to this some features such as error reporting '
|
||||
. 'or version check are disabled.'
|
||||
),
|
||||
'severity' => 'notice',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,826 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Import;
|
||||
|
||||
use PhpMyAdmin\Bookmark;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Console;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\File;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Import;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ParseAnalyze;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Plugins\ImportPlugin;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Sql;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
use Throwable;
|
||||
|
||||
use function __;
|
||||
use function _ngettext;
|
||||
use function in_array;
|
||||
use function ini_get;
|
||||
use function ini_set;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function is_link;
|
||||
use function is_numeric;
|
||||
use function is_string;
|
||||
use function is_uploaded_file;
|
||||
use function mb_strlen;
|
||||
use function mb_strtolower;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function preg_replace;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use function time;
|
||||
use function trim;
|
||||
|
||||
final class ImportController extends AbstractController
|
||||
{
|
||||
/** @var Import */
|
||||
private $import;
|
||||
|
||||
/** @var Sql */
|
||||
private $sql;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Import $import,
|
||||
Sql $sql,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->import = $import;
|
||||
$this->sql = $sql;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $collation_connection, $db, $import_type, $table, $goto, $display_query;
|
||||
global $format, $local_import_file, $ajax_reload, $import_text, $sql_query, $message, $errorUrl, $urlParams;
|
||||
global $memory_limit, $read_limit, $finished, $offset, $charset_conversion, $charset_of_file;
|
||||
global $timestamp, $maximum_time, $timeout_passed, $import_file, $go_sql, $sql_file, $error, $max_sql_len, $msg;
|
||||
global $sql_query_disabled, $executed_queries, $run_query, $reset_charset;
|
||||
global $result, $import_file_name, $sql_data, $import_notice, $read_multiply, $my_die, $active_page;
|
||||
global $show_as_php, $reload, $charset_connection, $is_js_confirmed, $MAX_FILE_SIZE, $message_to_show;
|
||||
global $noplugin, $skip_queries;
|
||||
|
||||
$charset_of_file = $_POST['charset_of_file'] ?? null;
|
||||
$format = $_POST['format'] ?? '';
|
||||
$import_type = $_POST['import_type'] ?? null;
|
||||
$is_js_confirmed = $_POST['is_js_confirmed'] ?? null;
|
||||
$MAX_FILE_SIZE = $_POST['MAX_FILE_SIZE'] ?? null;
|
||||
$message_to_show = $_POST['message_to_show'] ?? null;
|
||||
$noplugin = $_POST['noplugin'] ?? null;
|
||||
$skip_queries = $_POST['skip_queries'] ?? null;
|
||||
$local_import_file = $_POST['local_import_file'] ?? null;
|
||||
$show_as_php = $_POST['show_as_php'] ?? null;
|
||||
|
||||
// If it's a refresh console bookmarks request
|
||||
if (isset($_GET['console_bookmark_refresh'])) {
|
||||
$this->response->addJSON(
|
||||
'console_message_bookmark',
|
||||
Console::getBookmarkContent()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a console bookmark add request
|
||||
if (isset($_POST['console_bookmark_add'])) {
|
||||
if (! isset($_POST['label'], $_POST['db'], $_POST['bookmark_query'], $_POST['shared'])) {
|
||||
$this->response->addJSON('message', __('Incomplete params'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$bookmarkFields = [
|
||||
'bkm_database' => $_POST['db'],
|
||||
'bkm_user' => $cfg['Server']['user'],
|
||||
'bkm_sql_query' => $_POST['bookmark_query'],
|
||||
'bkm_label' => $_POST['label'],
|
||||
];
|
||||
$isShared = ($_POST['shared'] === 'true');
|
||||
$bookmark = Bookmark::createBookmark($this->dbi, $bookmarkFields, $isShared);
|
||||
if ($bookmark !== false && $bookmark->save()) {
|
||||
$this->response->addJSON('message', __('Succeeded'));
|
||||
$this->response->addJSON('data', $bookmarkFields);
|
||||
$this->response->addJSON('isShared', $isShared);
|
||||
} else {
|
||||
$this->response->addJSON('message', __('Failed'));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// reset import messages for ajax request
|
||||
$_SESSION['Import_message']['message'] = null;
|
||||
$_SESSION['Import_message']['go_back_url'] = null;
|
||||
// default values
|
||||
$reload = false;
|
||||
|
||||
// Use to identify current cycle is executing
|
||||
// a multiquery statement or stored routine
|
||||
if (! isset($_SESSION['is_multi_query'])) {
|
||||
$_SESSION['is_multi_query'] = false;
|
||||
}
|
||||
|
||||
$ajax_reload = [];
|
||||
$import_text = '';
|
||||
// Are we just executing plain query or sql file?
|
||||
// (eg. non import, but query box/window run)
|
||||
if (! empty($sql_query)) {
|
||||
// apply values for parameters
|
||||
if (! empty($_POST['parameterized']) && ! empty($_POST['parameters']) && is_array($_POST['parameters'])) {
|
||||
$parameters = $_POST['parameters'];
|
||||
foreach ($parameters as $parameter => $replacementValue) {
|
||||
if (! is_numeric($replacementValue)) {
|
||||
$replacementValue = '\'' . $this->dbi->escapeString($replacementValue) . '\'';
|
||||
}
|
||||
|
||||
$quoted = preg_quote($parameter, '/');
|
||||
// making sure that :param does not apply values to :param1
|
||||
$sql_query = preg_replace(
|
||||
'/' . $quoted . '([^a-zA-Z0-9_])/',
|
||||
$replacementValue . '${1}',
|
||||
$sql_query
|
||||
);
|
||||
// for parameters the appear at the end of the string
|
||||
$sql_query = preg_replace('/' . $quoted . '$/', $replacementValue, $sql_query);
|
||||
}
|
||||
}
|
||||
|
||||
// run SQL query
|
||||
$import_text = $sql_query;
|
||||
$import_type = 'query';
|
||||
$format = 'sql';
|
||||
$_SESSION['sql_from_query_box'] = true;
|
||||
|
||||
// If there is a request to ROLLBACK when finished.
|
||||
if (isset($_POST['rollback_query'])) {
|
||||
$this->import->handleRollbackRequest($import_text);
|
||||
}
|
||||
|
||||
// refresh navigation and main panels
|
||||
if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)) {
|
||||
$reload = true;
|
||||
$ajax_reload['reload'] = true;
|
||||
}
|
||||
|
||||
// refresh navigation panel only
|
||||
if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)) {
|
||||
$ajax_reload['reload'] = true;
|
||||
}
|
||||
|
||||
// do a dynamic reload if table is RENAMED
|
||||
// (by sending the instruction to the AJAX response handler)
|
||||
if (preg_match('/^RENAME\s+TABLE\s+(.*?)\s+TO\s+(.*?)($|;|\s)/i', $sql_query, $rename_table_names)) {
|
||||
$ajax_reload['reload'] = true;
|
||||
$ajax_reload['table_name'] = Util::unQuote($rename_table_names[2]);
|
||||
}
|
||||
|
||||
$sql_query = '';
|
||||
} elseif (! empty($sql_file)) {
|
||||
// run uploaded SQL file
|
||||
$import_file = $sql_file;
|
||||
$import_type = 'queryfile';
|
||||
$format = 'sql';
|
||||
unset($sql_file);
|
||||
} elseif (! empty($_POST['id_bookmark'])) {
|
||||
// run bookmark
|
||||
$import_type = 'query';
|
||||
$format = 'sql';
|
||||
}
|
||||
|
||||
// If we didn't get any parameters, either user called this directly, or
|
||||
// upload limit has been reached, let's assume the second possibility.
|
||||
if ($_POST == [] && $_GET == []) {
|
||||
$message = Message::error(
|
||||
__(
|
||||
'You probably tried to upload a file that is too large. Please refer ' .
|
||||
'to %sdocumentation%s for a workaround for this limit.'
|
||||
)
|
||||
);
|
||||
$message->addParam('[doc@faq1-16]');
|
||||
$message->addParam('[/doc]');
|
||||
|
||||
// so we can obtain the message
|
||||
$_SESSION['Import_message']['message'] = $message->getDisplay();
|
||||
$_SESSION['Import_message']['go_back_url'] = $goto;
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $message);
|
||||
|
||||
return; // the footer is displayed automatically
|
||||
}
|
||||
|
||||
// Add console message id to response output
|
||||
if (isset($_POST['console_message_id'])) {
|
||||
$this->response->addJSON('console_message_id', $_POST['console_message_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets globals from $_POST patterns, for import plugins
|
||||
* We only need to load the selected plugin
|
||||
*/
|
||||
|
||||
if (! in_array($format, ['csv', 'ldi', 'mediawiki', 'ods', 'shp', 'sql', 'xml'])) {
|
||||
// this should not happen for a normal user
|
||||
// but only during an attack
|
||||
Core::fatalError('Incorrect format parameter');
|
||||
}
|
||||
|
||||
$post_patterns = [
|
||||
'/^force_file_/',
|
||||
'/^' . $format . '_/',
|
||||
];
|
||||
|
||||
Core::setPostAsGlobal($post_patterns);
|
||||
|
||||
// Check needed parameters
|
||||
Util::checkParameters(['import_type', 'format']);
|
||||
|
||||
// We don't want anything special in format
|
||||
$format = Core::securePath($format);
|
||||
|
||||
if (strlen($table) > 0 && strlen($db) > 0) {
|
||||
$urlParams = [
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
];
|
||||
} elseif (strlen($db) > 0) {
|
||||
$urlParams = ['db' => $db];
|
||||
} else {
|
||||
$urlParams = [];
|
||||
}
|
||||
|
||||
// Create error and goto url
|
||||
if ($import_type === 'table') {
|
||||
$goto = Url::getFromRoute('/table/import');
|
||||
} elseif ($import_type === 'database') {
|
||||
$goto = Url::getFromRoute('/database/import');
|
||||
} elseif ($import_type === 'server') {
|
||||
$goto = Url::getFromRoute('/server/import');
|
||||
} elseif (empty($goto) || ! preg_match('@^index\.php$@i', $goto)) {
|
||||
if (strlen($table) > 0 && strlen($db) > 0) {
|
||||
$goto = Url::getFromRoute('/table/structure');
|
||||
} elseif (strlen($db) > 0) {
|
||||
$goto = Url::getFromRoute('/database/structure');
|
||||
} else {
|
||||
$goto = Url::getFromRoute('/server/sql');
|
||||
}
|
||||
}
|
||||
|
||||
$errorUrl = $goto . Url::getCommon($urlParams, '&');
|
||||
$_SESSION['Import_message']['go_back_url'] = $errorUrl;
|
||||
|
||||
if (strlen($db) > 0) {
|
||||
$this->dbi->selectDb($db);
|
||||
}
|
||||
|
||||
Util::setTimeLimit();
|
||||
if (! empty($cfg['MemoryLimit'])) {
|
||||
ini_set('memory_limit', $cfg['MemoryLimit']);
|
||||
}
|
||||
|
||||
$timestamp = time();
|
||||
$maximum_time = 0;
|
||||
$maxExecutionTime = (int) ini_get('max_execution_time');
|
||||
if (isset($_POST['allow_interrupt']) && $maxExecutionTime >= 1) {
|
||||
$maximum_time = $maxExecutionTime - 1; // Give 1 second for phpMyAdmin to exit nicely
|
||||
}
|
||||
|
||||
// set default values
|
||||
$timeout_passed = false;
|
||||
$error = false;
|
||||
$read_multiply = 1;
|
||||
$finished = false;
|
||||
$offset = 0;
|
||||
$max_sql_len = 0;
|
||||
$sql_query = '';
|
||||
$sql_query_disabled = false;
|
||||
$go_sql = false;
|
||||
$executed_queries = 0;
|
||||
$run_query = true;
|
||||
$charset_conversion = false;
|
||||
$reset_charset = false;
|
||||
$msg = 'Sorry an unexpected error happened!';
|
||||
|
||||
/** @var bool|mixed $result */
|
||||
$result = false;
|
||||
|
||||
// Bookmark Support: get a query back from bookmark if required
|
||||
if (! empty($_POST['id_bookmark'])) {
|
||||
$id_bookmark = (int) $_POST['id_bookmark'];
|
||||
switch ($_POST['action_bookmark']) {
|
||||
case 0: // bookmarked query that have to be run
|
||||
$bookmark = Bookmark::get(
|
||||
$this->dbi,
|
||||
$cfg['Server']['user'],
|
||||
$db,
|
||||
$id_bookmark,
|
||||
'id',
|
||||
isset($_POST['action_bookmark_all'])
|
||||
);
|
||||
if (! $bookmark instanceof Bookmark) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (! empty($_POST['bookmark_variable'])) {
|
||||
$import_text = $bookmark->applyVariables($_POST['bookmark_variable']);
|
||||
} else {
|
||||
$import_text = $bookmark->getQuery();
|
||||
}
|
||||
|
||||
// refresh navigation and main panels
|
||||
if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $import_text)) {
|
||||
$reload = true;
|
||||
$ajax_reload['reload'] = true;
|
||||
}
|
||||
|
||||
// refresh navigation panel only
|
||||
if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $import_text)) {
|
||||
$ajax_reload['reload'] = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case 1: // bookmarked query that have to be displayed
|
||||
$bookmark = Bookmark::get($this->dbi, $cfg['Server']['user'], $db, $id_bookmark);
|
||||
if (! $bookmark instanceof Bookmark) {
|
||||
break;
|
||||
}
|
||||
|
||||
$import_text = $bookmark->getQuery();
|
||||
if ($this->response->isAjax()) {
|
||||
$message = Message::success(__('Showing bookmark'));
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON('message', $message);
|
||||
$this->response->addJSON('sql_query', $import_text);
|
||||
$this->response->addJSON('action_bookmark', $_POST['action_bookmark']);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$run_query = false;
|
||||
}
|
||||
|
||||
break;
|
||||
case 2: // bookmarked query that have to be deleted
|
||||
$bookmark = Bookmark::get($this->dbi, $cfg['Server']['user'], $db, $id_bookmark);
|
||||
if (! $bookmark instanceof Bookmark) {
|
||||
break;
|
||||
}
|
||||
|
||||
$bookmark->delete();
|
||||
if ($this->response->isAjax()) {
|
||||
$message = Message::success(
|
||||
__('The bookmark has been deleted.')
|
||||
);
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON('message', $message);
|
||||
$this->response->addJSON('action_bookmark', $_POST['action_bookmark']);
|
||||
$this->response->addJSON('id_bookmark', $id_bookmark);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$run_query = false;
|
||||
$error = true; // this is kind of hack to skip processing the query
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Do no run query if we show PHP code
|
||||
if (isset($show_as_php)) {
|
||||
$run_query = false;
|
||||
$go_sql = true;
|
||||
}
|
||||
|
||||
// We can not read all at once, otherwise we can run out of memory
|
||||
$memory_limit = trim((string) ini_get('memory_limit'));
|
||||
// 2 MB as default
|
||||
if (empty($memory_limit)) {
|
||||
$memory_limit = 2 * 1024 * 1024;
|
||||
}
|
||||
|
||||
// In case no memory limit we work on 10MB chunks
|
||||
if ($memory_limit === '-1') {
|
||||
$memory_limit = 10 * 1024 * 1024;
|
||||
}
|
||||
|
||||
// Calculate value of the limit
|
||||
$memoryUnit = mb_strtolower(substr((string) $memory_limit, -1));
|
||||
if ($memoryUnit === 'm') {
|
||||
$memory_limit = (int) substr((string) $memory_limit, 0, -1) * 1024 * 1024;
|
||||
} elseif ($memoryUnit === 'k') {
|
||||
$memory_limit = (int) substr((string) $memory_limit, 0, -1) * 1024;
|
||||
} elseif ($memoryUnit === 'g') {
|
||||
$memory_limit = (int) substr((string) $memory_limit, 0, -1) * 1024 * 1024 * 1024;
|
||||
} else {
|
||||
$memory_limit = (int) $memory_limit;
|
||||
}
|
||||
|
||||
// Just to be sure, there might be lot of memory needed for uncompression
|
||||
$read_limit = $memory_limit / 8;
|
||||
|
||||
// handle filenames
|
||||
if (
|
||||
isset($_FILES['import_file'])
|
||||
&& is_array($_FILES['import_file'])
|
||||
&& isset($_FILES['import_file']['name'], $_FILES['import_file']['tmp_name'])
|
||||
&& is_string($_FILES['import_file']['name'])
|
||||
&& is_string($_FILES['import_file']['tmp_name'])
|
||||
) {
|
||||
$import_file = $_FILES['import_file']['tmp_name'];
|
||||
$import_file_name = $_FILES['import_file']['name'];
|
||||
}
|
||||
|
||||
if (! empty($local_import_file) && ! empty($cfg['UploadDir'])) {
|
||||
// sanitize $local_import_file as it comes from a POST
|
||||
$local_import_file = Core::securePath($local_import_file);
|
||||
|
||||
$import_file = Util::userDir((string) $cfg['UploadDir'])
|
||||
. $local_import_file;
|
||||
|
||||
/*
|
||||
* Do not allow symlinks to avoid security issues
|
||||
* (user can create symlink to file they can not access,
|
||||
* but phpMyAdmin can).
|
||||
*/
|
||||
if (@is_link($import_file)) {
|
||||
$import_file = 'none';
|
||||
}
|
||||
} elseif (empty($import_file) || ! is_uploaded_file($import_file)) {
|
||||
$import_file = 'none';
|
||||
}
|
||||
|
||||
// Do we have file to import?
|
||||
|
||||
if ($import_file !== 'none' && ! $error) {
|
||||
/**
|
||||
* Handle file compression
|
||||
*/
|
||||
$importHandle = new File($import_file);
|
||||
$importHandle->checkUploadedFile();
|
||||
if ($importHandle->isError()) {
|
||||
/** @var Message $errorMessage */
|
||||
$errorMessage = $importHandle->getError();
|
||||
|
||||
$importHandle->close();
|
||||
|
||||
$_SESSION['Import_message']['message'] = $errorMessage->getDisplay();
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $errorMessage->getDisplay());
|
||||
$this->response->addHTML($errorMessage->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$importHandle->setDecompressContent(true);
|
||||
$importHandle->open();
|
||||
if ($importHandle->isError()) {
|
||||
/** @var Message $errorMessage */
|
||||
$errorMessage = $importHandle->getError();
|
||||
|
||||
$importHandle->close();
|
||||
|
||||
$_SESSION['Import_message']['message'] = $errorMessage->getDisplay();
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $errorMessage->getDisplay());
|
||||
$this->response->addHTML($errorMessage->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
} elseif (! $error && (! isset($import_text) || empty($import_text))) {
|
||||
$message = Message::error(
|
||||
__(
|
||||
'No data was received to import. Either no file name was ' .
|
||||
'submitted, or the file size exceeded the maximum size permitted ' .
|
||||
'by your PHP configuration. See [doc@faq1-16]FAQ 1.16[/doc].'
|
||||
)
|
||||
);
|
||||
|
||||
$_SESSION['Import_message']['message'] = $message->getDisplay();
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $message->getDisplay());
|
||||
$this->response->addHTML($message->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the file's charset if necessary
|
||||
if (Encoding::isSupported() && isset($charset_of_file)) {
|
||||
if ($charset_of_file !== 'utf-8') {
|
||||
$charset_conversion = true;
|
||||
}
|
||||
} elseif (isset($charset_of_file) && $charset_of_file !== 'utf-8') {
|
||||
$this->dbi->query('SET NAMES \'' . $charset_of_file . '\'');
|
||||
// We can not show query in this case, it is in different charset
|
||||
$sql_query_disabled = true;
|
||||
$reset_charset = true;
|
||||
}
|
||||
|
||||
// Something to skip? (because timeout has passed)
|
||||
if (! $error && isset($_POST['skip'])) {
|
||||
$original_skip = $skip = intval($_POST['skip']);
|
||||
while ($skip > 0 && ! $finished) {
|
||||
$this->import->getNextChunk($importHandle ?? null, $skip < $read_limit ? $skip : $read_limit);
|
||||
// Disable read progressivity, otherwise we eat all memory!
|
||||
$read_multiply = 1;
|
||||
$skip -= $read_limit;
|
||||
}
|
||||
|
||||
unset($skip);
|
||||
}
|
||||
|
||||
// This array contain the data like number of valid sql queries in the statement
|
||||
// and complete valid sql statement (which affected for rows)
|
||||
$sql_data = [
|
||||
'valid_sql' => [],
|
||||
'valid_queries' => 0,
|
||||
];
|
||||
|
||||
if (! $error) {
|
||||
/**
|
||||
* @var ImportPlugin $import_plugin
|
||||
*/
|
||||
$import_plugin = Plugins::getPlugin('import', $format, $import_type);
|
||||
if ($import_plugin == null) {
|
||||
$message = Message::error(
|
||||
__('Could not load import plugins, please check your installation!')
|
||||
);
|
||||
|
||||
$_SESSION['Import_message']['message'] = $message->getDisplay();
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', $message->getDisplay());
|
||||
$this->response->addHTML($message->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Do the real import
|
||||
$default_fk_check = ForeignKey::handleDisableCheckInit();
|
||||
try {
|
||||
$import_plugin->doImport($importHandle ?? null, $sql_data);
|
||||
ForeignKey::handleDisableCheckCleanup($default_fk_check);
|
||||
} catch (Throwable $e) {
|
||||
ForeignKey::handleDisableCheckCleanup($default_fk_check);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($importHandle)) {
|
||||
$importHandle->close();
|
||||
}
|
||||
|
||||
// Reset charset back, if we did some changes
|
||||
if ($reset_charset) {
|
||||
$this->dbi->query('SET CHARACTER SET ' . $charset_connection);
|
||||
$this->dbi->setCollation($collation_connection);
|
||||
}
|
||||
|
||||
// Show correct message
|
||||
if (! empty($id_bookmark) && $_POST['action_bookmark'] == 2) {
|
||||
$message = Message::success(__('The bookmark has been deleted.'));
|
||||
$display_query = $import_text;
|
||||
$error = false; // unset error marker, it was used just to skip processing
|
||||
} elseif (! empty($id_bookmark) && $_POST['action_bookmark'] == 1) {
|
||||
$message = Message::notice(__('Showing bookmark'));
|
||||
} elseif ($finished && ! $error) {
|
||||
// Do not display the query with message, we do it separately
|
||||
$display_query = ';';
|
||||
if ($import_type !== 'query') {
|
||||
$message = Message::success(
|
||||
'<em>'
|
||||
. _ngettext(
|
||||
'Import has been successfully finished, %d query executed.',
|
||||
'Import has been successfully finished, %d queries executed.',
|
||||
$executed_queries
|
||||
)
|
||||
. '</em>'
|
||||
);
|
||||
$message->addParam($executed_queries);
|
||||
|
||||
if (! empty($import_notice)) {
|
||||
$message->addHtml($import_notice);
|
||||
}
|
||||
|
||||
if (! empty($local_import_file)) {
|
||||
$message->addText('(' . $local_import_file . ')');
|
||||
} elseif (
|
||||
isset($_FILES['import_file'])
|
||||
&& is_array($_FILES['import_file'])
|
||||
&& isset($_FILES['import_file']['name'])
|
||||
&& is_string($_FILES['import_file']['name'])
|
||||
) {
|
||||
$message->addText('(' . $_FILES['import_file']['name'] . ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Did we hit timeout? Tell it user.
|
||||
if ($timeout_passed) {
|
||||
$urlParams['timeout_passed'] = '1';
|
||||
$urlParams['offset'] = $offset;
|
||||
if (isset($local_import_file)) {
|
||||
$urlParams['local_import_file'] = $local_import_file;
|
||||
}
|
||||
|
||||
$importUrl = $errorUrl = $goto . Url::getCommon($urlParams, '&');
|
||||
|
||||
$message = Message::error(
|
||||
__(
|
||||
'Script timeout passed, if you want to finish import,'
|
||||
. ' please %sresubmit the same file%s and import will resume.'
|
||||
)
|
||||
);
|
||||
$message->addParamHtml('<a href="' . $importUrl . '">');
|
||||
$message->addParamHtml('</a>');
|
||||
|
||||
if ($offset == 0 || (isset($original_skip) && $original_skip == $offset)) {
|
||||
$message->addText(
|
||||
__(
|
||||
'However on last run no data has been parsed,'
|
||||
. ' this usually means phpMyAdmin won\'t be able to'
|
||||
. ' finish this import unless you increase php time limits.'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// if there is any message, copy it into $_SESSION as well,
|
||||
// so we can obtain it by AJAX call
|
||||
if (isset($message)) {
|
||||
$_SESSION['Import_message']['message'] = $message->getDisplay();
|
||||
}
|
||||
|
||||
// Parse and analyze the query, for correct db and table name
|
||||
// in case of a query typed in the query window
|
||||
// (but if the query is too large, in case of an imported file, the parser
|
||||
// can choke on it so avoid parsing)
|
||||
$sqlLength = mb_strlen($sql_query);
|
||||
if ($sqlLength <= $cfg['MaxCharactersInDisplayedSQL']) {
|
||||
[
|
||||
$analyzed_sql_results,
|
||||
$db,
|
||||
$table_from_sql,
|
||||
] = ParseAnalyze::sqlQuery($sql_query, $db);
|
||||
|
||||
$reload = $analyzed_sql_results['reload'];
|
||||
$offset = $analyzed_sql_results['offset'];
|
||||
|
||||
if ($table != $table_from_sql && ! empty($table_from_sql)) {
|
||||
$table = $table_from_sql;
|
||||
}
|
||||
}
|
||||
|
||||
// There was an error?
|
||||
if (isset($my_die)) {
|
||||
foreach ($my_die as $die) {
|
||||
Generator::mysqlDie($die['error'], $die['sql'], false, $errorUrl, $error);
|
||||
}
|
||||
}
|
||||
|
||||
if ($go_sql) {
|
||||
if (! empty($sql_data) && ($sql_data['valid_queries'] > 1)) {
|
||||
$_SESSION['is_multi_query'] = true;
|
||||
$sql_queries = $sql_data['valid_sql'];
|
||||
} else {
|
||||
$sql_queries = [$sql_query];
|
||||
}
|
||||
|
||||
$html_output = '';
|
||||
|
||||
foreach ($sql_queries as $sql_query) {
|
||||
// parse sql query
|
||||
[
|
||||
$analyzed_sql_results,
|
||||
$db,
|
||||
$table_from_sql,
|
||||
] = ParseAnalyze::sqlQuery($sql_query, $db);
|
||||
|
||||
$offset = $analyzed_sql_results['offset'];
|
||||
$reload = $analyzed_sql_results['reload'];
|
||||
|
||||
// Check if User is allowed to issue a 'DROP DATABASE' Statement
|
||||
if (
|
||||
$this->sql->hasNoRightsToDropDatabase(
|
||||
$analyzed_sql_results,
|
||||
$cfg['AllowUserDropDatabase'],
|
||||
$this->dbi->isSuperUser()
|
||||
)
|
||||
) {
|
||||
Generator::mysqlDie(
|
||||
__('"DROP DATABASE" statements are disabled.'),
|
||||
'',
|
||||
false,
|
||||
$_SESSION['Import_message']['go_back_url']
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($table != $table_from_sql && ! empty($table_from_sql)) {
|
||||
$table = $table_from_sql;
|
||||
}
|
||||
|
||||
$html_output .= $this->sql->executeQueryAndGetQueryResponse(
|
||||
$analyzed_sql_results, // analyzed_sql_results
|
||||
false, // is_gotofile
|
||||
$db, // db
|
||||
$table, // table
|
||||
null, // find_real_end
|
||||
null, // sql_query_for_bookmark - see below
|
||||
null, // extra_data
|
||||
null, // message_to_show
|
||||
null, // sql_data
|
||||
$goto, // goto
|
||||
null, // disp_query
|
||||
null, // disp_message
|
||||
$sql_query, // sql_query
|
||||
null // complete_query
|
||||
);
|
||||
}
|
||||
|
||||
// sql_query_for_bookmark is not included in Sql::executeQueryAndGetQueryResponse
|
||||
// since only one bookmark has to be added for all the queries submitted through
|
||||
// the SQL tab
|
||||
if (! empty($_POST['bkm_label']) && ! empty($import_text)) {
|
||||
$relation = new Relation($this->dbi);
|
||||
|
||||
$this->sql->storeTheQueryAsBookmark(
|
||||
$relation->getRelationParameters()->bookmarkFeature,
|
||||
$db,
|
||||
$cfg['Server']['user'],
|
||||
$_POST['sql_query'],
|
||||
$_POST['bkm_label'],
|
||||
isset($_POST['bkm_replace'])
|
||||
);
|
||||
}
|
||||
|
||||
$this->response->addJSON('ajax_reload', $ajax_reload);
|
||||
$this->response->addHTML($html_output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
// Save a Bookmark with more than one queries (if Bookmark label given).
|
||||
if (! empty($_POST['bkm_label']) && ! empty($import_text)) {
|
||||
$relation = new Relation($this->dbi);
|
||||
|
||||
$this->sql->storeTheQueryAsBookmark(
|
||||
$relation->getRelationParameters()->bookmarkFeature,
|
||||
$db,
|
||||
$cfg['Server']['user'],
|
||||
$_POST['sql_query'],
|
||||
$_POST['bkm_label'],
|
||||
isset($_POST['bkm_replace'])
|
||||
);
|
||||
}
|
||||
|
||||
$this->response->setRequestStatus(true);
|
||||
$this->response->addJSON('message', Message::success($msg));
|
||||
$this->response->addJSON(
|
||||
'sql_query',
|
||||
Generator::getMessage($msg, $sql_query, 'success')
|
||||
);
|
||||
} elseif ($result === false) {
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON('message', Message::error($msg));
|
||||
} else {
|
||||
$active_page = $goto;
|
||||
/** @psalm-suppress UnresolvableInclude */
|
||||
include ROOT_PATH . $goto;
|
||||
}
|
||||
|
||||
// If there is request for ROLLBACK in the end.
|
||||
if (! isset($_POST['rollback_query'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->dbi->query('ROLLBACK');
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Import;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Import\SimulateDml;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\SqlParser\Parser;
|
||||
use PhpMyAdmin\SqlParser\Statements\DeleteStatement;
|
||||
use PhpMyAdmin\SqlParser\Statements\UpdateStatement;
|
||||
use PhpMyAdmin\SqlParser\Utils\Query;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function explode;
|
||||
|
||||
final class SimulateDmlController extends AbstractController
|
||||
{
|
||||
/** @var SimulateDml */
|
||||
private $simulateDml;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
SimulateDml $simulateDml
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->simulateDml = $simulateDml;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$error = '';
|
||||
$errorMsg = __('Only single-table UPDATE and DELETE queries can be simulated.');
|
||||
/** @var string $sqlDelimiter */
|
||||
$sqlDelimiter = $_POST['sql_delimiter'];
|
||||
$sqlData = [];
|
||||
/** @var string[] $queries */
|
||||
$queries = explode($sqlDelimiter, $GLOBALS['sql_query']);
|
||||
foreach ($queries as $sqlQuery) {
|
||||
if (empty($sqlQuery)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parsing the query.
|
||||
$parser = new Parser($sqlQuery);
|
||||
|
||||
if (empty($parser->statements[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$statement = $parser->statements[0];
|
||||
|
||||
if (
|
||||
! ($statement instanceof UpdateStatement || $statement instanceof DeleteStatement)
|
||||
|| ! empty($statement->join)
|
||||
) {
|
||||
$error = $errorMsg;
|
||||
break;
|
||||
}
|
||||
|
||||
$tables = Query::getTables($statement);
|
||||
if (count($tables) > 1) {
|
||||
$error = $errorMsg;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the matched rows for the query.
|
||||
$result = $this->simulateDml->getMatchedRows($sqlQuery, $parser, $statement);
|
||||
$error = $this->simulateDml->getError();
|
||||
|
||||
if ($error !== '') {
|
||||
break;
|
||||
}
|
||||
|
||||
$sqlData[] = $result;
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
$message = Message::rawError($error);
|
||||
$this->response->addJSON('message', $message);
|
||||
$this->response->addJSON('sql_data', false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON('sql_data', $sqlData);
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Import;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Import\Ajax;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
use function __;
|
||||
use function header;
|
||||
use function ini_get;
|
||||
use function session_start;
|
||||
use function session_write_close;
|
||||
use function time;
|
||||
use function usleep;
|
||||
|
||||
/**
|
||||
* Import progress bar backend
|
||||
*/
|
||||
class StatusController
|
||||
{
|
||||
/** @var Template */
|
||||
private $template;
|
||||
|
||||
public function __construct(Template $template)
|
||||
{
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $SESSION_KEY, $upload_id, $plugins, $timestamp;
|
||||
|
||||
[
|
||||
$SESSION_KEY,
|
||||
$upload_id,
|
||||
$plugins,
|
||||
] = Ajax::uploadProgressSetup();
|
||||
|
||||
// $_GET["message"] is used for asking for an import message
|
||||
if (isset($_GET['message']) && $_GET['message']) {
|
||||
// AJAX requests can't be cached!
|
||||
Core::noCacheHeader();
|
||||
|
||||
header('Content-type: text/html');
|
||||
|
||||
// wait 0.3 sec before we check for $_SESSION variable
|
||||
usleep(300000);
|
||||
|
||||
$maximumTime = ini_get('max_execution_time');
|
||||
$timestamp = time();
|
||||
// wait until message is available
|
||||
while (($_SESSION['Import_message']['message'] ?? null) == null) {
|
||||
// close session before sleeping
|
||||
session_write_close();
|
||||
// sleep
|
||||
usleep(250000); // 0.25 sec
|
||||
// reopen session
|
||||
session_start();
|
||||
|
||||
if (time() - $timestamp > $maximumTime) {
|
||||
$_SESSION['Import_message']['message'] = Message::error(
|
||||
__('Could not load the progress of the import.')
|
||||
)->getDisplay();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
echo $_SESSION['Import_message']['message'] ?? '';
|
||||
|
||||
if (isset($_SESSION['Import_message']['go_back_url'])) {
|
||||
echo $this->template->render('import_status', [
|
||||
'go_back_url' => $_SESSION['Import_message']['go_back_url'],
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
Ajax::status($_GET['id']);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,713 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Theme;
|
||||
|
||||
use function __;
|
||||
use function _pgettext;
|
||||
use function json_encode;
|
||||
|
||||
/**
|
||||
* Exporting of translated messages from PHP to JavaScript.
|
||||
*/
|
||||
final class JavaScriptMessagesController
|
||||
{
|
||||
/** @var array<string, string> */
|
||||
private $messages = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setMessages();
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
echo 'var Messages = ' . json_encode($this->messages) . ';';
|
||||
}
|
||||
|
||||
private function setMessages(): void
|
||||
{
|
||||
global $cfg, $theme;
|
||||
|
||||
$ajaxClockSmallGifPath = $theme instanceof Theme ? $theme->getImgPath('ajax_clock_small.gif') : '';
|
||||
|
||||
$this->messages = [
|
||||
/* For confirmations */
|
||||
'strConfirm' => __('Confirm'),
|
||||
'strDoYouReally' => __('Do you really want to execute "%s"?'),
|
||||
'strDropDatabaseStrongWarning' => __('You are about to DESTROY a complete database!'),
|
||||
'strDatabaseRenameToSameName' => __(
|
||||
'Cannot rename database to the same name. Change the name and try again'
|
||||
),
|
||||
'strDropTableStrongWarning' => __('You are about to DESTROY a complete table!'),
|
||||
'strTruncateTableStrongWarning' => __('You are about to TRUNCATE a complete table!'),
|
||||
'strDeleteTableStrongWarning' => __('You are about to DELETE all the rows of the table!'),
|
||||
'strDeleteTrackingData' => __('Delete tracking data for this table?'),
|
||||
'strDeleteTrackingDataMultiple' => __('Delete tracking data for these tables?'),
|
||||
'strDeleteTrackingVersion' => __('Delete tracking data for this version?'),
|
||||
'strDeleteTrackingVersionMultiple' => __('Delete tracking data for these versions?'),
|
||||
'strDeletingTrackingEntry' => __('Delete entry from tracking report?'),
|
||||
'strDeletingTrackingData' => __('Deleting tracking data'),
|
||||
'strDroppingPrimaryKeyIndex' => __('Dropping Primary Key/Index'),
|
||||
'strDroppingForeignKey' => __('Dropping Foreign key.'),
|
||||
'strOperationTakesLongTime' => __('This operation could take a long time. Proceed anyway?'),
|
||||
'strDropUserGroupWarning' => __('Do you really want to delete user group "%s"?'),
|
||||
'strConfirmDeleteQBESearch' => __('Do you really want to delete the search "%s"?'),
|
||||
'strConfirmNavigation' => __('You have unsaved changes; are you sure you want to leave this page?'),
|
||||
'strConfirmRowChange' => __(
|
||||
'You are trying to reduce the number of rows, but have already entered'
|
||||
. ' data in those rows which will be lost. Do you wish to continue?'
|
||||
),
|
||||
'strDropUserWarning' => __('Do you really want to revoke the selected user(s) ?'),
|
||||
'strDeleteCentralColumnWarning' => __('Do you really want to delete this central column?'),
|
||||
'strDropRTEitems' => __('Do you really want to delete the selected items?'),
|
||||
'strDropPartitionWarning' => __(
|
||||
'Do you really want to DROP the selected partition(s)? This will also DELETE ' .
|
||||
'the data related to the selected partition(s)!'
|
||||
),
|
||||
'strTruncatePartitionWarning' => __('Do you really want to TRUNCATE the selected partition(s)?'),
|
||||
'strRemovePartitioningWarning' => __('Do you really want to remove partitioning?'),
|
||||
'strResetReplicaWarning' => __('Do you really want to reset the replica (RESET REPLICA)?'),
|
||||
'strChangeColumnCollation' => __(
|
||||
'This operation will attempt to convert your data to the new collation. In '
|
||||
. 'rare cases, especially where a character doesn\'t exist in the new '
|
||||
. 'collation, this process could cause the data to appear incorrectly under '
|
||||
. 'the new collation; in this case we suggest you revert to the original '
|
||||
. 'collation and refer to the tips at '
|
||||
)
|
||||
. '<a href="%s" target="garbled_data_wiki">' . __('Garbled Data') . '</a>.'
|
||||
. '<br><br>'
|
||||
. __('Are you sure you wish to change the collation and convert the data?'),
|
||||
|
||||
'strChangeAllColumnCollationsWarning' => __(
|
||||
'Through this operation, MySQL attempts to map the data values between '
|
||||
. 'collations. If the character sets are incompatible, there may be data loss '
|
||||
. 'and this lost data may <b>NOT</b> be recoverable simply by changing back the '
|
||||
. 'column collation(s). <b>To convert existing data, it is suggested to use the '
|
||||
. 'column(s) editing feature (the "Change" Link) on the table structure page. '
|
||||
. '</b>'
|
||||
)
|
||||
. '<br><br>'
|
||||
. __('Are you sure you wish to change all the column collations and convert the data?'),
|
||||
|
||||
/* For modal dialog buttons */
|
||||
'strSaveAndClose' => __('Save & close'),
|
||||
'strReset' => __('Reset'),
|
||||
'strResetAll' => __('Reset all'),
|
||||
|
||||
/* For indexes */
|
||||
'strFormEmpty' => __('Missing value in the form!'),
|
||||
'strRadioUnchecked' => __('Select at least one of the options!'),
|
||||
'strEnterValidNumber' => __('Please enter a valid number!'),
|
||||
'strEnterValidLength' => __('Please enter a valid length!'),
|
||||
'strAddIndex' => __('Add index'),
|
||||
'strEditIndex' => __('Edit index'),
|
||||
/* l10n: Rename a table Index */
|
||||
'strRenameIndex' => __('Rename index'),
|
||||
'strAddToIndex' => __('Add %s column(s) to index'),
|
||||
'strCreateSingleColumnIndex' => __('Create single-column index'),
|
||||
'strCreateCompositeIndex' => __('Create composite index'),
|
||||
'strCompositeWith' => __('Composite with:'),
|
||||
'strMissingColumn' => __('Please select column(s) for the index.'),
|
||||
|
||||
/* For Preview SQL*/
|
||||
'strPreviewSQL' => __('Preview SQL'),
|
||||
|
||||
/* For Simulate DML*/
|
||||
'strSimulateDML' => __('Simulate query'),
|
||||
'strMatchedRows' => __('Matched rows:'),
|
||||
'strSQLQuery' => __('SQL query:'),
|
||||
|
||||
/* Charts */
|
||||
/* l10n: Default label for the y-Axis of Charts */
|
||||
'strYValues' => __('Y values'),
|
||||
|
||||
/* Database multi-table query */
|
||||
'strEmptyQuery' => __('Please enter the SQL query first.'),
|
||||
|
||||
/* For server/privileges.js */
|
||||
'strHostEmpty' => __('The host name is empty!'),
|
||||
'strUserEmpty' => __('The user name is empty!'),
|
||||
'strPasswordEmpty' => __('The password is empty!'),
|
||||
'strPasswordNotSame' => __('The passwords aren\'t the same!'),
|
||||
'strRemovingSelectedUsers' => __('Removing Selected Users'),
|
||||
'strClose' => __('Close'),
|
||||
'strLock' => _pgettext('Lock the account.', 'Lock'),
|
||||
'strUnlock' => _pgettext('Unlock the account.', 'Unlock'),
|
||||
'strLockAccount' => __('Lock this account.'),
|
||||
'strUnlockAccount' => __('Unlock this account.'),
|
||||
|
||||
/* For export.js */
|
||||
'strTemplateCreated' => __('Template was created.'),
|
||||
'strTemplateLoaded' => __('Template was loaded.'),
|
||||
'strTemplateUpdated' => __('Template was updated.'),
|
||||
'strTemplateDeleted' => __('Template was deleted.'),
|
||||
|
||||
/* l10n: Other, small valued, queries */
|
||||
'strOther' => __('Other'),
|
||||
/* l10n: Thousands separator */
|
||||
'strThousandsSeparator' => __(','),
|
||||
/* l10n: Decimal separator */
|
||||
'strDecimalSeparator' => __('.'),
|
||||
|
||||
'strChartConnectionsTitle' => __('Connections / Processes'),
|
||||
|
||||
/* server status monitor */
|
||||
'strIncompatibleMonitorConfig' => __('Local monitor configuration incompatible!'),
|
||||
'strIncompatibleMonitorConfigDescription' => __(
|
||||
'The chart arrangement configuration in your browsers local storage is not '
|
||||
. 'compatible anymore to the newer version of the monitor dialog. It is very '
|
||||
. 'likely that your current configuration will not work anymore. Please reset '
|
||||
. 'your configuration to default in the <i>Settings</i> menu.'
|
||||
),
|
||||
|
||||
'strQueryCacheEfficiency' => __('Query cache efficiency'),
|
||||
'strQueryCacheUsage' => __('Query cache usage'),
|
||||
'strQueryCacheUsed' => __('Query cache used'),
|
||||
|
||||
'strSystemCPUUsage' => __('System CPU usage'),
|
||||
'strSystemMemory' => __('System memory'),
|
||||
'strSystemSwap' => __('System swap'),
|
||||
|
||||
'strAverageLoad' => __('Average load'),
|
||||
'strTotalMemory' => __('Total memory'),
|
||||
'strCachedMemory' => __('Cached memory'),
|
||||
'strBufferedMemory' => __('Buffered memory'),
|
||||
'strFreeMemory' => __('Free memory'),
|
||||
'strUsedMemory' => __('Used memory'),
|
||||
|
||||
'strTotalSwap' => __('Total swap'),
|
||||
'strCachedSwap' => __('Cached swap'),
|
||||
'strUsedSwap' => __('Used swap'),
|
||||
'strFreeSwap' => __('Free swap'),
|
||||
|
||||
'strBytesSent' => __('Bytes sent'),
|
||||
'strBytesReceived' => __('Bytes received'),
|
||||
'strConnections' => __('Connections'),
|
||||
'strProcesses' => __('Processes'),
|
||||
|
||||
/* summary row */
|
||||
'strB' => __('B'),
|
||||
'strKiB' => __('KiB'),
|
||||
'strMiB' => __('MiB'),
|
||||
'strGiB' => __('GiB'),
|
||||
'strTiB' => __('TiB'),
|
||||
'strPiB' => __('PiB'),
|
||||
'strEiB' => __('EiB'),
|
||||
'strNTables' => __('%d table(s)'),
|
||||
|
||||
/* l10n: Questions is the name of a MySQL Status variable */
|
||||
'strQuestions' => __('Questions'),
|
||||
'strTraffic' => __('Traffic'),
|
||||
'strSettings' => __('Settings'),
|
||||
'strAddChart' => __('Add chart to grid'),
|
||||
'strAddOneSeriesWarning' => __('Please add at least one variable to the series!'),
|
||||
'strNone' => __('None'),
|
||||
/* l10n: SQL Query on modal to show exported query */
|
||||
'strQuery' => __('SQL Query'),
|
||||
'strResumeMonitor' => __('Resume monitor'),
|
||||
'strPauseMonitor' => __('Pause monitor'),
|
||||
'strStartRefresh' => __('Start auto refresh'),
|
||||
'strStopRefresh' => __('Stop auto refresh'),
|
||||
/* Monitor: Instructions Dialog */
|
||||
'strBothLogOn' => __('general_log and slow_query_log are enabled.'),
|
||||
'strGenLogOn' => __('general_log is enabled.'),
|
||||
'strSlowLogOn' => __('slow_query_log is enabled.'),
|
||||
'strBothLogOff' => __('slow_query_log and general_log are disabled.'),
|
||||
'strLogOutNotTable' => __('log_output is not set to TABLE.'),
|
||||
'strLogOutIsTable' => __('log_output is set to TABLE.'),
|
||||
'strSmallerLongQueryTimeAdvice' => __(
|
||||
'slow_query_log is enabled, but the server logs only queries that take longer '
|
||||
. 'than %d seconds. It is advisable to set this long_query_time 0-2 seconds, '
|
||||
. 'depending on your system.'
|
||||
),
|
||||
'strLongQueryTimeSet' => __('long_query_time is set to %d second(s).'),
|
||||
'strSettingsAppliedGlobal' => __(
|
||||
'Following settings will be applied globally and reset to default on server restart:'
|
||||
),
|
||||
/* l10n: %s is FILE or TABLE */
|
||||
'strSetLogOutput' => __('Set log_output to %s'),
|
||||
/* l10n: Enable in this context means setting a status variable to ON */
|
||||
'strEnableVar' => __('Enable %s'),
|
||||
/* l10n: Disable in this context means setting a status variable to OFF */
|
||||
'strDisableVar' => __('Disable %s'),
|
||||
/* l10n: %d seconds */
|
||||
'setSetLongQueryTime' => __('Set long_query_time to %d seconds.'),
|
||||
'strNoSuperUser' => __(
|
||||
'You can\'t change these variables. Please log in as root or contact your database administrator.'
|
||||
),
|
||||
'strChangeSettings' => __('Change settings'),
|
||||
'strCurrentSettings' => __('Current settings'),
|
||||
|
||||
'strChartTitle' => __('Chart title'),
|
||||
/* l10n: As in differential values */
|
||||
'strDifferential' => __('Differential'),
|
||||
'strDividedBy' => __('Divided by %s'),
|
||||
'strUnit' => __('Unit'),
|
||||
|
||||
'strFromSlowLog' => __('From slow log'),
|
||||
'strFromGeneralLog' => __('From general log'),
|
||||
'strServerLogError' => __('The database name is not known for this query in the server\'s logs.'),
|
||||
'strAnalysingLogsTitle' => __('Analysing logs'),
|
||||
'strAnalysingLogs' => __('Analysing & loading logs. This may take a while.'),
|
||||
'strCancelRequest' => __('Cancel request'),
|
||||
'strCountColumnExplanation' => __(
|
||||
'This column shows the amount of identical queries that are grouped together. '
|
||||
. 'However only the SQL query itself has been used as a grouping criteria, so '
|
||||
. 'the other attributes of queries, such as start time, may differ.'
|
||||
),
|
||||
'strMoreCountColumnExplanation' => __(
|
||||
'Since grouping of INSERTs queries has been selected, INSERT queries into the '
|
||||
. 'same table are also being grouped together, disregarding of the inserted '
|
||||
. 'data.'
|
||||
),
|
||||
'strLogDataLoaded' => __('Log data loaded. Queries executed in this time span:'),
|
||||
|
||||
'strJumpToTable' => __('Jump to Log table'),
|
||||
'strNoDataFoundTitle' => __('No data found'),
|
||||
'strNoDataFound' => __('Log analysed, but no data found in this time span.'),
|
||||
|
||||
'strAnalyzing' => __('Analyzing…'),
|
||||
'strExplainOutput' => __('Explain output'),
|
||||
'strStatus' => __('Status'),
|
||||
'strTime' => __('Time'),
|
||||
'strTotalTime' => __('Total time:'),
|
||||
'strProfilingResults' => __('Profiling results'),
|
||||
'strTable' => _pgettext('Display format', 'Table'),
|
||||
'strChart' => __('Chart'),
|
||||
|
||||
'strAliasDatabase' => _pgettext('Alias', 'Database'),
|
||||
'strAliasTable' => _pgettext('Alias', 'Table'),
|
||||
'strAliasColumn' => _pgettext('Alias', 'Column'),
|
||||
|
||||
/* l10n: A collection of available filters */
|
||||
'strFiltersForLogTable' => __('Log table filter options'),
|
||||
/* l10n: Filter as in "Start Filtering" */
|
||||
'strFilter' => __('Filter'),
|
||||
'strFilterByWordRegexp' => __('Filter queries by word/regexp:'),
|
||||
'strIgnoreWhereAndGroup' => __('Group queries, ignoring variable data in WHERE clauses'),
|
||||
'strSumRows' => __('Sum of grouped rows:'),
|
||||
'strTotal' => __('Total:'),
|
||||
|
||||
'strLoadingLogs' => __('Loading logs'),
|
||||
'strRefreshFailed' => __('Monitor refresh failed'),
|
||||
'strInvalidResponseExplanation' => __(
|
||||
'While requesting new chart data the server returned an invalid response. This '
|
||||
. 'is most likely because your session expired. Reloading the page and '
|
||||
. 'reentering your credentials should help.'
|
||||
),
|
||||
'strReloadPage' => __('Reload page'),
|
||||
|
||||
'strAffectedRows' => __('Affected rows:'),
|
||||
|
||||
'strFailedParsingConfig' => __('Failed parsing config file. It doesn\'t seem to be valid JSON code.'),
|
||||
'strFailedBuildingGrid' => __(
|
||||
'Failed building chart grid with imported config. Resetting to default config…'
|
||||
),
|
||||
'strImport' => __('Import'),
|
||||
'strImportDialogTitle' => __('Import monitor configuration'),
|
||||
'strImportDialogMessage' => __('Please select the file you want to import:'),
|
||||
'strTableNameDialogMessage' => __('Please enter a valid table name.'),
|
||||
'strDBNameDialogMessage' => __('Please enter a valid database name.'),
|
||||
'strNoImportFile' => __('No files available on server for import!'),
|
||||
|
||||
'strAnalyzeQuery' => __('Analyse query'),
|
||||
|
||||
/* For query editor */
|
||||
'strFormatting' => __('Formatting SQL…'),
|
||||
'strNoParam' => __('No parameters found!'),
|
||||
|
||||
/* For inline query editing */
|
||||
'strGo' => __('Go'),
|
||||
'strCancel' => __('Cancel'),
|
||||
|
||||
/* For page-related settings */
|
||||
'strPageSettings' => __('Page-related settings'),
|
||||
'strApply' => __('Apply'),
|
||||
|
||||
/* For Ajax Notifications */
|
||||
'strLoading' => __('Loading…'),
|
||||
'strAbortedRequest' => __('Request aborted!!'),
|
||||
'strProcessingRequest' => __('Processing request'),
|
||||
'strRequestFailed' => __('Request failed!!'),
|
||||
'strErrorProcessingRequest' => __('Error in processing request'),
|
||||
'strErrorCode' => __('Error code: %s'),
|
||||
'strErrorText' => __('Error text: %s'),
|
||||
'strErrorConnection' => __(
|
||||
'It seems that the connection to server has been lost. Please check your ' .
|
||||
'network connectivity and server status.'
|
||||
),
|
||||
'strNoDatabasesSelected' => __('No databases selected.'),
|
||||
'strNoTableSelected' => __('No table selected.'),
|
||||
'strNoAccountSelected' => __('No accounts selected.'),
|
||||
'strDroppingColumn' => __('Dropping column'),
|
||||
'strAddingPrimaryKey' => __('Adding primary key'),
|
||||
'strOK' => __('OK'),
|
||||
'strDismiss' => __('Click to dismiss this notification'),
|
||||
|
||||
/* For database/operations.js */
|
||||
'strRenamingDatabases' => __('Renaming databases'),
|
||||
'strCopyingDatabase' => __('Copying database'),
|
||||
'strChangingCharset' => __('Changing charset'),
|
||||
'strNo' => __('No'),
|
||||
|
||||
/* For Foreign key checks */
|
||||
'strForeignKeyCheck' => __('Enable foreign key checks'),
|
||||
|
||||
/* For database/structure.js */
|
||||
'strErrorRealRowCount' => __('Failed to get real row count.'),
|
||||
|
||||
/* For database/search.js */
|
||||
'strSearching' => __('Searching'),
|
||||
'strHideSearchResults' => __('Hide search results'),
|
||||
'strShowSearchResults' => __('Show search results'),
|
||||
'strBrowsing' => __('Browsing'),
|
||||
'strDeleting' => __('Deleting'),
|
||||
'strConfirmDeleteResults' => __('Delete the matches for the %s table?'),
|
||||
|
||||
/* For rte.js */
|
||||
'MissingReturn' => __('The definition of a stored function must contain a RETURN statement!'),
|
||||
'strExport' => __('Export'),
|
||||
'NoExportable' => __('No routine is exportable. Required privileges may be lacking.'),
|
||||
|
||||
/* For ENUM/SET editor*/
|
||||
'enum_columnVals' => __('Values for column %s'),
|
||||
'enum_newColumnVals' => __('Values for a new column'),
|
||||
'enum_hint' => __('Enter each value in a separate field.'),
|
||||
'enum_addValue' => __('Add %d value(s)'),
|
||||
|
||||
/* For import.js */
|
||||
'strImportCSV' => __('Note: If the file contains multiple tables, they will be combined into one.'),
|
||||
|
||||
/* For sql.js */
|
||||
'strHideQueryBox' => __('Hide query box'),
|
||||
'strShowQueryBox' => __('Show query box'),
|
||||
'strEdit' => __('Edit'),
|
||||
'strDelete' => __('Delete'),
|
||||
'strNotValidRowNumber' => __('%d is not valid row number.'),
|
||||
'strBrowseForeignValues' => __('Browse foreign values'),
|
||||
'strNoAutoSavedQuery' => __('No previously auto-saved query is available. Loading default query.'),
|
||||
'strPreviousSaveQuery' => __(
|
||||
'You have a previously saved query. Click Get auto-saved query to load the query.'
|
||||
),
|
||||
'strBookmarkVariable' => __('Variable %d:'),
|
||||
|
||||
/* For Central list of columns */
|
||||
'pickColumn' => __('Pick'),
|
||||
'pickColumnTitle' => __('Column selector'),
|
||||
'searchList' => __('Search this list'),
|
||||
'strEmptyCentralList' => __(
|
||||
'No columns in the central list. Make sure the Central columns list for '
|
||||
. 'database %s has columns that are not present in the current table.'
|
||||
),
|
||||
'seeMore' => __('See more'),
|
||||
|
||||
/* For normalization */
|
||||
'strAddPrimaryKey' => __('Add primary key'),
|
||||
'strPrimaryKeyAdded' => __('Primary key added.'),
|
||||
'strToNextStep' => __('Taking you to next step…'),
|
||||
'strFinishMsg' => __("The first step of normalization is complete for table '%s'."),
|
||||
'strEndStep' => __('End of step'),
|
||||
'str2NFNormalization' => __('Second step of normalization (2NF)'),
|
||||
'strDone' => __('Done'),
|
||||
'strConfirmPd' => __('Confirm partial dependencies'),
|
||||
'strSelectedPd' => __('Selected partial dependencies are as follows:'),
|
||||
'strPdHintNote' => __(
|
||||
'Note: a, b -> d,f implies values of columns a and b combined together can '
|
||||
. 'determine values of column d and column f.'
|
||||
),
|
||||
'strNoPdSelected' => __('No partial dependencies selected!'),
|
||||
'strBack' => __('Back'),
|
||||
'strShowPossiblePd' => __('Show me the possible partial dependencies based on data in the table'),
|
||||
'strHidePd' => __('Hide partial dependencies list'),
|
||||
'strWaitForPd' => __(
|
||||
'Sit tight! It may take few seconds depending on data size and column count of the table.'
|
||||
),
|
||||
'strStep' => __('Step'),
|
||||
'strMoveRepeatingGroup' => '<ol><b>' . __('The following actions will be performed:') . '</b>'
|
||||
. '<li>' . __('DROP columns %s from the table %s') . '</li>'
|
||||
. '<li>' . __('Create the following table') . '</li>',
|
||||
'strNewTablePlaceholder' => 'Enter new table name',
|
||||
'strNewColumnPlaceholder' => 'Enter column name',
|
||||
'str3NFNormalization' => __('Third step of normalization (3NF)'),
|
||||
'strConfirmTd' => __('Confirm transitive dependencies'),
|
||||
'strSelectedTd' => __('Selected dependencies are as follows:'),
|
||||
'strNoTdSelected' => __('No dependencies selected!'),
|
||||
|
||||
/* For server/variables.js */
|
||||
'strSave' => __('Save'),
|
||||
|
||||
/* For table/select.js */
|
||||
'strHideSearchCriteria' => __('Hide search criteria'),
|
||||
'strShowSearchCriteria' => __('Show search criteria'),
|
||||
'strColumnMax' => __('Column maximum:'),
|
||||
'strColumnMin' => __('Column minimum:'),
|
||||
|
||||
/* For table/find_replace.js */
|
||||
'strHideFindNReplaceCriteria' => __('Hide find and replace criteria'),
|
||||
'strShowFindNReplaceCriteria' => __('Show find and replace criteria'),
|
||||
|
||||
/* For table/zoom_plot_jqplot.js */
|
||||
'strDisplayHelp' => '<ul><li>'
|
||||
. __('Each point represents a data row.')
|
||||
. '</li><li>'
|
||||
. __('Hovering over a point will show its label.')
|
||||
. '</li><li>'
|
||||
. __('To zoom in, select a section of the plot with the mouse.')
|
||||
. '</li><li>'
|
||||
. __('Click reset zoom button to come back to original state.')
|
||||
. '</li><li>'
|
||||
. __('Click a data point to view and possibly edit the data row.')
|
||||
. '</li><li>'
|
||||
. __('The plot can be resized by dragging it along the bottom right corner.')
|
||||
. '</li></ul>',
|
||||
'strHelpTitle' => 'Zoom search instructions',
|
||||
'strInputNull' => '<strong>' . __('Select two columns') . '</strong>',
|
||||
'strSameInputs' => '<strong>'
|
||||
. __('Select two different columns')
|
||||
. '</strong>',
|
||||
'strDataPointContent' => __('Data point content'),
|
||||
|
||||
/* For table/change.js */
|
||||
'strIgnore' => __('Ignore'),
|
||||
'strCopy' => __('Copy'),
|
||||
'strX' => __('X'),
|
||||
'strY' => __('Y'),
|
||||
'strPoint' => __('Point'),
|
||||
'strPointN' => __('Point %d'),
|
||||
'strLineString' => __('Linestring'),
|
||||
'strPolygon' => __('Polygon'),
|
||||
'strGeometry' => __('Geometry'),
|
||||
'strInnerRing' => __('Inner ring'),
|
||||
'strOuterRing' => __('Outer ring'),
|
||||
'strAddPoint' => __('Add a point'),
|
||||
'strAddInnerRing' => __('Add an inner ring'),
|
||||
'strYes' => __('Yes'),
|
||||
'strCopyEncryptionKey' => __('Do you want to copy encryption key?'),
|
||||
'strEncryptionKey' => __('Encryption key'),
|
||||
/* l10n: Tip for HEX conversion of Integers */
|
||||
'HexConversionInfo' => __(
|
||||
'The HEX function will treat the integer as a string while calculating the hexadecimal value'
|
||||
),
|
||||
|
||||
/* For Tip to be shown on Time field */
|
||||
'strMysqlAllowedValuesTipTime' => __(
|
||||
'MySQL accepts additional values not selectable by the slider;'
|
||||
. ' key in those values directly if desired'
|
||||
),
|
||||
|
||||
/* For Tip to be shown on Date field */
|
||||
'strMysqlAllowedValuesTipDate' => __(
|
||||
'MySQL accepts additional values not selectable by the datepicker;'
|
||||
. ' key in those values directly if desired'
|
||||
),
|
||||
|
||||
/* For Lock symbol Tooltip */
|
||||
'strLockToolTip' => __(
|
||||
'Indicates that you have made changes to this page;'
|
||||
. ' you will be prompted for confirmation before abandoning changes'
|
||||
),
|
||||
|
||||
/* Designer (js/designer/move.js) */
|
||||
'strSelectReferencedKey' => __('Select referenced key'),
|
||||
'strSelectForeignKey' => __('Select Foreign Key'),
|
||||
'strPleaseSelectPrimaryOrUniqueKey' => __('Please select the primary key or a unique key!'),
|
||||
'strChangeDisplay' => __('Choose column to display'),
|
||||
'strLeavingDesigner' => __(
|
||||
'You haven\'t saved the changes in the layout. They will be lost if you'
|
||||
. ' don\'t save them. Do you want to continue?'
|
||||
),
|
||||
'strQueryEmpty' => __('value/subQuery is empty'),
|
||||
'strAddTables' => __('Add tables from other databases'),
|
||||
'strPageName' => __('Page name'),
|
||||
'strSavePage' => __('Save page'),
|
||||
'strSavePageAs' => __('Save page as'),
|
||||
'strOpenPage' => __('Open page'),
|
||||
'strDeletePage' => __('Delete page'),
|
||||
/* l10n: When the user opens a page saved in the Designer */
|
||||
'strSavedPageTableMissing' => __('Some tables saved in this page might have been renamed or deleted.'),
|
||||
'strUntitled' => __('Untitled'),
|
||||
'strSelectPage' => __('Please select a page to continue'),
|
||||
'strEnterValidPageName' => __('Please enter a valid page name'),
|
||||
'strLeavingPage' => __('Do you want to save the changes to the current page?'),
|
||||
'strSuccessfulPageDelete' => __('Successfully deleted the page'),
|
||||
'strExportRelationalSchema' => __('Export relational schema'),
|
||||
'strModificationSaved' => __('Modifications have been saved'),
|
||||
|
||||
/* Visual query builder (js/designer/move.js) */
|
||||
'strObjectsCreated' => __('%d object(s) created.'),
|
||||
'strColumnName' => __('Column name'),
|
||||
'strSubmit' => __('Submit'),
|
||||
|
||||
/* For makegrid.js (column reordering, show/hide column, grid editing) */
|
||||
'strCellEditHint' => __('Press escape to cancel editing.<br>- Shift+Enter for a newline.'),
|
||||
'strSaveCellWarning' => __(
|
||||
'You have edited some data and they have not been saved. Are you sure you want '
|
||||
. 'to leave this page before saving the data?'
|
||||
),
|
||||
'strColOrderHint' => __('Drag to reorder.'),
|
||||
'strSortHint' => __('Click to sort results by this column.'),
|
||||
'strMultiSortHint' => __(
|
||||
'Shift+Click to add this column to ORDER BY clause or to toggle ASC/DESC.'
|
||||
. '<br>- Ctrl+Click or Alt+Click (Mac: Shift+Option+Click) to remove column '
|
||||
. 'from ORDER BY clause'
|
||||
),
|
||||
'strColMarkHint' => __('Click to mark/unmark.'),
|
||||
'strColNameCopyHint' => __('Double-click to copy column name.'),
|
||||
'strColVisibHint' => __('Click the drop-down arrow<br>to toggle column\'s visibility.'),
|
||||
'strShowAllCol' => __('Show all'),
|
||||
'strAlertNonUnique' => __(
|
||||
'This table does not contain a unique column. Features related to the grid '
|
||||
. 'edit, checkbox, Edit, Copy and Delete links may not work after saving.'
|
||||
),
|
||||
'strEnterValidHex' => __('Please enter a valid hexadecimal string. Valid characters are 0-9, A-F.'),
|
||||
'strShowAllRowsWarning' => __(
|
||||
'Do you really want to see all of the rows? For a big table this could crash the browser.'
|
||||
),
|
||||
'strOriginalLength' => __('Original length'),
|
||||
|
||||
/* Drag & Drop sql import messages */
|
||||
'dropImportMessageCancel' => __('cancel'),
|
||||
'dropImportMessageAborted' => __('Aborted'),
|
||||
'dropImportMessageFailed' => __('Failed'),
|
||||
'dropImportMessageSuccess' => __('Success'),
|
||||
'dropImportImportResultHeader' => __('Import status'),
|
||||
'dropImportDropFiles' => __('Drop files here'),
|
||||
'dropImportSelectDB' => __('Select database first'),
|
||||
|
||||
// this approach does not work when the parameter is changed via user prefs
|
||||
'strGridEditFeatureHint' => $cfg['GridEditing'] === 'double-click'
|
||||
? __('You can also edit most values<br>by double-clicking directly on them.')
|
||||
: ($cfg['GridEditing'] === 'click'
|
||||
? __('You can also edit most values<br>by clicking directly on them.')
|
||||
: ''),
|
||||
|
||||
'strGoToLink' => __('Go to link:'),
|
||||
|
||||
/* password generation */
|
||||
'strGeneratePassword' => __('Generate password'),
|
||||
'strGenerate' => __('Generate'),
|
||||
'strChangePassword' => __('Change password'),
|
||||
|
||||
/* navigation tabs */
|
||||
'strMore' => __('More'),
|
||||
|
||||
/* navigation panel */
|
||||
'strShowPanel' => __('Show panel'),
|
||||
'strHidePanel' => __('Hide panel'),
|
||||
'linkWithMain' => __('Link with main panel'),
|
||||
'unlinkWithMain' => __('Unlink from main panel'),
|
||||
|
||||
/* update */
|
||||
'strNewerVersion' => __(
|
||||
'A newer version of phpMyAdmin is available and you should consider upgrading. '
|
||||
. 'The newest version is %s, released on %s.'
|
||||
),
|
||||
/* l10n: Latest available phpMyAdmin version */
|
||||
'strLatestAvailable' => __(', latest stable version:'),
|
||||
'strUpToDate' => __('up to date'),
|
||||
|
||||
/* Error Reporting */
|
||||
'strErrorOccurred' => __('A fatal JavaScript error has occurred. Would you like to send an error report?'),
|
||||
'strChangeReportSettings' => __('Change report settings'),
|
||||
'strShowReportDetails' => __('Show report details'),
|
||||
'strTimeOutError' => __('Your export is incomplete, due to a low execution time limit at the PHP level!'),
|
||||
|
||||
'strTooManyInputs' => __(
|
||||
'Warning: a form on this page has more than %d fields. On submission, '
|
||||
. "some of the fields might be ignored, due to PHP's "
|
||||
. 'max_input_vars configuration.'
|
||||
),
|
||||
|
||||
'phpErrorsFound' => '<div class="alert alert-danger" role="alert">'
|
||||
. __('Some errors have been detected on the server!')
|
||||
. '<br>'
|
||||
. __('Please look at the bottom of this window.')
|
||||
. '<div>'
|
||||
. '<input id="pma_ignore_errors_popup" type="submit" value="'
|
||||
. __('Ignore')
|
||||
. '" class="btn btn-secondary float-end message_errors_found">'
|
||||
. '<input id="pma_ignore_all_errors_popup" type="submit" value="'
|
||||
. __('Ignore All')
|
||||
. '" class="btn btn-secondary float-end message_errors_found">'
|
||||
. '</div></div>',
|
||||
|
||||
'phpErrorsBeingSubmitted' => '<div class="alert alert-danger" role="alert">'
|
||||
. __('Some errors have been detected on the server!')
|
||||
. '<br>'
|
||||
. __('As per your settings, they are being submitted currently, please be patient.')
|
||||
. '<br>'
|
||||
. '<img src="'
|
||||
. $ajaxClockSmallGifPath
|
||||
. '" width="16" height="16" alt="ajax clock">'
|
||||
. '</div>',
|
||||
'strCopyColumnSuccess' => __('Column name successfully copied to clipboard!'),
|
||||
'strCopyColumnFailure' => __('Column name copying to clipboard failed!'),
|
||||
'strCopyQueryButtonSuccess' => __('Successfully copied!'),
|
||||
'strCopyQueryButtonFailure' => __('Copying failed!'),
|
||||
|
||||
// For console
|
||||
'strConsoleRequeryConfirm' => __('Execute this query again?'),
|
||||
'strConsoleDeleteBookmarkConfirm' => __('Do you really want to delete this bookmark?'),
|
||||
'strConsoleDebugError' => __('Some error occurred while getting SQL debug info.'),
|
||||
'strConsoleDebugSummary' => __('%s queries executed %s times in %s seconds.'),
|
||||
'strConsoleDebugArgsSummary' => __('%s argument(s) passed'),
|
||||
'strConsoleDebugShowArgs' => __('Show arguments'),
|
||||
'strConsoleDebugHideArgs' => __('Hide arguments'),
|
||||
'strConsoleDebugTimeTaken' => __('Time taken:'),
|
||||
'strNoLocalStorage' => __(
|
||||
'There was a problem accessing your browser storage, some features may not'
|
||||
. ' work properly for you. It is likely that the browser doesn\'t support storage'
|
||||
. ' or the quota limit has been reached. In Firefox, corrupted storage can also'
|
||||
. ' cause such a problem, clearing your "Offline Website Data" might help. In Safari,'
|
||||
. ' such problem is commonly caused by "Private Mode Browsing".'
|
||||
),
|
||||
// For modals in /database/structure
|
||||
'strCopyTablesTo' => __('Copy tables to'),
|
||||
'strAddPrefix' => __('Add table prefix'),
|
||||
'strReplacePrefix' => __('Replace table with prefix'),
|
||||
'strCopyPrefix' => __('Copy table with prefix'),
|
||||
|
||||
/* For password strength simulation */
|
||||
'strExtrWeak' => __('Extremely weak'),
|
||||
'strVeryWeak' => __('Very weak'),
|
||||
'strWeak' => __('Weak'),
|
||||
'strGood' => __('Good'),
|
||||
'strStrong' => __('Strong'),
|
||||
|
||||
/* U2F errors */
|
||||
// l10n: error code 5 (from U2F API)
|
||||
'strU2FTimeout' => _pgettext('U2F error', 'Timed out waiting for security key activation.'),
|
||||
// l10n: error code 2 (from U2F API)
|
||||
'strU2FBadRequest' => _pgettext('U2F error', 'Invalid request sent to security key.'),
|
||||
// l10n: unknown error code (from U2F API)
|
||||
'strU2FUnknown' => _pgettext('U2F error', 'Unknown security key error.'),
|
||||
// l10n: error code 3 (from U2F API)
|
||||
'strU2FInvalidClient' => _pgettext('U2F error', 'Client does not support security key.'),
|
||||
// l10n: error code 4 (from U2F API) on register
|
||||
'strU2FErrorRegister' => _pgettext('U2F error', 'Failed security key activation.'),
|
||||
// l10n: error code 4 (from U2F API) on authanticate
|
||||
'strU2FErrorAuthenticate' => _pgettext('U2F error', 'Invalid security key.'),
|
||||
|
||||
'webAuthnNotSupported' => __(
|
||||
'WebAuthn is not available. Please use a supported browser in a secure context (HTTPS).'
|
||||
),
|
||||
|
||||
/* Designer */
|
||||
'strIndexedDBNotWorking' => __(
|
||||
'You can not open, save or delete your page layout, as IndexedDB is not working'
|
||||
. ' in your browser and your phpMyAdmin configuration storage is not configured for this.'
|
||||
),
|
||||
'strTableAlreadyExists' => _pgettext(
|
||||
'The table already exists in the designer and can not be added once more.',
|
||||
'Table %s already exists!'
|
||||
),
|
||||
'strHide' => __('Hide'),
|
||||
'strShow' => __('Show'),
|
||||
'strStructure' => __('Structure'),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple script to set correct charset for the license
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use function __;
|
||||
use function is_readable;
|
||||
use function printf;
|
||||
use function readfile;
|
||||
|
||||
/**
|
||||
* Simple script to set correct charset for the license
|
||||
*/
|
||||
class LicenseController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
$this->response->disable();
|
||||
$this->response->header('Content-type: text/plain; charset=utf-8');
|
||||
|
||||
$filename = LICENSE_FILE;
|
||||
|
||||
// Check if the file is available, some distributions remove these.
|
||||
if (@is_readable($filename)) {
|
||||
readfile($filename);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
__(
|
||||
'The %s file is not available on this system, please visit %s for more information.'
|
||||
),
|
||||
$filename,
|
||||
'https://www.phpmyadmin.net/'
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Represents the interface between the linter and the query editor.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Linter;
|
||||
|
||||
use function json_encode;
|
||||
|
||||
/**
|
||||
* Represents the interface between the linter and the query editor.
|
||||
*/
|
||||
class LintController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
$params = [
|
||||
'sql_query' => $_POST['sql_query'] ?? null,
|
||||
'options' => $_POST['options'] ?? null,
|
||||
];
|
||||
|
||||
/**
|
||||
* The SQL query to be analyzed.
|
||||
*
|
||||
* This does not need to be checked again XSS or MySQL injections because it is
|
||||
* never executed, just parsed.
|
||||
*
|
||||
* The client, which will receive the JSON response will decode the message and
|
||||
* and any HTML fragments that are displayed to the user will be encoded anyway.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
$sqlQuery = ! empty($params['sql_query']) ? $params['sql_query'] : '';
|
||||
|
||||
$this->response->setAjax(true);
|
||||
|
||||
// Disabling standard response.
|
||||
$this->response->disable();
|
||||
|
||||
Core::headerJSON();
|
||||
|
||||
if (! empty($params['options'])) {
|
||||
$options = $params['options'];
|
||||
|
||||
if (! empty($options['routineEditor'])) {
|
||||
$sqlQuery = 'CREATE PROCEDURE `a`() ' . $sqlQuery;
|
||||
} elseif (! empty($options['triggerEditor'])) {
|
||||
$sqlQuery = 'CREATE TRIGGER `a` AFTER INSERT ON `b` FOR EACH ROW ' . $sqlQuery;
|
||||
} elseif (! empty($options['eventEditor'])) {
|
||||
$sqlQuery = 'CREATE EVENT `a` ON SCHEDULE EVERY MINUTE DO ' . $sqlQuery;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(Linter::lint($sqlQuery));
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
|
||||
class LogoutController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $auth_plugin, $token_mismatch;
|
||||
|
||||
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST' || $token_mismatch) {
|
||||
Core::sendHeaderLocation('./index.php?route=/');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$auth_plugin->logOut();
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Navigation\Navigation;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Utils\SessionCache;
|
||||
|
||||
use function __;
|
||||
|
||||
/**
|
||||
* The navigation panel
|
||||
*
|
||||
* Displays server, database and table selection tree.
|
||||
*/
|
||||
class NavigationController extends AbstractController
|
||||
{
|
||||
/** @var Navigation */
|
||||
private $navigation;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Navigation $navigation,
|
||||
Relation $relation
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->navigation = $navigation;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
if (! $this->response->isAjax()) {
|
||||
$this->response->addHTML(
|
||||
Message::error(
|
||||
__('Fatal error: The navigation can only be accessed via AJAX')
|
||||
)->getDisplay()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['getNaviSettings']) && $_POST['getNaviSettings']) {
|
||||
$pageSettings = new PageSettings('Navi', 'pma_navigation_settings');
|
||||
$this->response->addHTML($pageSettings->getErrorHTML());
|
||||
$this->response->addJSON('message', $pageSettings->getHTML());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['reload'])) {
|
||||
SessionCache::set('dbs_to_test', false);// Empty database list cache, see #14252
|
||||
}
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
if ($relationParameters->navigationItemsHidingFeature !== null) {
|
||||
if (isset($_POST['hideNavItem'])) {
|
||||
if (! empty($_POST['itemName']) && ! empty($_POST['itemType']) && ! empty($_POST['dbName'])) {
|
||||
$this->navigation->hideNavigationItem(
|
||||
$_POST['itemName'],
|
||||
$_POST['itemType'],
|
||||
$_POST['dbName'],
|
||||
(! empty($_POST['tableName']) ? $_POST['tableName'] : null)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['unhideNavItem'])) {
|
||||
if (! empty($_POST['itemName']) && ! empty($_POST['itemType']) && ! empty($_POST['dbName'])) {
|
||||
$this->navigation->unhideNavigationItem(
|
||||
$_POST['itemName'],
|
||||
$_POST['itemType'],
|
||||
$_POST['dbName'],
|
||||
(! empty($_POST['tableName']) ? $_POST['tableName'] : null)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['showUnhideDialog'])) {
|
||||
if (! empty($_POST['dbName'])) {
|
||||
$this->response->addJSON(
|
||||
'message',
|
||||
$this->navigation->getItemUnhideDialog($_POST['dbName'])
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->addJSON('message', $this->navigation->getDisplay());
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Normalization;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function __;
|
||||
use function _pgettext;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function min;
|
||||
|
||||
/**
|
||||
* Normalization process (temporarily specific to 1NF).
|
||||
*/
|
||||
class NormalizationController extends AbstractController
|
||||
{
|
||||
/** @var Normalization */
|
||||
private $normalization;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Normalization $normalization)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->normalization = $normalization;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table;
|
||||
|
||||
if (isset($_POST['getColumns'])) {
|
||||
$html = '<option selected disabled>' . __('Select one…') . '</option>'
|
||||
. '<option value="no_such_col">' . __('No such column') . '</option>';
|
||||
//get column whose datatype falls under string category
|
||||
$html .= $this->normalization->getHtmlForColumnsList(
|
||||
$db,
|
||||
$table,
|
||||
_pgettext('string types', 'String')
|
||||
);
|
||||
echo $html;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['splitColumn'])) {
|
||||
$num_fields = min(4096, intval($_POST['numFields']));
|
||||
$html = $this->normalization->getHtmlForCreateNewColumn($num_fields, $db, $table);
|
||||
$html .= Url::getHiddenInputs($db, $table);
|
||||
echo $html;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['addNewPrimary'])) {
|
||||
$num_fields = 1;
|
||||
$columnMeta = [
|
||||
'Field' => $table . '_id',
|
||||
'Extra' => 'auto_increment',
|
||||
];
|
||||
$html = $this->normalization->getHtmlForCreateNewColumn($num_fields, $db, $table, $columnMeta);
|
||||
$html .= Url::getHiddenInputs($db, $table);
|
||||
echo $html;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['findPdl'])) {
|
||||
$html = $this->normalization->findPartialDependencies($table, $db);
|
||||
echo $html;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['getNewTables2NF'])) {
|
||||
$partialDependencies = json_decode($_POST['pd'], true);
|
||||
$html = $this->normalization->getHtmlForNewTables2NF($partialDependencies, $table);
|
||||
echo $html;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['getNewTables3NF'])) {
|
||||
$dependencies = json_decode($_POST['pd']);
|
||||
$tables = json_decode($_POST['tables'], true);
|
||||
$newTables = $this->normalization->getHtmlForNewTables3NF($dependencies, $tables, $db);
|
||||
$this->response->disable();
|
||||
Core::headerJSON();
|
||||
echo json_encode($newTables);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['normalization.js', 'vendor/jquery/jquery.uitablefilter.js']);
|
||||
|
||||
$normalForm = '1nf';
|
||||
if (isset($_POST['normalizeTo']) && in_array($_POST['normalizeTo'], ['1nf', '2nf', '3nf'])) {
|
||||
$normalForm = $_POST['normalizeTo'];
|
||||
}
|
||||
|
||||
if (isset($_POST['createNewTables2NF'])) {
|
||||
$partialDependencies = json_decode($_POST['pd'], true);
|
||||
$tablesName = json_decode($_POST['newTablesName']);
|
||||
$res = $this->normalization->createNewTablesFor2NF($partialDependencies, $tablesName, $table, $db);
|
||||
$this->response->addJSON($res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['createNewTables3NF'])) {
|
||||
$newtables = json_decode($_POST['newTables'], true);
|
||||
$res = $this->normalization->createNewTablesFor3NF($newtables, $db);
|
||||
$this->response->addJSON($res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['repeatingColumns'])) {
|
||||
$repeatingColumns = $_POST['repeatingColumns'];
|
||||
$newTable = $_POST['newTable'];
|
||||
$newColumn = $_POST['newColumn'];
|
||||
$primary_columns = $_POST['primary_columns'];
|
||||
$res = $this->normalization->moveRepeatingGroup(
|
||||
$repeatingColumns,
|
||||
$primary_columns,
|
||||
$newTable,
|
||||
$newColumn,
|
||||
$table,
|
||||
$db
|
||||
);
|
||||
$this->response->addJSON($res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['step1'])) {
|
||||
$html = $this->normalization->getHtmlFor1NFStep1($db, $table, $normalForm);
|
||||
$this->response->addHTML($html);
|
||||
} elseif (isset($_POST['step2'])) {
|
||||
$res = $this->normalization->getHtmlContentsFor1NFStep2($db, $table);
|
||||
$this->response->addJSON($res);
|
||||
} elseif (isset($_POST['step3'])) {
|
||||
$res = $this->normalization->getHtmlContentsFor1NFStep3($db, $table);
|
||||
$this->response->addJSON($res);
|
||||
} elseif (isset($_POST['step4'])) {
|
||||
$res = $this->normalization->getHtmlContentsFor1NFStep4($db, $table);
|
||||
$this->response->addJSON($res);
|
||||
} elseif (isset($_POST['step']) && $_POST['step'] == '2.1') {
|
||||
$res = $this->normalization->getHtmlFor2NFstep1($db, $table);
|
||||
$this->response->addJSON($res);
|
||||
} elseif (isset($_POST['step']) && $_POST['step'] == '3.1') {
|
||||
$tables = $_POST['tables'];
|
||||
$res = $this->normalization->getHtmlFor3NFstep1($db, $tables);
|
||||
$this->response->addJSON($res);
|
||||
} else {
|
||||
$this->response->addHTML($this->normalization->getHtmlForNormalizeTable());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* phpinfo() wrapper to allow displaying only when configured to do so.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use function phpinfo;
|
||||
|
||||
use const INFO_CONFIGURATION;
|
||||
use const INFO_GENERAL;
|
||||
use const INFO_MODULES;
|
||||
|
||||
/**
|
||||
* phpinfo() wrapper to allow displaying only when configured to do so.
|
||||
*/
|
||||
class PhpInfoController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$this->response->disable();
|
||||
$this->response->getHeader()->sendHttpHeaders();
|
||||
|
||||
if (! $cfg['ShowPhpInfo']) {
|
||||
return;
|
||||
}
|
||||
|
||||
phpinfo(INFO_GENERAL | INFO_CONFIGURATION | INFO_MODULES);
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\ExportForm;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function define;
|
||||
use function ltrim;
|
||||
|
||||
class ExportController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $cf, $error, $tabHash, $hash, $server, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new ExportForm($cf, 1);
|
||||
|
||||
if (isset($_POST['revert'])) {
|
||||
// revert erroneous fields to their default values
|
||||
$formDisplay->fixErrors();
|
||||
$this->redirect('/preferences/export');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) {
|
||||
// Load 2FA settings
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
// save back the 2FA setting only
|
||||
$twoFactor->save();
|
||||
if ($result === true) {
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$tabHash = $_POST['tab_hash'] ?? null;
|
||||
$hash = ltrim($tabHash, '#');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/export', null, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
$formErrors = $formDisplay->displayErrors();
|
||||
}
|
||||
|
||||
$this->render('preferences/forms/main', [
|
||||
'error' => $error ? $error->getDisplay() : '',
|
||||
'has_errors' => $formDisplay->hasErrors(),
|
||||
'errors' => $formErrors ?? null,
|
||||
'form' => $formDisplay->getDisplay(
|
||||
true,
|
||||
Url::getFromRoute('/preferences/export'),
|
||||
['server' => $server]
|
||||
),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
} else {
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\FeaturesForm;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function define;
|
||||
use function ltrim;
|
||||
|
||||
class FeaturesController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $cf, $error, $tabHash, $hash, $server, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new FeaturesForm($cf, 1);
|
||||
|
||||
if (isset($_POST['revert'])) {
|
||||
// revert erroneous fields to their default values
|
||||
$formDisplay->fixErrors();
|
||||
$this->redirect('/preferences/features');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) {
|
||||
// Load 2FA settings
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
// save back the 2FA setting only
|
||||
$twoFactor->save();
|
||||
if ($result === true) {
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$tabHash = $_POST['tab_hash'] ?? null;
|
||||
$hash = ltrim($tabHash, '#');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/features', null, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
$formErrors = $formDisplay->displayErrors();
|
||||
}
|
||||
|
||||
$this->render('preferences/forms/main', [
|
||||
'error' => $error ? $error->getDisplay() : '',
|
||||
'has_errors' => $formDisplay->hasErrors(),
|
||||
'errors' => $formErrors ?? null,
|
||||
'form' => $formDisplay->getDisplay(
|
||||
true,
|
||||
Url::getFromRoute('/preferences/features'),
|
||||
['server' => $server]
|
||||
),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
} else {
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\ImportForm;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function define;
|
||||
use function ltrim;
|
||||
|
||||
class ImportController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $cf, $error, $tabHash, $hash, $server, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new ImportForm($cf, 1);
|
||||
|
||||
if (isset($_POST['revert'])) {
|
||||
// revert erroneous fields to their default values
|
||||
$formDisplay->fixErrors();
|
||||
$this->redirect('/preferences/import');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) {
|
||||
// Load 2FA settings
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
// save back the 2FA setting only
|
||||
$twoFactor->save();
|
||||
if ($result === true) {
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$tabHash = $_POST['tab_hash'] ?? null;
|
||||
$hash = ltrim($tabHash, '#');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/import', null, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
$formErrors = $formDisplay->displayErrors();
|
||||
}
|
||||
|
||||
$this->render('preferences/forms/main', [
|
||||
'error' => $error ? $error->getDisplay() : '',
|
||||
'has_errors' => $formDisplay->hasErrors(),
|
||||
'errors' => $formErrors ?? null,
|
||||
'form' => $formDisplay->getDisplay(
|
||||
true,
|
||||
Url::getFromRoute('/preferences/import'),
|
||||
['server' => $server]
|
||||
),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
} else {
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\MainForm;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function define;
|
||||
use function ltrim;
|
||||
|
||||
class MainPanelController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $cf, $error, $tabHash, $hash, $server, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new MainForm($cf, 1);
|
||||
|
||||
if (isset($_POST['revert'])) {
|
||||
// revert erroneous fields to their default values
|
||||
$formDisplay->fixErrors();
|
||||
$this->redirect('/preferences/main-panel');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) {
|
||||
// Load 2FA settings
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
// save back the 2FA setting only
|
||||
$twoFactor->save();
|
||||
if ($result === true) {
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$tabHash = $_POST['tab_hash'] ?? null;
|
||||
$hash = ltrim($tabHash, '#');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/main-panel', null, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
$formErrors = $formDisplay->displayErrors();
|
||||
}
|
||||
|
||||
$this->render('preferences/forms/main', [
|
||||
'error' => $error ? $error->getDisplay() : '',
|
||||
'has_errors' => $formDisplay->hasErrors(),
|
||||
'errors' => $formErrors ?? null,
|
||||
'form' => $formDisplay->getDisplay(
|
||||
true,
|
||||
Url::getFromRoute('/preferences/main-panel'),
|
||||
['server' => $server]
|
||||
),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
} else {
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,283 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\UserFormList;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\File;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\ThemeManager;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_merge;
|
||||
use function define;
|
||||
use function file_exists;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function is_uploaded_file;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function mb_strpos;
|
||||
use function mb_substr;
|
||||
use function parse_url;
|
||||
use function str_replace;
|
||||
use function urlencode;
|
||||
use function var_export;
|
||||
|
||||
use const JSON_PRETTY_PRINT;
|
||||
use const PHP_URL_PATH;
|
||||
use const UPLOAD_ERR_OK;
|
||||
|
||||
/**
|
||||
* User preferences management page.
|
||||
*/
|
||||
class ManageController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cf, $error, $filename, $json, $lang;
|
||||
global $new_config, $return_url, $form_display, $all_ok, $params, $query, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$error = '';
|
||||
if (isset($_POST['submit_export'], $_POST['export_type']) && $_POST['export_type'] === 'text_file') {
|
||||
// export to JSON file
|
||||
$this->response->disable();
|
||||
$filename = 'phpMyAdmin-config-' . urlencode(Core::getenv('HTTP_HOST')) . '.json';
|
||||
Core::downloadHeader($filename, 'application/json');
|
||||
$settings = $this->userPreferences->load();
|
||||
echo json_encode($settings['config_data'], JSON_PRETTY_PRINT);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['submit_export'], $_POST['export_type']) && $_POST['export_type'] === 'php_file') {
|
||||
// export to JSON file
|
||||
$this->response->disable();
|
||||
$filename = 'phpMyAdmin-config-' . urlencode(Core::getenv('HTTP_HOST')) . '.php';
|
||||
Core::downloadHeader($filename, 'application/php');
|
||||
$settings = $this->userPreferences->load();
|
||||
echo '/* ' . __('phpMyAdmin configuration snippet') . " */\n\n";
|
||||
echo '/* ' . __('Paste it to your config.inc.php') . " */\n\n";
|
||||
foreach ($settings['config_data'] as $key => $val) {
|
||||
echo '$cfg[\'' . str_replace('/', '\'][\'', $key) . '\'] = ';
|
||||
echo var_export($val, true) . ";\n";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['submit_get_json'])) {
|
||||
$settings = $this->userPreferences->load();
|
||||
$this->response->addJSON('prefs', json_encode($settings['config_data']));
|
||||
$this->response->addJSON('mtime', $settings['mtime']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_POST['submit_import'])) {
|
||||
// load from JSON file
|
||||
$json = '';
|
||||
if (
|
||||
isset($_POST['import_type'], $_FILES['import_file'])
|
||||
&& $_POST['import_type'] === 'text_file'
|
||||
&& is_array($_FILES['import_file'])
|
||||
&& $_FILES['import_file']['error'] == UPLOAD_ERR_OK
|
||||
&& isset($_FILES['import_file']['tmp_name'])
|
||||
&& is_string($_FILES['import_file']['tmp_name'])
|
||||
&& is_uploaded_file($_FILES['import_file']['tmp_name'])
|
||||
) {
|
||||
$importHandle = new File($_FILES['import_file']['tmp_name']);
|
||||
$importHandle->checkUploadedFile();
|
||||
if ($importHandle->isError()) {
|
||||
$error = $importHandle->getError();
|
||||
} else {
|
||||
// read JSON from uploaded file
|
||||
$json = $importHandle->getRawContent();
|
||||
}
|
||||
} else {
|
||||
// read from POST value (json)
|
||||
$json = $_POST['json'] ?? null;
|
||||
}
|
||||
|
||||
// hide header message
|
||||
$_SESSION['userprefs_autoload'] = true;
|
||||
|
||||
$configuration = json_decode($json, true);
|
||||
$return_url = $_POST['return_url'] ?? null;
|
||||
if (! is_array($configuration)) {
|
||||
if (! isset($error)) {
|
||||
$error = __('Could not import configuration');
|
||||
}
|
||||
} else {
|
||||
// sanitize input values: treat them as though
|
||||
// they came from HTTP POST request
|
||||
$form_display = new UserFormList($cf);
|
||||
$new_config = $cf->getFlatDefaultConfig();
|
||||
if (! empty($_POST['import_merge'])) {
|
||||
$new_config = array_merge($new_config, $cf->getConfigArray());
|
||||
}
|
||||
|
||||
$new_config = array_merge($new_config, $configuration);
|
||||
$_POST_bak = $_POST;
|
||||
foreach ($new_config as $k => $v) {
|
||||
$_POST[str_replace('/', '-', (string) $k)] = $v;
|
||||
}
|
||||
|
||||
$cf->resetConfigData();
|
||||
$all_ok = $form_display->process(true, false);
|
||||
$all_ok = $all_ok && ! $form_display->hasErrors();
|
||||
$_POST = $_POST_bak;
|
||||
|
||||
if (! $all_ok && isset($_POST['fix_errors'])) {
|
||||
$form_display->fixErrors();
|
||||
$all_ok = true;
|
||||
}
|
||||
|
||||
if (! $all_ok) {
|
||||
// mimic original form and post json in a hidden field
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
echo $this->template->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
echo $this->template->render('preferences/manage/error', [
|
||||
'form_errors' => $form_display->displayErrors(),
|
||||
'json' => $json,
|
||||
'import_merge' => $_POST['import_merge'] ?? null,
|
||||
'return_url' => $return_url,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check for ThemeDefault
|
||||
$params = [];
|
||||
$tmanager = ThemeManager::getInstance();
|
||||
if (
|
||||
isset($configuration['ThemeDefault'])
|
||||
&& $tmanager->theme->getId() != $configuration['ThemeDefault']
|
||||
&& $tmanager->checkTheme($configuration['ThemeDefault'])
|
||||
) {
|
||||
$tmanager->setActiveTheme($configuration['ThemeDefault']);
|
||||
$tmanager->setThemeCookie();
|
||||
}
|
||||
|
||||
if (isset($configuration['lang']) && $configuration['lang'] != $lang) {
|
||||
$params['lang'] = $configuration['lang'];
|
||||
}
|
||||
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
if ($result === true) {
|
||||
if ($return_url) {
|
||||
$query = Util::splitURLQuery($return_url);
|
||||
$return_url = parse_url($return_url, PHP_URL_PATH);
|
||||
|
||||
foreach ($query as $q) {
|
||||
$pos = mb_strpos($q, '=');
|
||||
$k = mb_substr($q, 0, (int) $pos);
|
||||
if ($k === 'token') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$params[$k] = mb_substr($q, $pos + 1);
|
||||
}
|
||||
} else {
|
||||
$return_url = 'index.php?route=/preferences/manage';
|
||||
}
|
||||
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$this->userPreferences->redirect($return_url ?? '', $params);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
} elseif (isset($_POST['submit_clear'])) {
|
||||
$result = $this->userPreferences->save([]);
|
||||
if ($result === true) {
|
||||
$params = [];
|
||||
$this->config->removeCookie('pma_collaction_connection');
|
||||
$this->config->removeCookie('pma_lang');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/manage', $params);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
echo $this->template->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($error) {
|
||||
if (! $error instanceof Message) {
|
||||
$error = Message::error($error);
|
||||
}
|
||||
|
||||
$error->getDisplay();
|
||||
}
|
||||
|
||||
echo $this->template->render('preferences/manage/main', [
|
||||
'error' => $error,
|
||||
'max_upload_size' => $GLOBALS['config']->get('max_upload_size'),
|
||||
'exists_setup_and_not_exists_config' => @file_exists(ROOT_PATH . 'setup/index.php')
|
||||
&& ! @file_exists(CONFIG_FILE),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
} else {
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\NaviForm;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function define;
|
||||
use function ltrim;
|
||||
|
||||
class NavigationController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $cf, $error, $tabHash, $hash, $server, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new NaviForm($cf, 1);
|
||||
|
||||
if (isset($_POST['revert'])) {
|
||||
// revert erroneous fields to their default values
|
||||
$formDisplay->fixErrors();
|
||||
$this->redirect('/preferences/navigation');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) {
|
||||
// Load 2FA settings
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
// save back the 2FA setting only
|
||||
$twoFactor->save();
|
||||
if ($result === true) {
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$tabHash = $_POST['tab_hash'] ?? null;
|
||||
$hash = ltrim($tabHash, '#');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/navigation', null, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
$formErrors = $formDisplay->displayErrors();
|
||||
}
|
||||
|
||||
$this->render('preferences/forms/main', [
|
||||
'error' => $error ? $error->getDisplay() : '',
|
||||
'has_errors' => $formDisplay->hasErrors(),
|
||||
'errors' => $formErrors ?? null,
|
||||
'form' => $formDisplay->getDisplay(
|
||||
true,
|
||||
Url::getFromRoute('/preferences/navigation'),
|
||||
['server' => $server]
|
||||
),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\Config;
|
||||
use PhpMyAdmin\Config\ConfigFile;
|
||||
use PhpMyAdmin\Config\Forms\User\SqlForm;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\UserPreferences;
|
||||
|
||||
use function define;
|
||||
use function ltrim;
|
||||
|
||||
class SqlController extends AbstractController
|
||||
{
|
||||
/** @var UserPreferences */
|
||||
private $userPreferences;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
UserPreferences $userPreferences,
|
||||
Relation $relation,
|
||||
Config $config
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->userPreferences = $userPreferences;
|
||||
$this->relation = $relation;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $cf, $error, $tabHash, $hash, $server, $route;
|
||||
|
||||
$cf = new ConfigFile($this->config->baseSettings);
|
||||
$this->userPreferences->pageInit($cf);
|
||||
|
||||
$formDisplay = new SqlForm($cf, 1);
|
||||
|
||||
if (isset($_POST['revert'])) {
|
||||
// revert erroneous fields to their default values
|
||||
$formDisplay->fixErrors();
|
||||
$this->redirect('/preferences/sql');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if ($formDisplay->process(false) && ! $formDisplay->hasErrors()) {
|
||||
// Load 2FA settings
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
// save settings
|
||||
$result = $this->userPreferences->save($cf->getConfigArray());
|
||||
// save back the 2FA setting only
|
||||
$twoFactor->save();
|
||||
if ($result === true) {
|
||||
// reload config
|
||||
$this->config->loadUserPreferences();
|
||||
$tabHash = $_POST['tab_hash'] ?? null;
|
||||
$hash = ltrim($tabHash, '#');
|
||||
$this->userPreferences->redirect('index.php?route=/preferences/sql', null, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $result;
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['config.js']);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
if ($formDisplay->hasErrors()) {
|
||||
$formErrors = $formDisplay->displayErrors();
|
||||
}
|
||||
|
||||
$this->render('preferences/forms/main', [
|
||||
'error' => $error ? $error->getDisplay() : '',
|
||||
'has_errors' => $formDisplay->hasErrors(),
|
||||
'errors' => $formErrors ?? null,
|
||||
'form' => $formDisplay->getDisplay(
|
||||
true,
|
||||
Url::getFromRoute('/preferences/sql'),
|
||||
['server' => $server]
|
||||
),
|
||||
]);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('disableNaviSettings', true);
|
||||
} else {
|
||||
define('PMA_DISABLE_NAVI_SETTINGS', true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Preferences;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\TwoFactor;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
|
||||
class TwoFactorController extends AbstractController
|
||||
{
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Relation $relation)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $route;
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
echo $this->template->render('preferences/header', [
|
||||
'route' => $route,
|
||||
'is_saved' => ! empty($_GET['saved']),
|
||||
'has_config_storage' => $relationParameters->userPreferencesFeature !== null,
|
||||
]);
|
||||
|
||||
$twoFactor = new TwoFactor($cfg['Server']['user']);
|
||||
|
||||
if (isset($_POST['2fa_remove'])) {
|
||||
if (! $twoFactor->check(true)) {
|
||||
echo $this->template->render('preferences/two_factor/confirm', [
|
||||
'form' => $twoFactor->render(),
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$twoFactor->configure('');
|
||||
echo Message::rawNotice(__('Two-factor authentication has been removed.'))->getDisplay();
|
||||
} elseif (isset($_POST['2fa_configure'])) {
|
||||
if (! $twoFactor->configure($_POST['2fa_configure'])) {
|
||||
echo $this->template->render('preferences/two_factor/configure', [
|
||||
'form' => $twoFactor->setup(),
|
||||
'configure' => $_POST['2fa_configure'],
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
echo Message::rawNotice(__('Two-factor authentication has been configured.'))->getDisplay();
|
||||
}
|
||||
|
||||
$backend = $twoFactor->getBackend();
|
||||
echo $this->template->render('preferences/two_factor/main', [
|
||||
'enabled' => $twoFactor->isWritable(),
|
||||
'num_backends' => count($twoFactor->getAvailable()),
|
||||
'backend_id' => $backend::$id,
|
||||
'backend_name' => $backend::getName(),
|
||||
'backend_description' => $backend::getDescription(),
|
||||
'backends' => $twoFactor->getAllBackends(),
|
||||
'missing' => $twoFactor->getMissingDeps(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\RecentFavoriteTable;
|
||||
|
||||
final class RecentTablesListController extends AbstractController
|
||||
{
|
||||
public function __invoke(): void
|
||||
{
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON([
|
||||
'list' => RecentFavoriteTable::getInstance('recent')->getHtmlList(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers;
|
||||
|
||||
use PhpMyAdmin\Export;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* Schema export handler
|
||||
*/
|
||||
class SchemaExportController
|
||||
{
|
||||
/** @var Export */
|
||||
private $export;
|
||||
|
||||
public function __construct(Export $export)
|
||||
{
|
||||
$this->export = $export;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
if (! isset($_POST['export_type'])) {
|
||||
Util::checkParameters(['export_type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include the appropriate Schema Class depending on $export_type
|
||||
* default is PDF
|
||||
*/
|
||||
$this->export->processExportSchema($_POST['export_type']);
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* Handles viewing binary logs
|
||||
*/
|
||||
class BinlogController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* binary log files
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $binaryLogs;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
|
||||
$this->binaryLogs = $this->dbi->fetchResult(
|
||||
'SHOW MASTER LOGS',
|
||||
'Log_name'
|
||||
);
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $errorUrl;
|
||||
|
||||
$params = [
|
||||
'log' => $_POST['log'] ?? null,
|
||||
'pos' => $_POST['pos'] ?? null,
|
||||
'is_full_query' => $_POST['is_full_query'] ?? null,
|
||||
];
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$position = ! empty($params['pos']) ? (int) $params['pos'] : 0;
|
||||
|
||||
$urlParams = [];
|
||||
if (isset($params['log']) && array_key_exists($params['log'], $this->binaryLogs)) {
|
||||
$urlParams['log'] = $params['log'];
|
||||
}
|
||||
|
||||
$isFullQuery = false;
|
||||
if (! empty($params['is_full_query'])) {
|
||||
$isFullQuery = true;
|
||||
$urlParams['is_full_query'] = 1;
|
||||
}
|
||||
|
||||
$sqlQuery = $this->getSqlQuery($params['log'] ?? '', $position, (int) $cfg['MaxRows']);
|
||||
$result = $this->dbi->query($sqlQuery);
|
||||
|
||||
$numRows = $result->numRows();
|
||||
|
||||
$previousParams = $urlParams;
|
||||
$fullQueriesParams = $urlParams;
|
||||
$nextParams = $urlParams;
|
||||
if ($position > 0) {
|
||||
$fullQueriesParams['pos'] = $position;
|
||||
if ($position > $cfg['MaxRows']) {
|
||||
$previousParams['pos'] = $position - $cfg['MaxRows'];
|
||||
}
|
||||
}
|
||||
|
||||
$fullQueriesParams['is_full_query'] = 1;
|
||||
if ($isFullQuery) {
|
||||
unset($fullQueriesParams['is_full_query']);
|
||||
}
|
||||
|
||||
if ($numRows >= $cfg['MaxRows']) {
|
||||
$nextParams['pos'] = $position + $cfg['MaxRows'];
|
||||
}
|
||||
|
||||
$values = $result->fetchAllAssoc();
|
||||
|
||||
$this->render('server/binlog/index', [
|
||||
'url_params' => $urlParams,
|
||||
'binary_logs' => $this->binaryLogs,
|
||||
'log' => $params['log'],
|
||||
'sql_message' => Generator::getMessage(Message::success(), $sqlQuery),
|
||||
'values' => $values,
|
||||
'has_previous' => $position > 0,
|
||||
'has_next' => $numRows >= $cfg['MaxRows'],
|
||||
'previous_params' => $previousParams,
|
||||
'full_queries_params' => $fullQueriesParams,
|
||||
'next_params' => $nextParams,
|
||||
'has_icons' => Util::showIcons('TableNavigationLinksMode'),
|
||||
'is_full_query' => $isFullQuery,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $log Binary log file name
|
||||
* @param int $position Position to display
|
||||
* @param int $maxRows Maximum number of rows
|
||||
*/
|
||||
private function getSqlQuery(
|
||||
string $log,
|
||||
int $position,
|
||||
int $maxRows
|
||||
): string {
|
||||
$sqlQuery = 'SHOW BINLOG EVENTS';
|
||||
if (! empty($log)) {
|
||||
$sqlQuery .= ' IN \'' . $log . '\'';
|
||||
}
|
||||
|
||||
$sqlQuery .= ' LIMIT ' . $position . ', ' . $maxRows;
|
||||
|
||||
return $sqlQuery;
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Charsets\Charset;
|
||||
use PhpMyAdmin\Charsets\Collation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
/**
|
||||
* Handles viewing character sets and collations
|
||||
*/
|
||||
class CollationsController extends AbstractController
|
||||
{
|
||||
/** @var array<string, Charset> */
|
||||
private $charsets;
|
||||
|
||||
/** @var array<string, array<string, Collation>> */
|
||||
private $collations;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/**
|
||||
* @param array<string, Charset>|null $charsets
|
||||
* @param array<string, array<string, Collation>>|null $collations
|
||||
*/
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
DatabaseInterface $dbi,
|
||||
?array $charsets = null,
|
||||
?array $collations = null
|
||||
) {
|
||||
global $cfg;
|
||||
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
|
||||
$this->charsets = $charsets ?? Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$this->collations = $collations ?? Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']);
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$charsets = [];
|
||||
foreach ($this->charsets as $charset) {
|
||||
$charsetCollations = [];
|
||||
foreach ($this->collations[$charset->getName()] as $collation) {
|
||||
$charsetCollations[] = [
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
'is_default' => $collation->isDefault(),
|
||||
];
|
||||
}
|
||||
|
||||
$charsets[] = [
|
||||
'name' => $charset->getName(),
|
||||
'description' => $charset->getDescription(),
|
||||
'collations' => $charsetCollations,
|
||||
];
|
||||
}
|
||||
|
||||
$this->render('server/collations/index', ['charsets' => $charsets]);
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Databases;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_key_exists;
|
||||
use function explode;
|
||||
use function mb_strlen;
|
||||
use function mb_strtolower;
|
||||
use function str_contains;
|
||||
|
||||
final class CreateController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $db;
|
||||
|
||||
$params = [
|
||||
'new_db' => $_POST['new_db'] ?? null,
|
||||
'db_collation' => $_POST['db_collation'] ?? null,
|
||||
];
|
||||
|
||||
if (! isset($params['new_db']) || mb_strlen($params['new_db']) === 0 || ! $this->response->isAjax()) {
|
||||
$this->response->addJSON(['message' => Message::error()]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// lower_case_table_names=1 `DB` becomes `db`
|
||||
if ($this->dbi->getLowerCaseNames() === '1') {
|
||||
$params['new_db'] = mb_strtolower($params['new_db']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and executes the db creation sql query
|
||||
*/
|
||||
$sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']);
|
||||
if (! empty($params['db_collation'])) {
|
||||
[$databaseCharset] = explode('_', $params['db_collation']);
|
||||
$charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']);
|
||||
if (
|
||||
array_key_exists($databaseCharset, $charsets)
|
||||
&& array_key_exists($params['db_collation'], $collations[$databaseCharset])
|
||||
) {
|
||||
$sqlQuery .= ' DEFAULT'
|
||||
. Util::getCharsetQueryPart($params['db_collation']);
|
||||
}
|
||||
}
|
||||
|
||||
$sqlQuery .= ';';
|
||||
|
||||
$result = $this->dbi->tryQuery($sqlQuery);
|
||||
|
||||
if (! $result) {
|
||||
// avoid displaying the not-created db name in header or navi panel
|
||||
$db = '';
|
||||
|
||||
$message = Message::rawError($this->dbi->getError());
|
||||
$json = ['message' => $message];
|
||||
|
||||
$this->response->setRequestStatus(false);
|
||||
} else {
|
||||
$db = $params['new_db'];
|
||||
|
||||
$message = Message::success(__('Database %1$s has been created.'));
|
||||
$message->addParam($params['new_db']);
|
||||
|
||||
$scriptName = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
|
||||
$json = [
|
||||
'message' => $message,
|
||||
'sql_query' => Generator::getMessage('', $sqlQuery, 'success'),
|
||||
'url' => $scriptName . Url::getCommon(
|
||||
['db' => $params['new_db']],
|
||||
! str_contains($scriptName, '?') ? '?' : '&'
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
$this->response->addJSON($json);
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Databases;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Transformations;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function _ngettext;
|
||||
use function count;
|
||||
use function is_array;
|
||||
|
||||
final class DestroyController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
/** @var Transformations */
|
||||
private $transformations;
|
||||
|
||||
/** @var RelationCleanup */
|
||||
private $relationCleanup;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
DatabaseInterface $dbi,
|
||||
Transformations $transformations,
|
||||
RelationCleanup $relationCleanup
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
$this->transformations = $transformations;
|
||||
$this->relationCleanup = $relationCleanup;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $selected, $errorUrl, $cfg, $dblist, $reload;
|
||||
|
||||
$selected_dbs = $_POST['selected_dbs'] ?? null;
|
||||
|
||||
if (
|
||||
! $this->response->isAjax()
|
||||
|| (! $this->dbi->isSuperUser() && ! $cfg['AllowUserDropDatabase'])
|
||||
) {
|
||||
$message = Message::error();
|
||||
$json = ['message' => $message];
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON($json);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
! is_array($selected_dbs)
|
||||
|| $selected_dbs === []
|
||||
) {
|
||||
$message = Message::error(__('No databases selected.'));
|
||||
$json = ['message' => $message];
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON($json);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$errorUrl = Url::getFromRoute('/server/databases');
|
||||
$selected = $selected_dbs;
|
||||
$numberOfDatabases = count($selected_dbs);
|
||||
|
||||
foreach ($selected_dbs as $database) {
|
||||
$this->relationCleanup->database($database);
|
||||
$aQuery = 'DROP DATABASE ' . Util::backquote($database);
|
||||
$reload = true;
|
||||
|
||||
$this->dbi->query($aQuery);
|
||||
$this->transformations->clear($database);
|
||||
}
|
||||
|
||||
$dblist->databases->build();
|
||||
|
||||
$message = Message::success(
|
||||
_ngettext(
|
||||
'%1$d database has been dropped successfully.',
|
||||
'%1$d databases have been dropped successfully.',
|
||||
$numberOfDatabases
|
||||
)
|
||||
);
|
||||
$message->addParam($numberOfDatabases);
|
||||
$json = ['message' => $message];
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON($json);
|
||||
}
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Query\Utilities;
|
||||
use PhpMyAdmin\ReplicationInfo;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Transformations;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_keys;
|
||||
use function array_search;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function mb_strtolower;
|
||||
use function str_contains;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
* Handles viewing and creating and deleting databases
|
||||
*/
|
||||
class DatabasesController extends AbstractController
|
||||
{
|
||||
/** @var array array of database details */
|
||||
private $databases = [];
|
||||
|
||||
/** @var int number of databases */
|
||||
private $databaseCount = 0;
|
||||
|
||||
/** @var string sort by column */
|
||||
private $sortBy;
|
||||
|
||||
/** @var string sort order of databases */
|
||||
private $sortOrder;
|
||||
|
||||
/** @var bool whether to show database statistics */
|
||||
private $hasStatistics;
|
||||
|
||||
/** @var int position in list navigation */
|
||||
private $position;
|
||||
|
||||
/** @var Transformations */
|
||||
private $transformations;
|
||||
|
||||
/** @var RelationCleanup */
|
||||
private $relationCleanup;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Transformations $transformations,
|
||||
RelationCleanup $relationCleanup,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->transformations = $transformations;
|
||||
$this->relationCleanup = $relationCleanup;
|
||||
$this->dbi = $dbi;
|
||||
|
||||
$checkUserPrivileges = new CheckUserPrivileges($dbi);
|
||||
$checkUserPrivileges->getPrivileges();
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $cfg, $server, $dblist, $is_create_db_priv;
|
||||
global $db_to_create, $text_dir, $errorUrl;
|
||||
|
||||
$params = [
|
||||
'statistics' => $_REQUEST['statistics'] ?? null,
|
||||
'pos' => $_REQUEST['pos'] ?? null,
|
||||
'sort_by' => $_REQUEST['sort_by'] ?? null,
|
||||
'sort_order' => $_REQUEST['sort_order'] ?? null,
|
||||
];
|
||||
|
||||
$this->addScriptFiles(['server/databases.js']);
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$replicationInfo = new ReplicationInfo($this->dbi);
|
||||
$replicationInfo->load($_POST['primary_connection'] ?? null);
|
||||
|
||||
$primaryInfo = $replicationInfo->getPrimaryInfo();
|
||||
$replicaInfo = $replicationInfo->getReplicaInfo();
|
||||
|
||||
$this->setSortDetails($params['sort_by'], $params['sort_order']);
|
||||
$this->hasStatistics = ! empty($params['statistics']);
|
||||
$this->position = ! empty($params['pos']) ? (int) $params['pos'] : 0;
|
||||
|
||||
/**
|
||||
* Gets the databases list
|
||||
*/
|
||||
if ($server > 0) {
|
||||
$this->databases = $this->dbi->getDatabasesFull(
|
||||
null,
|
||||
$this->hasStatistics,
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
$this->sortBy,
|
||||
$this->sortOrder,
|
||||
$this->position,
|
||||
true
|
||||
);
|
||||
$this->databaseCount = count($dblist->databases);
|
||||
}
|
||||
|
||||
$urlParams = [
|
||||
'statistics' => $this->hasStatistics,
|
||||
'pos' => $this->position,
|
||||
'sort_by' => $this->sortBy,
|
||||
'sort_order' => $this->sortOrder,
|
||||
];
|
||||
|
||||
$databases = $this->getDatabases($primaryInfo, $replicaInfo);
|
||||
|
||||
$charsetsList = [];
|
||||
if ($cfg['ShowCreateDb'] && $is_create_db_priv) {
|
||||
$charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$collations = Charsets::getCollations($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$serverCollation = $this->dbi->getServerCollation();
|
||||
foreach ($charsets as $charset) {
|
||||
$collationsList = [];
|
||||
foreach ($collations[$charset->getName()] as $collation) {
|
||||
$collationsList[] = [
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
'is_selected' => $serverCollation === $collation->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
$charsetsList[] = [
|
||||
'name' => $charset->getName(),
|
||||
'description' => $charset->getDescription(),
|
||||
'collations' => $collationsList,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$headerStatistics = $this->getStatisticsColumns();
|
||||
|
||||
$this->render('server/databases/index', [
|
||||
'is_create_database_shown' => $cfg['ShowCreateDb'],
|
||||
'has_create_database_privileges' => $is_create_db_priv,
|
||||
'has_statistics' => $this->hasStatistics,
|
||||
'database_to_create' => $db_to_create,
|
||||
'databases' => $databases['databases'],
|
||||
'total_statistics' => $databases['total_statistics'],
|
||||
'header_statistics' => $headerStatistics,
|
||||
'charsets' => $charsetsList,
|
||||
'database_count' => $this->databaseCount,
|
||||
'pos' => $this->position,
|
||||
'url_params' => $urlParams,
|
||||
'max_db_list' => $cfg['MaxDbList'],
|
||||
'has_primary_replication' => $primaryInfo['status'],
|
||||
'has_replica_replication' => $replicaInfo['status'],
|
||||
'is_drop_allowed' => $this->dbi->isSuperUser() || $cfg['AllowUserDropDatabase'],
|
||||
'text_dir' => $text_dir,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts parameters sort order and sort by
|
||||
*
|
||||
* @param string|null $sortBy sort by
|
||||
* @param string|null $sortOrder sort order
|
||||
*/
|
||||
private function setSortDetails(?string $sortBy, ?string $sortOrder): void
|
||||
{
|
||||
if (empty($sortBy)) {
|
||||
$this->sortBy = 'SCHEMA_NAME';
|
||||
} else {
|
||||
$sortByAllowList = [
|
||||
'SCHEMA_NAME',
|
||||
'DEFAULT_COLLATION_NAME',
|
||||
'SCHEMA_TABLES',
|
||||
'SCHEMA_TABLE_ROWS',
|
||||
'SCHEMA_DATA_LENGTH',
|
||||
'SCHEMA_INDEX_LENGTH',
|
||||
'SCHEMA_LENGTH',
|
||||
'SCHEMA_DATA_FREE',
|
||||
];
|
||||
$this->sortBy = 'SCHEMA_NAME';
|
||||
if (in_array($sortBy, $sortByAllowList)) {
|
||||
$this->sortBy = $sortBy;
|
||||
}
|
||||
}
|
||||
|
||||
$this->sortOrder = 'asc';
|
||||
if (! isset($sortOrder) || mb_strtolower($sortOrder) !== 'desc') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sortOrder = 'desc';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $primaryInfo
|
||||
* @param array $replicaInfo
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getDatabases($primaryInfo, $replicaInfo): array
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$databases = [];
|
||||
$totalStatistics = $this->getStatisticsColumns();
|
||||
foreach ($this->databases as $database) {
|
||||
$replication = [
|
||||
'primary' => ['status' => $primaryInfo['status']],
|
||||
'replica' => ['status' => $replicaInfo['status']],
|
||||
];
|
||||
|
||||
if ($primaryInfo['status']) {
|
||||
$key = array_search($database['SCHEMA_NAME'], $primaryInfo['Ignore_DB']);
|
||||
$replication['primary']['is_replicated'] = false;
|
||||
|
||||
if (strlen((string) $key) === 0) {
|
||||
$key = array_search($database['SCHEMA_NAME'], $primaryInfo['Do_DB']);
|
||||
|
||||
if (strlen((string) $key) > 0 || count($primaryInfo['Do_DB']) === 0) {
|
||||
$replication['primary']['is_replicated'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($replicaInfo['status']) {
|
||||
$key = array_search($database['SCHEMA_NAME'], $replicaInfo['Ignore_DB']);
|
||||
$replication['replica']['is_replicated'] = false;
|
||||
|
||||
if (strlen((string) $key) === 0) {
|
||||
$key = array_search($database['SCHEMA_NAME'], $replicaInfo['Do_DB']);
|
||||
|
||||
if (strlen((string) $key) > 0 || count($replicaInfo['Do_DB']) === 0) {
|
||||
$replication['replica']['is_replicated'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$statistics = $this->getStatisticsColumns();
|
||||
if ($this->hasStatistics) {
|
||||
foreach (array_keys($statistics) as $key) {
|
||||
$statistics[$key]['raw'] = (int) ($database[$key] ?? 0);
|
||||
$totalStatistics[$key]['raw'] += (int) ($database[$key] ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
$url = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
|
||||
$url .= Url::getCommonRaw(
|
||||
['db' => $database['SCHEMA_NAME']],
|
||||
! str_contains($url, '?') ? '?' : '&'
|
||||
);
|
||||
$databases[$database['SCHEMA_NAME']] = [
|
||||
'name' => $database['SCHEMA_NAME'],
|
||||
'collation' => [],
|
||||
'statistics' => $statistics,
|
||||
'replication' => $replication,
|
||||
'is_system_schema' => Utilities::isSystemSchema($database['SCHEMA_NAME'], true),
|
||||
'is_pmadb' => $database['SCHEMA_NAME'] === ($cfg['Server']['pmadb'] ?? ''),
|
||||
'url' => $url,
|
||||
];
|
||||
$collation = Charsets::findCollationByName(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS'],
|
||||
$database['DEFAULT_COLLATION_NAME']
|
||||
);
|
||||
if ($collation === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$databases[$database['SCHEMA_NAME']]['collation'] = [
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'databases' => $databases,
|
||||
'total_statistics' => $totalStatistics,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the statistics columns
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getStatisticsColumns(): array
|
||||
{
|
||||
return [
|
||||
'SCHEMA_TABLES' => [
|
||||
'title' => __('Tables'),
|
||||
'format' => 'number',
|
||||
'raw' => 0,
|
||||
],
|
||||
'SCHEMA_TABLE_ROWS' => [
|
||||
'title' => __('Rows'),
|
||||
'format' => 'number',
|
||||
'raw' => 0,
|
||||
],
|
||||
'SCHEMA_DATA_LENGTH' => [
|
||||
'title' => __('Data'),
|
||||
'format' => 'byte',
|
||||
'raw' => 0,
|
||||
],
|
||||
'SCHEMA_INDEX_LENGTH' => [
|
||||
'title' => __('Indexes'),
|
||||
'format' => 'byte',
|
||||
'raw' => 0,
|
||||
],
|
||||
'SCHEMA_LENGTH' => [
|
||||
'title' => __('Total'),
|
||||
'format' => 'byte',
|
||||
'raw' => 0,
|
||||
],
|
||||
'SCHEMA_DATA_FREE' => [
|
||||
'title' => __('Overhead'),
|
||||
'format' => 'byte',
|
||||
'raw' => 0,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
/**
|
||||
* Handles viewing storage engine details
|
||||
*/
|
||||
class EnginesController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$this->render('server/engines/index', [
|
||||
'engines' => StorageEngine::getStorageEngines(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Export\Options;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function __;
|
||||
use function array_merge;
|
||||
|
||||
final class ExportController extends AbstractController
|
||||
{
|
||||
/** @var Options */
|
||||
private $export;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Options $export, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->export = $export;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $sql_query, $num_tables, $unlim_num_rows;
|
||||
global $tmp_select, $select_item, $errorUrl;
|
||||
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$pageSettings = new PageSettings('Export');
|
||||
$pageSettingsErrorHtml = $pageSettings->getErrorHTML();
|
||||
$pageSettingsHtml = $pageSettings->getHTML();
|
||||
|
||||
$this->addScriptFiles(['export.js']);
|
||||
|
||||
$select_item = $tmp_select ?? '';
|
||||
$databases = $this->export->getDatabasesForSelectOptions($select_item);
|
||||
|
||||
if (! isset($sql_query)) {
|
||||
$sql_query = '';
|
||||
}
|
||||
|
||||
if (! isset($num_tables)) {
|
||||
$num_tables = 0;
|
||||
}
|
||||
|
||||
if (! isset($unlim_num_rows)) {
|
||||
$unlim_num_rows = 0;
|
||||
}
|
||||
|
||||
$GLOBALS['single_table'] = $_POST['single_table'] ?? $_GET['single_table'] ?? $GLOBALS['single_table'] ?? null;
|
||||
|
||||
$exportList = Plugins::getExport('server', isset($GLOBALS['single_table']));
|
||||
|
||||
if (empty($exportList)) {
|
||||
$this->response->addHTML(Message::error(
|
||||
__('Could not load export plugins, please check your installation!')
|
||||
)->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$options = $this->export->getOptions(
|
||||
'server',
|
||||
$db,
|
||||
$table,
|
||||
$sql_query,
|
||||
$num_tables,
|
||||
$unlim_num_rows,
|
||||
$exportList
|
||||
);
|
||||
|
||||
$this->render('server/export/index', array_merge($options, [
|
||||
'page_settings_error_html' => $pageSettingsErrorHtml,
|
||||
'page_settings_html' => $pageSettingsHtml,
|
||||
'databases' => $databases,
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\Import;
|
||||
use PhpMyAdmin\Import\Ajax;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Utils\ForeignKey;
|
||||
|
||||
use function __;
|
||||
use function intval;
|
||||
use function is_numeric;
|
||||
|
||||
final class ImportController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $SESSION_KEY, $cfg, $errorUrl;
|
||||
|
||||
$pageSettings = new PageSettings('Import');
|
||||
$pageSettingsErrorHtml = $pageSettings->getErrorHTML();
|
||||
$pageSettingsHtml = $pageSettings->getHTML();
|
||||
|
||||
$this->addScriptFiles(['import.js']);
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
[$SESSION_KEY, $uploadId] = Ajax::uploadProgressSetup();
|
||||
|
||||
$importList = Plugins::getImport('server');
|
||||
|
||||
if (empty($importList)) {
|
||||
$this->response->addHTML(Message::error(__(
|
||||
'Could not load import plugins, please check your installation!'
|
||||
))->getDisplay());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$offset = null;
|
||||
if (isset($_REQUEST['offset']) && is_numeric($_REQUEST['offset'])) {
|
||||
$offset = intval($_REQUEST['offset']);
|
||||
}
|
||||
|
||||
$timeoutPassed = $_REQUEST['timeout_passed'] ?? null;
|
||||
$localImportFile = $_REQUEST['local_import_file'] ?? null;
|
||||
$compressions = Import::getCompressions();
|
||||
|
||||
$charsets = Charsets::getCharsets($this->dbi, $cfg['Server']['DisableIS']);
|
||||
|
||||
$idKey = $_SESSION[$SESSION_KEY]['handler']::getIdKey();
|
||||
$hiddenInputs = [
|
||||
$idKey => $uploadId,
|
||||
'import_type' => 'server',
|
||||
];
|
||||
|
||||
$default = isset($_GET['format']) ? (string) $_GET['format'] : Plugins::getDefault('Import', 'format');
|
||||
$choice = Plugins::getChoice($importList, $default);
|
||||
$options = Plugins::getOptions('Import', $importList);
|
||||
$skipQueriesDefault = Plugins::getDefault('Import', 'skip_queries');
|
||||
$isAllowInterruptChecked = Plugins::checkboxCheck('Import', 'allow_interrupt');
|
||||
$maxUploadSize = (int) $GLOBALS['config']->get('max_upload_size');
|
||||
|
||||
$this->render('server/import/index', [
|
||||
'page_settings_error_html' => $pageSettingsErrorHtml,
|
||||
'page_settings_html' => $pageSettingsHtml,
|
||||
'upload_id' => $uploadId,
|
||||
'handler' => $_SESSION[$SESSION_KEY]['handler'],
|
||||
'hidden_inputs' => $hiddenInputs,
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'max_upload_size' => $maxUploadSize,
|
||||
'formatted_maximum_upload_size' => Util::getFormattedMaximumUploadSize($maxUploadSize),
|
||||
'plugins_choice' => $choice,
|
||||
'options' => $options,
|
||||
'skip_queries_default' => $skipQueriesDefault,
|
||||
'is_allow_interrupt_checked' => $isAllowInterruptChecked,
|
||||
'local_import_file' => $localImportFile,
|
||||
'is_upload' => $GLOBALS['config']->get('enable_upload'),
|
||||
'upload_dir' => $cfg['UploadDir'] ?? null,
|
||||
'timeout_passed_global' => $GLOBALS['timeout_passed'] ?? null,
|
||||
'compressions' => $compressions,
|
||||
'is_encoding_supported' => Encoding::isSupported(),
|
||||
'encodings' => Encoding::listEncodings(),
|
||||
'import_charset' => $cfg['Import']['charset'] ?? null,
|
||||
'timeout_passed' => $timeoutPassed,
|
||||
'offset' => $offset,
|
||||
'can_convert_kanji' => Encoding::canConvertKanji(),
|
||||
'charsets' => $charsets,
|
||||
'is_foreign_key_check' => ForeignKey::isCheckEnabled(),
|
||||
'user_upload_dir' => Util::userDir((string) ($cfg['UploadDir'] ?? '')),
|
||||
'local_files' => Import::getLocalFiles($importList),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Plugins;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function array_keys;
|
||||
use function ksort;
|
||||
use function mb_strtolower;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* Handles viewing server plugin details
|
||||
*/
|
||||
class PluginsController extends AbstractController
|
||||
{
|
||||
/** @var Plugins */
|
||||
private $plugins;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Plugins $plugins,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->plugins = $plugins;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$this->addScriptFiles(['vendor/jquery/jquery.tablesorter.js', 'server/plugins.js']);
|
||||
|
||||
$plugins = [];
|
||||
$serverPlugins = $this->plugins->getAll();
|
||||
foreach ($serverPlugins as $plugin) {
|
||||
$plugins[$plugin->getType()][] = $plugin->toArray();
|
||||
}
|
||||
|
||||
ksort($plugins);
|
||||
|
||||
$cleanTypes = [];
|
||||
foreach (array_keys($plugins) as $type) {
|
||||
$cleanTypes[$type] = preg_replace(
|
||||
'/[^a-z]/',
|
||||
'',
|
||||
mb_strtolower($type)
|
||||
);
|
||||
}
|
||||
|
||||
$this->render('server/plugins/index', [
|
||||
'plugins' => $plugins,
|
||||
'clean_types' => $cleanTypes,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Privileges;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Privileges\AccountLocking;
|
||||
use PhpMyAdmin\Template;
|
||||
use Throwable;
|
||||
|
||||
use function __;
|
||||
|
||||
final class AccountLockController extends AbstractController
|
||||
{
|
||||
/** @var AccountLocking */
|
||||
private $model;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, AccountLocking $accountLocking)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->model = $accountLocking;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
$this->response->setAjax(true);
|
||||
|
||||
/** @var string $userName */
|
||||
$userName = $request->getParsedBodyParam('username');
|
||||
/** @var string $hostName */
|
||||
$hostName = $request->getParsedBodyParam('hostname');
|
||||
|
||||
try {
|
||||
$this->model->lock($userName, $hostName);
|
||||
} catch (Throwable $exception) {
|
||||
$this->response->setHttpResponseCode(400);
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(['message' => Message::error($exception->getMessage())]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$message = Message::success(__('The account %s@%s has been successfully locked.'));
|
||||
$message->addParam($userName);
|
||||
$message->addParam($hostName);
|
||||
$this->response->addJSON(['message' => $message]);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Privileges;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Privileges\AccountLocking;
|
||||
use PhpMyAdmin\Template;
|
||||
use Throwable;
|
||||
|
||||
use function __;
|
||||
|
||||
final class AccountUnlockController extends AbstractController
|
||||
{
|
||||
/** @var AccountLocking */
|
||||
private $model;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, AccountLocking $accountLocking)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->model = $accountLocking;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequest $request): void
|
||||
{
|
||||
$this->response->setAjax(true);
|
||||
|
||||
/** @var string $userName */
|
||||
$userName = $request->getParsedBodyParam('username');
|
||||
/** @var string $hostName */
|
||||
$hostName = $request->getParsedBodyParam('hostname');
|
||||
|
||||
try {
|
||||
$this->model->unlock($userName, $hostName);
|
||||
} catch (Throwable $exception) {
|
||||
$this->response->setHttpResponseCode(400);
|
||||
$this->response->setRequestStatus(false);
|
||||
$this->response->addJSON(['message' => Message::error($exception->getMessage())]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$message = Message::success(__('The account %s@%s has been successfully unlocked.'));
|
||||
$message->addParam($userName);
|
||||
$message->addParam($hostName);
|
||||
$this->response->addJSON(['message' => $message]);
|
||||
}
|
||||
}
|
|
@ -1,475 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\CheckUserPrivileges;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\ConfigStorage\RelationCleanup;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\Controllers\Database\PrivilegesController as DatabaseController;
|
||||
use PhpMyAdmin\Controllers\Table\PrivilegesController as TableController;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Html\Generator;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Plugins;
|
||||
use PhpMyAdmin\Server\Privileges;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function header;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use function str_replace;
|
||||
use function urlencode;
|
||||
|
||||
/**
|
||||
* Server privileges and users manipulations.
|
||||
*/
|
||||
class PrivilegesController extends AbstractController
|
||||
{
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Relation $relation,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->relation = $relation;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $db, $table, $errorUrl, $message, $text_dir, $post_patterns;
|
||||
global $username, $hostname, $dbname, $tablename, $routinename, $db_and_table, $dbname_is_wildcard;
|
||||
global $queries, $password, $ret_message, $ret_queries, $queries_for_display, $sql_query, $_add_user_error;
|
||||
global $itemType, $tables, $num_tables, $total_num_tables, $sub_part;
|
||||
global $tooltip_truename, $tooltip_aliasname, $pos, $title, $export, $grants, $one_grant, $url_dbname;
|
||||
|
||||
$checkUserPrivileges = new CheckUserPrivileges($this->dbi);
|
||||
$checkUserPrivileges->getPrivileges();
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$this->addScriptFiles(['server/privileges.js', 'vendor/zxcvbn-ts.js']);
|
||||
|
||||
$relationCleanup = new RelationCleanup($this->dbi, $this->relation);
|
||||
$serverPrivileges = new Privileges(
|
||||
$this->template,
|
||||
$this->dbi,
|
||||
$this->relation,
|
||||
$relationCleanup,
|
||||
new Plugins($this->dbi)
|
||||
);
|
||||
|
||||
$databaseController = new DatabaseController(
|
||||
$this->response,
|
||||
$this->template,
|
||||
$db,
|
||||
$serverPrivileges,
|
||||
$this->dbi
|
||||
);
|
||||
|
||||
$tableController = new TableController(
|
||||
$this->response,
|
||||
$this->template,
|
||||
$db,
|
||||
$table,
|
||||
$serverPrivileges,
|
||||
$this->dbi
|
||||
);
|
||||
|
||||
if (
|
||||
(isset($_GET['viewing_mode'])
|
||||
&& $_GET['viewing_mode'] === 'server')
|
||||
&& $relationParameters->configurableMenusFeature !== null
|
||||
) {
|
||||
$this->response->addHTML('<div class="container-fluid">');
|
||||
$this->render('server/privileges/subnav', [
|
||||
'active' => 'privileges',
|
||||
'is_super_user' => $this->dbi->isSuperUser(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets globals from $_POST patterns, for privileges and max_* vars
|
||||
*/
|
||||
$post_patterns = [
|
||||
'/_priv$/i',
|
||||
'/^max_/i',
|
||||
];
|
||||
|
||||
Core::setPostAsGlobal($post_patterns);
|
||||
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$_add_user_error = false;
|
||||
/**
|
||||
* Get DB information: username, hostname, dbname,
|
||||
* tablename, db_and_table, dbname_is_wildcard
|
||||
*/
|
||||
[
|
||||
$username,
|
||||
$hostname,
|
||||
$dbname,
|
||||
$tablename,
|
||||
$routinename,
|
||||
$db_and_table,
|
||||
$dbname_is_wildcard,
|
||||
] = $serverPrivileges->getDataForDBInfo();
|
||||
|
||||
/**
|
||||
* Checks if the user is allowed to do what they try to...
|
||||
*/
|
||||
$isGrantUser = $this->dbi->isGrantUser();
|
||||
$isCreateUser = $this->dbi->isCreateUser();
|
||||
|
||||
if (! $this->dbi->isSuperUser() && ! $isGrantUser && ! $isCreateUser) {
|
||||
$this->render('server/sub_page_header', [
|
||||
'type' => 'privileges',
|
||||
'is_image' => false,
|
||||
]);
|
||||
$this->response->addHTML(
|
||||
Message::error(__('No Privileges'))
|
||||
->getDisplay()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $isGrantUser && ! $isCreateUser) {
|
||||
$this->response->addHTML(Message::notice(
|
||||
__('You do not have the privileges to administrate the users!')
|
||||
)->getDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user is using "Change Login Information / Copy User" dialog
|
||||
* only to update the password
|
||||
*/
|
||||
if (
|
||||
isset($_POST['change_copy']) && $username == $_POST['old_username']
|
||||
&& $hostname == $_POST['old_hostname']
|
||||
) {
|
||||
$this->response->addHTML(
|
||||
Message::error(
|
||||
__(
|
||||
"Username and hostname didn't change. "
|
||||
. 'If you only want to change the password, '
|
||||
. "'Change password' tab should be used."
|
||||
)
|
||||
)->getDisplay()
|
||||
);
|
||||
$this->response->setRequestStatus(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes / copies a user, part I
|
||||
*/
|
||||
[$queries, $password] = $serverPrivileges->getDataForChangeOrCopyUser();
|
||||
|
||||
/**
|
||||
* Adds a user
|
||||
* (Changes / copies a user, part II)
|
||||
*/
|
||||
[
|
||||
$ret_message,
|
||||
$ret_queries,
|
||||
$queries_for_display,
|
||||
$sql_query,
|
||||
$_add_user_error,
|
||||
] = $serverPrivileges->addUser(
|
||||
$dbname ?? null,
|
||||
$username ?? '',
|
||||
$hostname ?? '',
|
||||
$password ?? null,
|
||||
$relationParameters->configurableMenusFeature !== null
|
||||
);
|
||||
//update the old variables
|
||||
if (isset($ret_queries)) {
|
||||
$queries = $ret_queries;
|
||||
unset($ret_queries);
|
||||
}
|
||||
|
||||
if (isset($ret_message)) {
|
||||
$message = $ret_message;
|
||||
unset($ret_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes / copies a user, part III
|
||||
*/
|
||||
if (isset($_POST['change_copy']) && $username !== null && $hostname !== null) {
|
||||
$queries = $serverPrivileges->getDbSpecificPrivsQueriesForChangeOrCopyUser($queries, $username, $hostname);
|
||||
}
|
||||
|
||||
$itemType = '';
|
||||
if (! empty($routinename) && is_string($dbname)) {
|
||||
$itemType = $serverPrivileges->getRoutineType($dbname, $routinename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates privileges
|
||||
*/
|
||||
if (! empty($_POST['update_privs'])) {
|
||||
if (is_array($dbname)) {
|
||||
foreach ($dbname as $key => $db_name) {
|
||||
[$sql_query[$key], $message] = $serverPrivileges->updatePrivileges(
|
||||
($username ?? ''),
|
||||
($hostname ?? ''),
|
||||
($tablename ?? ($routinename ?? '')),
|
||||
($db_name ?? ''),
|
||||
$itemType
|
||||
);
|
||||
}
|
||||
|
||||
$sql_query = implode("\n", $sql_query);
|
||||
} else {
|
||||
[$sql_query, $message] = $serverPrivileges->updatePrivileges(
|
||||
($username ?? ''),
|
||||
($hostname ?? ''),
|
||||
($tablename ?? ($routinename ?? '')),
|
||||
($dbname ?? ''),
|
||||
$itemType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign users to user groups
|
||||
*/
|
||||
if (
|
||||
! empty($_POST['changeUserGroup']) && $relationParameters->configurableMenusFeature !== null
|
||||
&& $this->dbi->isSuperUser() && $this->dbi->isCreateUser()
|
||||
) {
|
||||
$serverPrivileges->setUserGroup($username ?? '', $_POST['userGroup']);
|
||||
$message = Message::success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes Privileges
|
||||
*/
|
||||
if (isset($_POST['revokeall'])) {
|
||||
[$message, $sql_query] = $serverPrivileges->getMessageAndSqlQueryForPrivilegesRevoke(
|
||||
(is_string($dbname) ? $dbname : ''),
|
||||
($tablename ?? ($routinename ?? '')),
|
||||
$username ?? '',
|
||||
$hostname ?? '',
|
||||
$itemType
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the password
|
||||
*/
|
||||
if (isset($_POST['change_pw'])) {
|
||||
$message = $serverPrivileges->updatePassword($errorUrl, $username ?? '', $hostname ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes users
|
||||
* (Changes / copies a user, part IV)
|
||||
*/
|
||||
if (isset($_POST['delete']) || (isset($_POST['change_copy']) && $_POST['mode'] < 4)) {
|
||||
$queries = $serverPrivileges->getDataForDeleteUsers($queries);
|
||||
if (empty($_POST['change_copy'])) {
|
||||
[$sql_query, $message] = $serverPrivileges->deleteUser($queries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes / copies a user, part V
|
||||
*/
|
||||
if (isset($_POST['change_copy'])) {
|
||||
$queries = $serverPrivileges->getDataForQueries($queries, $queries_for_display);
|
||||
$message = Message::success();
|
||||
$sql_query = implode("\n", $queries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the privilege tables into memory
|
||||
*/
|
||||
$message_ret = $serverPrivileges->updateMessageForReload();
|
||||
if ($message_ret !== null) {
|
||||
$message = $message_ret;
|
||||
unset($message_ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are in an Ajax request for Create User/Edit User/Revoke User/
|
||||
* Flush Privileges, show $message and return.
|
||||
*/
|
||||
if (
|
||||
$this->response->isAjax()
|
||||
&& empty($_REQUEST['ajax_page_request'])
|
||||
&& ! isset($_GET['export'])
|
||||
&& (! isset($_POST['submit_mult']) || $_POST['submit_mult'] !== 'export')
|
||||
&& ((! isset($_GET['initial']) || $_GET['initial'] === '')
|
||||
|| (isset($_POST['delete']) && $_POST['delete'] === __('Go')))
|
||||
&& ! isset($_GET['showall'])
|
||||
) {
|
||||
$extra_data = $serverPrivileges->getExtraDataForAjaxBehavior(
|
||||
($password ?? ''),
|
||||
($sql_query ?? ''),
|
||||
($hostname ?? ''),
|
||||
($username ?? '')
|
||||
);
|
||||
|
||||
if (! empty($message) && $message instanceof Message) {
|
||||
$this->response->setRequestStatus($message->isSuccess());
|
||||
$this->response->addJSON('message', $message);
|
||||
$this->response->addJSON($extra_data);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the links
|
||||
*/
|
||||
if (isset($_GET['viewing_mode']) && $_GET['viewing_mode'] === 'db') {
|
||||
$db = $_REQUEST['db'] = $_GET['checkprivsdb'];
|
||||
|
||||
// Gets the database structure
|
||||
$sub_part = '_structure';
|
||||
ob_start();
|
||||
|
||||
[
|
||||
$tables,
|
||||
$num_tables,
|
||||
$total_num_tables,
|
||||
$sub_part,,,
|
||||
$tooltip_truename,
|
||||
$tooltip_aliasname,
|
||||
$pos,
|
||||
] = Util::getDbInfo($db, $sub_part);
|
||||
|
||||
$content = ob_get_clean();
|
||||
$this->response->addHTML($content . "\n");
|
||||
} elseif (! empty($GLOBALS['message'])) {
|
||||
$this->response->addHTML(Generator::getMessage($GLOBALS['message']));
|
||||
unset($GLOBALS['message']);
|
||||
}
|
||||
|
||||
// export user definition
|
||||
if (isset($_GET['export']) || (isset($_POST['submit_mult']) && $_POST['submit_mult'] === 'export')) {
|
||||
[$title, $export] = $serverPrivileges->getListForExportUserDefinition($username ?? '', $hostname ?? '');
|
||||
|
||||
unset($username, $hostname, $grants, $one_grant);
|
||||
|
||||
if ($this->response->isAjax()) {
|
||||
$this->response->addJSON('message', $export);
|
||||
$this->response->addJSON('title', $title);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addHTML('<h2>' . $title . '</h2>' . $export);
|
||||
}
|
||||
|
||||
// Show back the form if an error occurred
|
||||
if (isset($_GET['adduser']) || $_add_user_error === true) {
|
||||
// Add user
|
||||
$this->response->addHTML(
|
||||
$serverPrivileges->getHtmlForAddUser(Util::escapeMysqlWildcards(is_string($dbname) ? $dbname : ''))
|
||||
);
|
||||
} elseif (isset($_GET['checkprivsdb']) && is_string($_GET['checkprivsdb'])) {
|
||||
if (isset($_GET['checkprivstable']) && is_string($_GET['checkprivstable'])) {
|
||||
$this->response->addHTML($tableController([
|
||||
'checkprivsdb' => $_GET['checkprivsdb'],
|
||||
'checkprivstable' => $_GET['checkprivstable'],
|
||||
]));
|
||||
$this->render('export_modal');
|
||||
} elseif ($this->response->isAjax() === true && empty($_REQUEST['ajax_page_request'])) {
|
||||
$message = Message::success(__('User has been added.'));
|
||||
$this->response->addJSON('message', $message);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$this->response->addHTML($databaseController(['checkprivsdb' => $_GET['checkprivsdb']]));
|
||||
$this->render('export_modal');
|
||||
}
|
||||
} else {
|
||||
if (isset($dbname) && ! is_array($dbname)) {
|
||||
$url_dbname = urlencode(
|
||||
str_replace(
|
||||
[
|
||||
'\_',
|
||||
'\%',
|
||||
],
|
||||
[
|
||||
'_',
|
||||
'%',
|
||||
],
|
||||
$dbname
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (! isset($username)) {
|
||||
// No username is given --> display the overview
|
||||
$this->response->addHTML(
|
||||
$serverPrivileges->getHtmlForUserOverview($text_dir)
|
||||
);
|
||||
} elseif (! empty($routinename)) {
|
||||
$this->response->addHTML(
|
||||
$serverPrivileges->getHtmlForRoutineSpecificPrivileges(
|
||||
$username,
|
||||
$hostname ?? '',
|
||||
is_string($dbname) ? $dbname : '',
|
||||
$routinename,
|
||||
Util::escapeMysqlWildcards($url_dbname ?? '')
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// A user was selected -> display the user's properties
|
||||
// In an Ajax request, prevent cached values from showing
|
||||
if ($this->response->isAjax()) {
|
||||
header('Cache-Control: no-cache');
|
||||
}
|
||||
|
||||
$this->response->addHTML(
|
||||
$serverPrivileges->getHtmlForUserProperties(
|
||||
$dbname_is_wildcard,
|
||||
Util::escapeMysqlWildcards($url_dbname ?? ''),
|
||||
$username,
|
||||
$hostname ?? '',
|
||||
$dbname ?? '',
|
||||
$tablename ?? ''
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
! isset($_GET['viewing_mode'])
|
||||
|| $_GET['viewing_mode'] !== 'server'
|
||||
|| $relationParameters->configurableMenusFeature === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addHTML('</div>');
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Server replications
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ReplicationGui;
|
||||
use PhpMyAdmin\ReplicationInfo;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* Server replications
|
||||
*/
|
||||
class ReplicationController extends AbstractController
|
||||
{
|
||||
/** @var ReplicationGui */
|
||||
private $replicationGui;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
ReplicationGui $replicationGui,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->replicationGui = $replicationGui;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $urlParams, $errorUrl;
|
||||
|
||||
$params = [
|
||||
'url_params' => $_POST['url_params'] ?? null,
|
||||
'primary_configure' => $_POST['primary_configure'] ?? null,
|
||||
'replica_configure' => $_POST['replica_configure'] ?? null,
|
||||
'repl_clear_scr' => $_POST['repl_clear_scr'] ?? null,
|
||||
];
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$replicationInfo = new ReplicationInfo($this->dbi);
|
||||
$replicationInfo->load($_POST['primary_connection'] ?? null);
|
||||
|
||||
$primaryInfo = $replicationInfo->getPrimaryInfo();
|
||||
$replicaInfo = $replicationInfo->getReplicaInfo();
|
||||
|
||||
$this->addScriptFiles(['server/privileges.js', 'replication.js', 'vendor/zxcvbn-ts.js']);
|
||||
|
||||
if (isset($params['url_params']) && is_array($params['url_params'])) {
|
||||
$urlParams = $params['url_params'];
|
||||
}
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->replicationGui->handleControlRequest();
|
||||
}
|
||||
|
||||
$errorMessages = $this->replicationGui->getHtmlForErrorMessage();
|
||||
|
||||
if ($primaryInfo['status']) {
|
||||
$primaryReplicationHtml = $this->replicationGui->getHtmlForPrimaryReplication();
|
||||
}
|
||||
|
||||
if (isset($params['primary_configure'])) {
|
||||
$primaryConfigurationHtml = $this->replicationGui->getHtmlForPrimaryConfiguration();
|
||||
} else {
|
||||
if (! isset($params['repl_clear_scr'])) {
|
||||
$replicaConfigurationHtml = $this->replicationGui->getHtmlForReplicaConfiguration(
|
||||
$replicaInfo['status'],
|
||||
$replicationInfo->getReplicaStatus()
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($params['replica_configure'])) {
|
||||
$changePrimaryHtml = $this->replicationGui->getHtmlForReplicationChangePrimary('replica_changeprimary');
|
||||
}
|
||||
}
|
||||
|
||||
$this->render('server/replication/index', [
|
||||
'url_params' => $urlParams,
|
||||
'is_super_user' => $this->dbi->isSuperUser(),
|
||||
'error_messages' => $errorMessages,
|
||||
'is_primary' => $primaryInfo['status'],
|
||||
'primary_configure' => $params['primary_configure'],
|
||||
'replica_configure' => $params['replica_configure'],
|
||||
'clear_screen' => $params['repl_clear_scr'],
|
||||
'primary_replication_html' => $primaryReplicationHtml ?? '',
|
||||
'primary_configuration_html' => $primaryConfigurationHtml ?? '',
|
||||
'replica_configuration_html' => $replicaConfigurationHtml ?? '',
|
||||
'change_primary_html' => $changePrimaryHtml ?? '',
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\StorageEngine;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
/**
|
||||
* Displays details about a given Storage Engine.
|
||||
*/
|
||||
final class ShowEngineController extends AbstractController
|
||||
{
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, DatabaseInterface $dbi)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @psalm-param array{engine: string, page?: string} $params
|
||||
*/
|
||||
public function __invoke(ServerRequest $request, array $params): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$page = $params['page'] ?? '';
|
||||
|
||||
$engine = [];
|
||||
if (StorageEngine::isValid($params['engine'])) {
|
||||
$storageEngine = StorageEngine::getEngine($params['engine']);
|
||||
$engine = [
|
||||
'engine' => $params['engine'],
|
||||
'title' => $storageEngine->getTitle(),
|
||||
'help_page' => $storageEngine->getMysqlHelpPage(),
|
||||
'comment' => $storageEngine->getComment(),
|
||||
'info_pages' => $storageEngine->getInfoPages(),
|
||||
'support' => $storageEngine->getSupportInformationMessage(),
|
||||
'variables' => $storageEngine->getHtmlVariables(),
|
||||
'page' => ! empty($page) ? $storageEngine->getPage($page) : '',
|
||||
];
|
||||
}
|
||||
|
||||
$this->render('server/engines/show', [
|
||||
'engine' => $engine,
|
||||
'page' => $page,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Config\PageSettings;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\SqlQueryForm;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
/**
|
||||
* Server SQL executor
|
||||
*/
|
||||
class SqlController extends AbstractController
|
||||
{
|
||||
/** @var SqlQueryForm */
|
||||
private $sqlQueryForm;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
SqlQueryForm $sqlQueryForm,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template);
|
||||
$this->sqlQueryForm = $sqlQueryForm;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$this->addScriptFiles(['makegrid.js', 'vendor/jquery/jquery.uitablefilter.js', 'sql.js']);
|
||||
|
||||
$pageSettings = new PageSettings('Sql');
|
||||
$this->response->addHTML($pageSettings->getErrorHTML());
|
||||
$this->response->addHTML($pageSettings->getHTML());
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
$this->response->addHTML($this->sqlQueryForm->getHtml('', ''));
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Status;
|
||||
|
||||
use PhpMyAdmin\Controllers\AbstractController as Controller;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Status\Data;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
abstract class AbstractController extends Controller
|
||||
{
|
||||
/** @var Data */
|
||||
protected $data;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Data $data)
|
||||
{
|
||||
parent::__construct($response, $template);
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Status;
|
||||
|
||||
use PhpMyAdmin\Advisor;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Status\Data;
|
||||
use PhpMyAdmin\Template;
|
||||
|
||||
/**
|
||||
* Displays the advisor feature
|
||||
*/
|
||||
class AdvisorController extends AbstractController
|
||||
{
|
||||
/** @var Advisor */
|
||||
private $advisor;
|
||||
|
||||
public function __construct(ResponseRenderer $response, Template $template, Data $data, Advisor $advisor)
|
||||
{
|
||||
parent::__construct($response, $template, $data);
|
||||
$this->advisor = $advisor;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
$data = [];
|
||||
if ($this->data->dataLoaded) {
|
||||
$data = $this->advisor->run();
|
||||
}
|
||||
|
||||
$this->render('server/status/advisor/index', ['data' => $data]);
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Status\Monitor;
|
||||
|
||||
use PhpMyAdmin\Controllers\Server\Status\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Status\Data;
|
||||
use PhpMyAdmin\Server\Status\Monitor;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
final class ChartingDataController extends AbstractController
|
||||
{
|
||||
/** @var Monitor */
|
||||
private $monitor;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Data $data,
|
||||
Monitor $monitor,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $data);
|
||||
$this->monitor = $monitor;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$params = ['requiredData' => $_POST['requiredData'] ?? null];
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON([
|
||||
'message' => $this->monitor->getJsonForChartingData(
|
||||
$params['requiredData'] ?? ''
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Status\Monitor;
|
||||
|
||||
use PhpMyAdmin\Controllers\Server\Status\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Status\Data;
|
||||
use PhpMyAdmin\Server\Status\Monitor;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
final class GeneralLogController extends AbstractController
|
||||
{
|
||||
/** @var Monitor */
|
||||
private $monitor;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Data $data,
|
||||
Monitor $monitor,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $data);
|
||||
$this->monitor = $monitor;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$params = [
|
||||
'time_start' => $_POST['time_start'] ?? null,
|
||||
'time_end' => $_POST['time_end'] ?? null,
|
||||
'limitTypes' => $_POST['limitTypes'] ?? null,
|
||||
'removeVariables' => $_POST['removeVariables'] ?? null,
|
||||
];
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->monitor->getJsonForLogDataTypeGeneral(
|
||||
(int) $params['time_start'],
|
||||
(int) $params['time_end'],
|
||||
(bool) $params['limitTypes'],
|
||||
(bool) $params['removeVariables']
|
||||
);
|
||||
|
||||
if ($data === null) {
|
||||
$this->response->setRequestStatus(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON(['message' => $data]);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Controllers\Server\Status\Monitor;
|
||||
|
||||
use PhpMyAdmin\Controllers\Server\Status\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\ResponseRenderer;
|
||||
use PhpMyAdmin\Server\Status\Data;
|
||||
use PhpMyAdmin\Server\Status\Monitor;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
|
||||
final class LogVarsController extends AbstractController
|
||||
{
|
||||
/** @var Monitor */
|
||||
private $monitor;
|
||||
|
||||
/** @var DatabaseInterface */
|
||||
private $dbi;
|
||||
|
||||
public function __construct(
|
||||
ResponseRenderer $response,
|
||||
Template $template,
|
||||
Data $data,
|
||||
Monitor $monitor,
|
||||
DatabaseInterface $dbi
|
||||
) {
|
||||
parent::__construct($response, $template, $data);
|
||||
$this->monitor = $monitor;
|
||||
$this->dbi = $dbi;
|
||||
}
|
||||
|
||||
public function __invoke(): void
|
||||
{
|
||||
global $errorUrl;
|
||||
|
||||
$params = [
|
||||
'varName' => $_POST['varName'] ?? null,
|
||||
'varValue' => $_POST['varValue'] ?? null,
|
||||
];
|
||||
$errorUrl = Url::getFromRoute('/');
|
||||
|
||||
if ($this->dbi->isSuperUser()) {
|
||||
$this->dbi->selectDb('mysql');
|
||||
}
|
||||
|
||||
if (! $this->response->isAjax()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->response->addJSON([
|
||||
'message' => $this->monitor->getJsonForLoggingVars(
|
||||
$params['varName'],
|
||||
$params['varValue']
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue