Leitgedanken/msd/inc/functions_restore.php
2023-02-11 15:24:36 +01:00

421 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/* ----------------------------------------------------------------------
MyOOS [Dumper]
http://www.oos-shop.de/
Copyright (c) 2013 - 2022 by the MyOOS Development Team.
----------------------------------------------------------------------
Based on:
MySqlDumper
http://www.mysqldumper.de
Copyright (C)2004-2011 Daniel Schlichtholz (admin@mysqldumper.de)
----------------------------------------------------------------------
Released under the GNU General Public License
---------------------------------------------------------------------- */
define('DEBUG', 0);
if (!defined('MOD_VERSION')) {
exit('No direct access.');
}
function get_sqlbefehl()
{
global $restore, $config, $databases, $lang;
//Init
$restore['fileEOF'] = false;
$restore['EOB'] = false;
$complete_sql = '';
$sqlparser_status = 0;
if (!isset($restore['eintraege_ready'])) {
$restore['eintraege_ready'] = 0;
}
//Parsen
while (100 != $sqlparser_status && !$restore['fileEOF'] && !$restore['EOB']) {
//nächste Zeile lesen
$zeile = ($restore['compressed']) ? gzgets($restore['filehandle']) : fgets($restore['filehandle']);
if (DEBUG) {
echo '<br><br>Zeile: '.htmlspecialchars($zeile);
}
/******************* Setzen des Parserstatus *******************/
// herausfinden um was für einen Befehl es sich handelt
if (0 == $sqlparser_status) {
//Vergleichszeile, um nicht bei jedem Vergleich strtoupper ausführen zu müssen
$zeile2 = strtoupper(trim($zeile));
// pre-built compare strings - so we need the CPU power only once :)
$sub9 = substr($zeile2, 0, 9);
$sub7 = substr($sub9, 0, 7);
$sub6 = substr($sub7, 0, 6);
$sub4 = substr($sub6, 0, 4);
$sub3 = substr($sub4, 0, 3);
$sub2 = substr($sub3, 0, 2);
$sub1 = substr($sub2, 0, 1);
if ('INSERT ' == $sub7) {
$sqlparser_status = 3; //Datensatzaktion
$restore['actual_table'] = get_tablename($zeile);
}
//Einfache Anweisung finden die mit Semikolon beendet werden
elseif ('LOCK TA' == $sub7) {
$sqlparser_status = 4;
} elseif ('COMMIT' == $sub6) {
$sqlparser_status = 7;
} elseif ('BEGIN' == substr($sub6, 0, 5)) {
$sqlparser_status = 7;
} elseif ('UNLOCK TA' == $sub9) {
$sqlparser_status = 4;
} elseif ('SET' == $sub3) {
$sqlparser_status = 4;
} elseif ('START ' == $sub6) {
$sqlparser_status = 4;
} elseif ('/*!' == $sub3) {
$sqlparser_status = 5;
} //MySQL-Condition oder Kommentar
elseif ('ALTER TAB' == $sub9) {
$sqlparser_status = 4;
} // Alter Table
elseif ('CREATE TA' == $sub9) {
$sqlparser_status = 2;
} //Create Table
elseif ('CREATE AL' == $sub9) {
$sqlparser_status = 2;
} //Create View
elseif ('CREATE IN' == $sub9) {
$sqlparser_status = 4;
} //Indexaktion
//Condition?
elseif ((5 != $sqlparser_status) && ('/*' == substr($zeile2, 0, 2))) {
$sqlparser_status = 6;
}
// Delete actions
elseif ('DROP TABL' == $sub9) {
$sqlparser_status = 1;
} elseif ('DROP VIEW' == $sub9) {
$sqlparser_status = 1;
}
// Befehle, die nicht ausgeführt werden sollen
elseif ('CREATE DA' == $sub9) {
$sqlparser_status = 7;
} elseif ('DROP DATA ' == $sub9) {
$sqlparser_status = 7;
} elseif ('USE' == $sub3) {
$sqlparser_status = 7;
}
// Am Ende eines MySQLDumper-Backups angelangt?
elseif ('-- EOB' == $sub6 || '# EO' == $sub4) {
$restore['EOB'] = true;
$restore['fileEOF'] = true;
$zeile = '';
$zeile2 = '';
$sqlparser_status = 100;
}
// Kommentar?
elseif ('--' == $sub2 || '#' == $sub1) {
$zeile = '';
$zeile2 = '';
$sqlparser_status = 0;
}
// Fortsetzung von erweiterten Inserts
if (1 == $restore['flag']) {
$sqlparser_status = 3;
}
if ((0 == $sqlparser_status) && (trim($complete_sql) > '') && (-1 == $restore['flag'])) {
// Unbekannten Befehl entdeckt
v($restore);
echo '<br>Sql: '.htmlspecialchars($complete_sql);
echo '<br>Erweiterte Inserts: '.$restore['erweiterte_inserts'];
exit('<br>'.$lang['L_UNKNOWN_SQLCOMMAND'].': '.$zeile.'<br><br>'.$complete_sql);
}
/******************* Ende von Setzen des Parserstatus *******************/
}
$last_char = substr(rtrim($zeile), -1);
// Zeilenumbrüche erhalten - sonst werden Schlüsselwörter zusammengefügt
// z.B. 'null' und in der nächsten Zeile 'check' wird zu 'nullcheck'
$complete_sql .= $zeile."\n";
if (3 == $sqlparser_status) {
//INSERT
if (SQL_Is_Complete($complete_sql)) {
$sqlparser_status = 100;
$complete_sql = trim($complete_sql);
if ('*/' == substr($complete_sql, -2)) {
$complete_sql = remove_comment_at_eol($complete_sql);
}
// letzter Ausdruck des erweiterten Inserts erreicht?
if (');' == substr($complete_sql, -2)) {
$restore['flag'] = -1;
}
// Wenn am Ende der Zeile ein Klammer Komma -> erweiterter Insert-Modus -> Steuerflag setzen
elseif ('),' == substr($complete_sql, -2)) {
// letztes Komme gegen Semikolon tauschen
$complete_sql = substr($complete_sql, 0, -1).';';
$restore['erweiterte_inserts'] = 1;
$restore['flag'] = 1;
}
if ('INSERT ' != substr(strtoupper($complete_sql), 0, 7)) {
// wenn der Syntax aufgrund eines Reloads verloren ging - neu ermitteln
if (!isset($restore['insert_syntax'])) {
$restore['insert_syntax'] = get_insert_syntax($restore['actual_table']);
}
$complete_sql = $restore['insert_syntax'].' VALUES '.$complete_sql.';';
} else {
// INSERT Syntax ermitteln und merken
$ipos = strpos(strtoupper($complete_sql), ' VALUES');
if (false === !$ipos) {
$restore['insert_syntax'] = substr($complete_sql, 0, $ipos);
} else {
$restore['insert_syntax'] = 'INSERT INTO `'.$restore['actual_table'].'`';
}
}
}
} elseif (1 == $sqlparser_status) {
//Löschaktion
if (';' == $last_char) {
$sqlparser_status = 100;
} //Befehl komplett
$restore['actual_table'] = get_tablename($complete_sql);
} elseif (2 == $sqlparser_status) {
// Createanweisung ist beim Finden eines ; beendet
if (';' == $last_char) {
if ($config['minspeed'] > 0) {
$restore['anzahl_zeilen'] = $config['minspeed'];
}
// Soll die Tabelle hergestellt werden?
$do_it = true;
if (is_array($restore['tables_to_restore'])) {
$do_it = false;
if (in_array($restore['actual_table'], $restore['tables_to_restore'])) {
$do_it = true;
}
}
if ($do_it) {
$tablename = submit_create_action($complete_sql);
$restore['actual_table'] = $tablename;
++$restore['table_ready'];
}
// Zeile verwerfen, da CREATE jetzt bereits ausgefuehrt wurde und naechsten Befehl suchen
$complete_sql = '';
$sqlparser_status = 0;
}
}
// Index
elseif (4 == $sqlparser_status) { //Createindex
if (';' == $last_char) {
if ($config['minspeed'] > 0) {
$restore['anzahl_zeilen'] = $config['minspeed'];
}
$complete_sql = del_inline_comments($complete_sql);
$sqlparser_status = 100;
}
}
// Kommentar oder Condition
elseif (5 == $sqlparser_status) { //Anweisung
$t = strrpos($zeile, '*/;');
if (false === !$t) {
$restore['anzahl_zeilen'] = $config['minspeed'];
$sqlparser_status = 100;
if ($config['ignore_enable_keys'] &&
false !== strrpos($zeile, 'ENABLE KEYS ')) {
$sqlparser_status = 100;
$complete_sql = '';
}
}
}
// Mehrzeiliger oder Inline-Kommentar
elseif (6 == $sqlparser_status) {
$t = strrpos($zeile, '*/');
if (false === !$t) {
$complete_sql = '';
$sqlparser_status = 0;
}
}
// Befehle, die verworfen werden sollen
elseif (7 == $sqlparser_status) { //Anweisung
if (';' == $last_char) {
if ($config['minspeed'] > 0) {
$restore['anzahl_zeilen'] = $config['minspeed'];
}
$complete_sql = '';
$sqlparser_status = 0;
}
}
if (($restore['compressed']) && (gzeof($restore['filehandle']))) {
$restore['fileEOF'] = true;
}
if ((!$restore['compressed']) && (feof($restore['filehandle']))) {
$restore['fileEOF'] = true;
}
}
// wenn bestimmte Tabellen wiederhergestellt werden sollen -> pruefen
if (is_array($restore['tables_to_restore']) && !(in_array($restore['actual_table'], $restore['tables_to_restore']))) {
$complete_sql = '';
}
return trim($complete_sql);
}
function submit_create_action($sql)
{
global $config;
//executes a create command
$tablename = get_tablename($sql);
if ('CREATE ALGORITHM' == strtoupper(substr($sql, 0, 16))) {
// It`s a VIEW. We need to substitute the original DEFINER with the actual MySQL-User
$parts = explode(' ', $sql);
for ($i = 0, $count = sizeof($parts); $i < $count; ++$i) {
if ('DEFINER=' == strtoupper(substr($parts[$i], 0, 8))) {
$parts[$i] = 'DEFINER=`'.$config['dbuser'].'`@`'.$config['dbhost'].'`';
$sql = implode(' ', $parts);
$i = $count;
}
}
}
$res = mysqli_query($config['dbconnection'], $sql);
if (false === $res) {
// erster Versuch fehlgeschlagen -> zweiter Versuch - vielleicht versteht der Server die Inline-Kommentare nicht?
$sql = del_inline_comments($sql);
$res = mysqli_query($config['dbconnection'], downgrade($sql));
}
if (false === $res) {
// wenn wir hier angekommen sind hat nichts geklappt -> Fehler ausgeben und abbrechen
SQLError($sql, mysqli_error($config['dbconnection']));
exit("<br>Fatal error: Couldn't create table or view `".$tablename.'´');
}
return $tablename;
}
function get_insert_syntax($table)
{
global $config;
$insert = '';
$sql = 'SHOW COLUMNS FROM `'.$table.'`';
$res = mysqli_query($config['dbconnection'], $sql);
if ($res) {
$insert = 'INSERT INTO `'.$table.'` (';
while ($row = mysqli_fetch_object($res)) {
$insert .= '`'.$row->Field.'`,';
}
$insert = substr($insert, 0, strlen($insert) - 1).') ';
} else {
global $restore;
v($restore);
SQLError($sql, mysqli_error($config['dbconnection']));
}
return $insert;
}
function del_inline_comments($sql)
{
//$sql=str_replace("\n",'<br>', $sql);
$array = [];
preg_match_all("/(\/\*(.+)\*\/)/U", $sql, $array);
if (is_array($array[0])) {
$sql = str_replace($array[0], '', $sql);
if (DEBUG) {
echo 'Nachher: :<br>'.$sql.'<br><hr>';
}
}
//$sql=trim(str_replace('<br>',"\n", $sql));
//Wenn nach dem Entfernen nur noch ein ; übrigbleibt -> entfernen
if (';' == $sql) {
$sql = '';
}
return $sql;
}
// extrahiert auf einfache Art den Tabellennamen aus dem "Create",Drop"-Befehl
function get_tablename($t)
{
// alle Schluesselbegriffe entfernen, bis der Tabellenname am Anfang steht
$t = substr($t, 0, 150); // verkuerzen, um Speicher zu sparen - wir brauchenhier nur den Tabellennamen
$t = str_ireplace('DROP TABLE', '', $t);
$t = str_ireplace('DROP VIEW', '', $t);
$t = str_ireplace('CREATE TABLE', '', $t);
$t = str_ireplace('INSERT INTO', '', $t);
$t = str_ireplace('REPLACE INTO', '', $t);
$t = str_ireplace('IF NOT EXISTS', '', $t);
$t = str_ireplace('IF EXISTS', '', $t);
if ('CREATE ALGORITHM' == substr(strtoupper($t), 0, 16)) {
$pos = strpos($t, 'DEFINER VIEW ');
$t = substr($t, $pos, strlen($t) - $pos);
}
$t = str_ireplace(';', ' ;', $t); // tricky -> insert space as delimiter
$t = trim($t);
// jetzt einfach nach dem ersten Leerzeichen suchen
$delimiter = substr($t, 0, 1);
if ('`' != $delimiter) {
$delimiter = ' ';
}
$found = false;
$position = 1;
while (!$found) {
if (substr($t, $position, 1) == $delimiter) {
$found = true;
}
if ($position >= strlen($t)) {
$found = true;
}
++$position;
}
$t = substr($t, 0, $position);
$t = trim(str_replace('`', '', $t));
return $t;
}
// decide if an INSERT-Command is complete - simply count quotes and look for ); at the end of line
function SQL_Is_Complete($string)
{
$string = str_replace('\\\\', '', trim($string)); // trim and remove escaped backslashes
$string = trim($string);
$quotes = substr_count($string, '\'');
$escaped_quotes = substr_count($string, '\\\'');
if (($quotes - $escaped_quotes) % 2 == 0) {
$compare = substr($string, -2);
if ('*/' == $compare) {
$compare = substr(trim(remove_comment_at_eol($string)), -2);
}
if (');' == $compare) {
return true;
}
if ('),' == $compare) {
return true;
}
}
return false;
}
function remove_comment_at_eol($string)
{
// check for Inline-Comments at the end of the line
if ('*/' == substr(trim($string), -2)) {
$pos = strrpos($string, '/*');
if ($pos > 0) {
$string = trim(substr($string, 0, $pos));
}
}
return $string;
}