421 lines
16 KiB
PHP
421 lines
16 KiB
PHP
<?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;
|
||
}
|