phpmyadmin/libraries/classes/Controllers/Import/ImportController.php
Maurício Meneghini Fauth 10b937511d
Replace $analyzedSqlResults array with StatementInfo object
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
2022-05-24 21:35:30 -03:00

857 lines
35 KiB
PHP

<?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_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
{
$GLOBALS['collation_connection'] = $GLOBALS['collation_connection'] ?? null;
$GLOBALS['goto'] = $GLOBALS['goto'] ?? null;
$GLOBALS['display_query'] = $GLOBALS['display_query'] ?? null;
$GLOBALS['ajax_reload'] = $GLOBALS['ajax_reload'] ?? null;
$GLOBALS['import_text'] = $GLOBALS['import_text'] ?? null;
$GLOBALS['message'] = $GLOBALS['message'] ?? null;
$GLOBALS['errorUrl'] = $GLOBALS['errorUrl'] ?? null;
$GLOBALS['urlParams'] = $GLOBALS['urlParams'] ?? null;
$GLOBALS['memory_limit'] = $GLOBALS['memory_limit'] ?? null;
$GLOBALS['read_limit'] = $GLOBALS['read_limit'] ?? null;
$GLOBALS['finished'] = $GLOBALS['finished'] ?? null;
$GLOBALS['offset'] = $GLOBALS['offset'] ?? null;
$GLOBALS['charset_conversion'] = $GLOBALS['charset_conversion'] ?? null;
$GLOBALS['timestamp'] = $GLOBALS['timestamp'] ?? null;
$GLOBALS['maximum_time'] = $GLOBALS['maximum_time'] ?? null;
$GLOBALS['timeout_passed'] = $GLOBALS['timeout_passed'] ?? null;
$GLOBALS['import_file'] = $GLOBALS['import_file'] ?? null;
$GLOBALS['go_sql'] = $GLOBALS['go_sql'] ?? null;
$GLOBALS['sql_file'] = $GLOBALS['sql_file'] ?? null;
$GLOBALS['error'] = $GLOBALS['error'] ?? null;
$GLOBALS['max_sql_len'] = $GLOBALS['max_sql_len'] ?? null;
$GLOBALS['msg'] = $GLOBALS['msg'] ?? null;
$GLOBALS['sql_query_disabled'] = $GLOBALS['sql_query_disabled'] ?? null;
$GLOBALS['executed_queries'] = $GLOBALS['executed_queries'] ?? null;
$GLOBALS['run_query'] = $GLOBALS['run_query'] ?? null;
$GLOBALS['reset_charset'] = $GLOBALS['reset_charset'] ?? null;
$GLOBALS['result'] = $GLOBALS['result'] ?? null;
$GLOBALS['import_file_name'] = $GLOBALS['import_file_name'] ?? null;
$GLOBALS['import_notice'] = $GLOBALS['import_notice'] ?? null;
$GLOBALS['read_multiply'] = $GLOBALS['read_multiply'] ?? null;
$GLOBALS['my_die'] = $GLOBALS['my_die'] ?? null;
$GLOBALS['active_page'] = $GLOBALS['active_page'] ?? null;
$GLOBALS['reload'] = $GLOBALS['reload'] ?? null;
$GLOBALS['charset_connection'] = $GLOBALS['charset_connection'] ?? null;
$GLOBALS['charset_of_file'] = $_POST['charset_of_file'] ?? null;
$GLOBALS['format'] = $_POST['format'] ?? '';
$GLOBALS['import_type'] = $_POST['import_type'] ?? null;
$GLOBALS['is_js_confirmed'] = $_POST['is_js_confirmed'] ?? null;
$GLOBALS['MAX_FILE_SIZE'] = $_POST['MAX_FILE_SIZE'] ?? null;
$GLOBALS['message_to_show'] = $_POST['message_to_show'] ?? null;
$GLOBALS['noplugin'] = $_POST['noplugin'] ?? null;
$GLOBALS['skip_queries'] = $_POST['skip_queries'] ?? null;
$GLOBALS['local_import_file'] = $_POST['local_import_file'] ?? null;
$GLOBALS['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' => $GLOBALS['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
$GLOBALS['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;
}
$GLOBALS['ajax_reload'] = [];
$GLOBALS['import_text'] = '';
// Are we just executing plain query or sql file?
// (eg. non import, but query box/window run)
if (! empty($GLOBALS['sql_query'])) {
// apply values for parameters
if (! empty($_POST['parameterized']) && ! empty($_POST['parameters']) && is_array($_POST['parameters'])) {
$parameters = $_POST['parameters'];
foreach ($parameters as $parameter => $replacement) {
$replacementValue = $this->dbi->escapeString($replacement);
if (! is_numeric($replacementValue)) {
$replacementValue = '\'' . $replacementValue . '\'';
}
$quoted = preg_quote($parameter, '/');
// making sure that :param does not apply values to :param1
$GLOBALS['sql_query'] = preg_replace(
'/' . $quoted . '([^a-zA-Z0-9_])/',
$replacementValue . '${1}',
$GLOBALS['sql_query']
);
// for parameters the appear at the end of the string
$GLOBALS['sql_query'] = preg_replace(
'/' . $quoted . '$/',
$replacementValue,
$GLOBALS['sql_query']
);
}
}
// run SQL query
$GLOBALS['import_text'] = $GLOBALS['sql_query'];
$GLOBALS['import_type'] = 'query';
$GLOBALS['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($GLOBALS['import_text']);
}
// refresh navigation and main panels
if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['sql_query'])) {
$GLOBALS['reload'] = true;
$GLOBALS['ajax_reload']['reload'] = true;
}
// refresh navigation panel only
if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['sql_query'])) {
$GLOBALS['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',
$GLOBALS['sql_query'],
$rename_table_names
)
) {
$GLOBALS['ajax_reload']['reload'] = true;
$GLOBALS['ajax_reload']['table_name'] = Util::unQuote($rename_table_names[2]);
}
$GLOBALS['sql_query'] = '';
} elseif (! empty($GLOBALS['sql_file'])) {
// run uploaded SQL file
$GLOBALS['import_file'] = $GLOBALS['sql_file'];
$GLOBALS['import_type'] = 'queryfile';
$GLOBALS['format'] = 'sql';
unset($GLOBALS['sql_file']);
} elseif (! empty($_POST['id_bookmark'])) {
// run bookmark
$GLOBALS['import_type'] = 'query';
$GLOBALS['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 == []) {
$GLOBALS['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.'
)
);
$GLOBALS['message']->addParam('[doc@faq1-16]');
$GLOBALS['message']->addParam('[/doc]');
// so we can obtain the message
$_SESSION['Import_message']['message'] = $GLOBALS['message']->getDisplay();
$_SESSION['Import_message']['go_back_url'] = $GLOBALS['goto'];
$this->response->setRequestStatus(false);
$this->response->addJSON('message', $GLOBALS['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($GLOBALS['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_/',
'/^' . $GLOBALS['format'] . '_/',
];
Core::setPostAsGlobal($post_patterns);
$this->checkParameters(['import_type', 'format']);
// We don't want anything special in format
$GLOBALS['format'] = Core::securePath($GLOBALS['format']);
if (strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) {
$GLOBALS['urlParams'] = [
'db' => $GLOBALS['db'],
'table' => $GLOBALS['table'],
];
} elseif (strlen($GLOBALS['db']) > 0) {
$GLOBALS['urlParams'] = ['db' => $GLOBALS['db']];
} else {
$GLOBALS['urlParams'] = [];
}
// Create error and goto url
if ($GLOBALS['import_type'] === 'table') {
$GLOBALS['goto'] = Url::getFromRoute('/table/import');
} elseif ($GLOBALS['import_type'] === 'database') {
$GLOBALS['goto'] = Url::getFromRoute('/database/import');
} elseif ($GLOBALS['import_type'] === 'server') {
$GLOBALS['goto'] = Url::getFromRoute('/server/import');
} elseif (empty($GLOBALS['goto']) || ! preg_match('@^index\.php$@i', $GLOBALS['goto'])) {
if (strlen($GLOBALS['table']) > 0 && strlen($GLOBALS['db']) > 0) {
$GLOBALS['goto'] = Url::getFromRoute('/table/structure');
} elseif (strlen($GLOBALS['db']) > 0) {
$GLOBALS['goto'] = Url::getFromRoute('/database/structure');
} else {
$GLOBALS['goto'] = Url::getFromRoute('/server/sql');
}
}
$GLOBALS['errorUrl'] = $GLOBALS['goto'] . Url::getCommon($GLOBALS['urlParams'], '&');
$_SESSION['Import_message']['go_back_url'] = $GLOBALS['errorUrl'];
if (strlen($GLOBALS['db']) > 0) {
$this->dbi->selectDb($GLOBALS['db']);
}
Util::setTimeLimit();
if (! empty($GLOBALS['cfg']['MemoryLimit'])) {
ini_set('memory_limit', $GLOBALS['cfg']['MemoryLimit']);
}
$GLOBALS['timestamp'] = time();
if (isset($_POST['allow_interrupt'])) {
$GLOBALS['maximum_time'] = ini_get('max_execution_time');
} else {
$GLOBALS['maximum_time'] = 0;
}
// set default values
$GLOBALS['timeout_passed'] = false;
$GLOBALS['error'] = false;
$GLOBALS['read_multiply'] = 1;
$GLOBALS['finished'] = false;
$GLOBALS['offset'] = 0;
$GLOBALS['max_sql_len'] = 0;
$GLOBALS['sql_query'] = '';
$GLOBALS['sql_query_disabled'] = false;
$GLOBALS['go_sql'] = false;
$GLOBALS['executed_queries'] = 0;
$GLOBALS['run_query'] = true;
$GLOBALS['charset_conversion'] = false;
$GLOBALS['reset_charset'] = false;
$GLOBALS['msg'] = 'Sorry an unexpected error happened!';
$GLOBALS['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,
$GLOBALS['cfg']['Server']['user'],
$GLOBALS['db'],
$id_bookmark,
'id',
isset($_POST['action_bookmark_all'])
);
if (! $bookmark instanceof Bookmark) {
break;
}
if (! empty($_POST['bookmark_variable'])) {
$GLOBALS['import_text'] = $bookmark->applyVariables($_POST['bookmark_variable']);
} else {
$GLOBALS['import_text'] = $bookmark->getQuery();
}
// refresh navigation and main panels
if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['import_text'])) {
$GLOBALS['reload'] = true;
$GLOBALS['ajax_reload']['reload'] = true;
}
// refresh navigation panel only
if (preg_match('/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $GLOBALS['import_text'])) {
$GLOBALS['ajax_reload']['reload'] = true;
}
break;
case 1: // bookmarked query that have to be displayed
$bookmark = Bookmark::get(
$this->dbi,
$GLOBALS['cfg']['Server']['user'],
$GLOBALS['db'],
$id_bookmark
);
if (! $bookmark instanceof Bookmark) {
break;
}
$GLOBALS['import_text'] = $bookmark->getQuery();
if ($this->response->isAjax()) {
$GLOBALS['message'] = Message::success(__('Showing bookmark'));
$this->response->setRequestStatus($GLOBALS['message']->isSuccess());
$this->response->addJSON('message', $GLOBALS['message']);
$this->response->addJSON('sql_query', $GLOBALS['import_text']);
$this->response->addJSON('action_bookmark', $_POST['action_bookmark']);
return;
} else {
$GLOBALS['run_query'] = false;
}
break;
case 2: // bookmarked query that have to be deleted
$bookmark = Bookmark::get(
$this->dbi,
$GLOBALS['cfg']['Server']['user'],
$GLOBALS['db'],
$id_bookmark
);
if (! $bookmark instanceof Bookmark) {
break;
}
$bookmark->delete();
if ($this->response->isAjax()) {
$GLOBALS['message'] = Message::success(
__('The bookmark has been deleted.')
);
$this->response->setRequestStatus($GLOBALS['message']->isSuccess());
$this->response->addJSON('message', $GLOBALS['message']);
$this->response->addJSON('action_bookmark', $_POST['action_bookmark']);
$this->response->addJSON('id_bookmark', $id_bookmark);
return;
} else {
$GLOBALS['run_query'] = false;
$GLOBALS['error'] = true; // this is kind of hack to skip processing the query
}
break;
}
}
// Do no run query if we show PHP code
if (isset($GLOBALS['show_as_php'])) {
$GLOBALS['run_query'] = false;
$GLOBALS['go_sql'] = true;
}
// We can not read all at once, otherwise we can run out of memory
$GLOBALS['memory_limit'] = trim((string) ini_get('memory_limit'));
// 2 MB as default
if (empty($GLOBALS['memory_limit'])) {
$GLOBALS['memory_limit'] = 2 * 1024 * 1024;
}
// In case no memory limit we work on 10MB chunks
if ($GLOBALS['memory_limit'] === '-1') {
$GLOBALS['memory_limit'] = 10 * 1024 * 1024;
}
// Calculate value of the limit
$memoryUnit = mb_strtolower(substr((string) $GLOBALS['memory_limit'], -1));
if ($memoryUnit === 'm') {
$GLOBALS['memory_limit'] = (int) substr((string) $GLOBALS['memory_limit'], 0, -1) * 1024 * 1024;
} elseif ($memoryUnit === 'k') {
$GLOBALS['memory_limit'] = (int) substr((string) $GLOBALS['memory_limit'], 0, -1) * 1024;
} elseif ($memoryUnit === 'g') {
$GLOBALS['memory_limit'] = (int) substr((string) $GLOBALS['memory_limit'], 0, -1) * 1024 * 1024 * 1024;
} else {
$GLOBALS['memory_limit'] = (int) $GLOBALS['memory_limit'];
}
// Just to be sure, there might be lot of memory needed for uncompression
$GLOBALS['read_limit'] = $GLOBALS['memory_limit'] / 8;
// handle filenames
if (isset($_FILES['import_file'])) {
$GLOBALS['import_file'] = $_FILES['import_file']['tmp_name'];
$GLOBALS['import_file_name'] = $_FILES['import_file']['name'];
}
if (! empty($GLOBALS['local_import_file']) && ! empty($GLOBALS['cfg']['UploadDir'])) {
// sanitize $local_import_file as it comes from a POST
$GLOBALS['local_import_file'] = Core::securePath($GLOBALS['local_import_file']);
$GLOBALS['import_file'] = Util::userDir((string) $GLOBALS['cfg']['UploadDir'])
. $GLOBALS['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($GLOBALS['import_file'])) {
$GLOBALS['import_file'] = 'none';
}
} elseif (empty($GLOBALS['import_file']) || ! is_uploaded_file($GLOBALS['import_file'])) {
$GLOBALS['import_file'] = 'none';
}
// Do we have file to import?
if ($GLOBALS['import_file'] !== 'none' && ! $GLOBALS['error']) {
/**
* Handle file compression
*/
$importHandle = new File($GLOBALS['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 (! $GLOBALS['error'] && (! isset($GLOBALS['import_text']) || empty($GLOBALS['import_text']))) {
$GLOBALS['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'] = $GLOBALS['message']->getDisplay();
$this->response->setRequestStatus(false);
$this->response->addJSON('message', $GLOBALS['message']->getDisplay());
$this->response->addHTML($GLOBALS['message']->getDisplay());
return;
}
// Convert the file's charset if necessary
if (Encoding::isSupported() && isset($GLOBALS['charset_of_file'])) {
if ($GLOBALS['charset_of_file'] !== 'utf-8') {
$GLOBALS['charset_conversion'] = true;
}
} elseif (isset($GLOBALS['charset_of_file']) && $GLOBALS['charset_of_file'] !== 'utf-8') {
$this->dbi->query('SET NAMES \'' . $GLOBALS['charset_of_file'] . '\'');
// We can not show query in this case, it is in different charset
$GLOBALS['sql_query_disabled'] = true;
$GLOBALS['reset_charset'] = true;
}
// Something to skip? (because timeout has passed)
if (! $GLOBALS['error'] && isset($_POST['skip'])) {
$original_skip = $skip = intval($_POST['skip']);
while ($skip > 0 && ! $GLOBALS['finished']) {
$this->import->getNextChunk(
$importHandle ?? null,
$skip < $GLOBALS['read_limit'] ? $skip : $GLOBALS['read_limit']
);
// Disable read progressivity, otherwise we eat all memory!
$GLOBALS['read_multiply'] = 1;
$skip -= $GLOBALS['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)
$queriesToBeExecuted = [];
if (! $GLOBALS['error']) {
/**
* @var ImportPlugin $import_plugin
*/
$import_plugin = Plugins::getPlugin('import', $GLOBALS['format'], $GLOBALS['import_type']);
if ($import_plugin == null) {
$GLOBALS['message'] = Message::error(
__('Could not load import plugins, please check your installation!')
);
$_SESSION['Import_message']['message'] = $GLOBALS['message']->getDisplay();
$this->response->setRequestStatus(false);
$this->response->addJSON('message', $GLOBALS['message']->getDisplay());
$this->response->addHTML($GLOBALS['message']->getDisplay());
return;
}
// Do the real import
$default_fk_check = ForeignKey::handleDisableCheckInit();
try {
$queriesToBeExecuted = $import_plugin->doImport($importHandle ?? null);
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 ($GLOBALS['reset_charset']) {
$this->dbi->query('SET CHARACTER SET ' . $GLOBALS['charset_connection']);
$this->dbi->setCollation($GLOBALS['collation_connection']);
}
// Show correct message
if (! empty($id_bookmark) && $_POST['action_bookmark'] == 2) {
$GLOBALS['message'] = Message::success(__('The bookmark has been deleted.'));
$GLOBALS['display_query'] = $GLOBALS['import_text'];
$GLOBALS['error'] = false; // unset error marker, it was used just to skip processing
} elseif (! empty($id_bookmark) && $_POST['action_bookmark'] == 1) {
$GLOBALS['message'] = Message::notice(__('Showing bookmark'));
} elseif ($GLOBALS['finished'] && ! $GLOBALS['error']) {
// Do not display the query with message, we do it separately
$GLOBALS['display_query'] = ';';
if ($GLOBALS['import_type'] !== 'query') {
$GLOBALS['message'] = Message::success(
'<em>'
. _ngettext(
'Import has been successfully finished, %d query executed.',
'Import has been successfully finished, %d queries executed.',
$GLOBALS['executed_queries']
)
. '</em>'
);
$GLOBALS['message']->addParam($GLOBALS['executed_queries']);
if (! empty($GLOBALS['import_notice'])) {
$GLOBALS['message']->addHtml($GLOBALS['import_notice']);
}
if (! empty($GLOBALS['local_import_file'])) {
$GLOBALS['message']->addText('(' . $GLOBALS['local_import_file'] . ')');
} else {
$GLOBALS['message']->addText('(' . $_FILES['import_file']['name'] . ')');
}
}
}
// Did we hit timeout? Tell it user.
if ($GLOBALS['timeout_passed']) {
$GLOBALS['urlParams']['timeout_passed'] = '1';
$GLOBALS['urlParams']['offset'] = $GLOBALS['offset'];
if (isset($GLOBALS['local_import_file'])) {
$GLOBALS['urlParams']['local_import_file'] = $GLOBALS['local_import_file'];
}
$importUrl = $GLOBALS['errorUrl'] = $GLOBALS['goto'] . Url::getCommon($GLOBALS['urlParams'], '&');
$GLOBALS['message'] = Message::error(
__(
'Script timeout passed, if you want to finish import,'
. ' please %sresubmit the same file%s and import will resume.'
)
);
$GLOBALS['message']->addParamHtml('<a href="' . $importUrl . '">');
$GLOBALS['message']->addParamHtml('</a>');
if ($GLOBALS['offset'] == 0 || (isset($original_skip) && $original_skip == $GLOBALS['offset'])) {
$GLOBALS['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($GLOBALS['message'])) {
$_SESSION['Import_message']['message'] = $GLOBALS['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($GLOBALS['sql_query']);
if ($sqlLength <= $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) {
[$statementInfo, $GLOBALS['db'], $table_from_sql] = ParseAnalyze::sqlQuery(
$GLOBALS['sql_query'],
$GLOBALS['db']
);
$GLOBALS['reload'] = $statementInfo->reload;
$GLOBALS['offset'] = $statementInfo->offset;
if ($GLOBALS['table'] != $table_from_sql && ! empty($table_from_sql)) {
$GLOBALS['table'] = $table_from_sql;
}
}
// There was an error?
if (isset($GLOBALS['my_die'])) {
foreach ($GLOBALS['my_die'] as $die) {
Generator::mysqlDie($die['error'], $die['sql'], false, $GLOBALS['errorUrl'], $GLOBALS['error']);
}
}
if ($GLOBALS['go_sql']) {
if ($queriesToBeExecuted !== []) {
$_SESSION['is_multi_query'] = true;
} else {
$queriesToBeExecuted = [$GLOBALS['sql_query']];
}
$html_output = '';
foreach ($queriesToBeExecuted as $GLOBALS['sql_query']) {
// parse sql query
[$statementInfo, $GLOBALS['db'], $table_from_sql] = ParseAnalyze::sqlQuery(
$GLOBALS['sql_query'],
$GLOBALS['db']
);
$GLOBALS['offset'] = $statementInfo->offset;
$GLOBALS['reload'] = $statementInfo->reload;
// Check if User is allowed to issue a 'DROP DATABASE' Statement
if (
$this->sql->hasNoRightsToDropDatabase(
$statementInfo,
$GLOBALS['cfg']['AllowUserDropDatabase'],
$this->dbi->isSuperUser()
)
) {
Generator::mysqlDie(
__('"DROP DATABASE" statements are disabled.'),
'',
false,
$_SESSION['Import_message']['go_back_url']
);
return;
}
if ($GLOBALS['table'] != $table_from_sql && ! empty($table_from_sql)) {
$GLOBALS['table'] = $table_from_sql;
}
$html_output .= $this->sql->executeQueryAndGetQueryResponse(
$statementInfo,
false, // is_gotofile
$GLOBALS['db'], // db
$GLOBALS['table'], // table
null, // find_real_end
null, // sql_query_for_bookmark - see below
null, // extra_data
null, // message_to_show
null, // sql_data
$GLOBALS['goto'], // goto
null, // disp_query
null, // disp_message
$GLOBALS['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($GLOBALS['import_text'])) {
$relation = new Relation($this->dbi);
$this->sql->storeTheQueryAsBookmark(
$relation->getRelationParameters()->bookmarkFeature,
$GLOBALS['db'],
$GLOBALS['cfg']['Server']['user'],
$_POST['sql_query'],
$_POST['bkm_label'],
isset($_POST['bkm_replace'])
);
}
$this->response->addJSON('ajax_reload', $GLOBALS['ajax_reload']);
$this->response->addHTML($html_output);
return;
}
if ($GLOBALS['result']) {
// Save a Bookmark with more than one queries (if Bookmark label given).
if (! empty($_POST['bkm_label']) && ! empty($GLOBALS['import_text'])) {
$relation = new Relation($this->dbi);
$this->sql->storeTheQueryAsBookmark(
$relation->getRelationParameters()->bookmarkFeature,
$GLOBALS['db'],
$GLOBALS['cfg']['Server']['user'],
$_POST['sql_query'],
$_POST['bkm_label'],
isset($_POST['bkm_replace'])
);
}
$this->response->setRequestStatus(true);
$this->response->addJSON('message', Message::success($GLOBALS['msg']));
$this->response->addJSON(
'sql_query',
Generator::getMessage($GLOBALS['msg'], $GLOBALS['sql_query'], 'success')
);
} elseif ($GLOBALS['result'] === false) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error($GLOBALS['msg']));
} else {
$GLOBALS['active_page'] = $GLOBALS['goto'];
/** @psalm-suppress UnresolvableInclude */
include ROOT_PATH . $GLOBALS['goto'];
}
// If there is request for ROLLBACK in the end.
if (! isset($_POST['rollback_query'])) {
return;
}
$this->dbi->query('ROLLBACK');
}
}