1 <?php
2
3 /**
4 * Class to execute a sql dump.
5 *
6 * @package redaxo\core\sql
7 */
8 class rex_sql_util
9 {
10 /**
11 * Allgemeine funktion die eine Datenbankspalte fortlaufend durchnummeriert.
12 * Dies ist z.B. nützlich beim Umgang mit einer Prioritäts-Spalte.
13 *
14 * @param string $tableName Name der Datenbanktabelle
15 * @param string $priorColumnName Name der Spalte in der Tabelle, in der die Priorität (Integer) gespeichert wird
16 * @param string $whereCondition Where-Bedingung zur Einschränkung des ResultSets
17 * @param string $orderBy Sortierung des ResultSets
18 * @param int $startBy Startpriorität
19 */
20 public static function organizePriorities($tableName, $priorColumnName, $whereCondition = '', $orderBy = '', $startBy = 1)
21 {
22 // Datenbankvariable initialisieren
23 $qry = 'SET @count=' . ($startBy - 1);
24 $sql = rex_sql::factory();
25 $sql->setQuery($qry);
26
27 // Spalte updaten
28 $qry = 'UPDATE ' . $tableName . ' SET ' . $priorColumnName . ' = ( SELECT @count := @count +1 )';
29
30 if ($whereCondition != '') {
31 $qry .= ' WHERE ' . $whereCondition;
32 }
33
34 if ($orderBy != '') {
35 $qry .= ' ORDER BY ' . $orderBy;
36 }
37
38 $sql->setQuery($qry);
39 }
40
41 /**
42 * Importiert die gegebene SQL-Datei in die Datenbank.
43 *
44 * @param string $file
45 * @param bool $debug
46 *
47 * @throws rex_sql_exception
48 *
49 * @return bool true bei Erfolg
50 */
51 public static function importDump($file, $debug = false)
52 {
53 $sql = rex_sql::factory();
54 $sql->setDebug($debug);
55 $error = '';
56
57 foreach (self::readSqlDump($file) as $query) {
58 try {
59 $sql->setQuery(self::prepareQuery($query));
60 } catch (rex_sql_exception $e) {
61 $error .= $e->getMessage() . "\n<br />";
62 }
63 }
64 if ($error) {
65 throw new rex_sql_exception($error, null, $sql);
66 }
67
68 return true;
69 }
70
71 private static function prepareQuery($qry)
72 {
73 // rex::getUser() gibts im Setup nicht
74 $user = rex::getUser() ? rex::getUser()->getValue('login') : '';
75
76 $qry = str_replace('%USER%', $user, $qry);
77 $qry = str_replace('%TIME%', time(), $qry);
78 $qry = str_replace('%TABLE_PREFIX%', rex::getTablePrefix(), $qry);
79 $qry = str_replace('%TEMP_PREFIX%', rex::getTempPrefix(), $qry);
80
81 return $qry;
82 }
83
84 /**
85 * Reads a file and split all statements in it.
86 *
87 * @param string $file Path to the SQL-dump-file
88 *
89 * @return array
90 */
91 private static function readSqlDump($file)
92 {
93 if (is_file($file) && is_readable($file)) {
94 $ret = [];
95 $sqlsplit = [];
96 $fileContent = file_get_contents($file);
97 self::splitSqlFile($sqlsplit, $fileContent, '');
98
99 if (is_array($sqlsplit)) {
100 foreach ($sqlsplit as $qry) {
101 $ret[] = $qry['query'];
102 }
103 }
104
105 return $ret;
106 }
107
108 return false;
109 }
110
111 /**
112 * Removes comment lines and splits up large sql files into individual queries.
113 *
114 * Last revision: September 23, 2001 - gandon
115 *
116 * @param array $ret the splitted sql commands
117 * @param string $sql the sql commands
118 * @param int $release the MySQL release number (because certains php3 versions
119 * can't get the value of a constant from within a function)
120 *
121 * @return bool always true
122 */
123 // Taken from phpmyadmin (read_dump.lib.php: PMA_splitSqlFile)
124 public static function splitSqlFile(&$ret, $sql, $release)
125 {
126 // do not trim, see bug #1030644
127 //$sql = trim($sql);
128 $sql = rtrim($sql, "\n\r");
129 $sql_len = strlen($sql);
130 $string_start = '';
131 $in_string = false;
132 $nothing = true;
133 $time0 = time();
134
135 for ($i = 0; $i < $sql_len; ++$i) {
136 $char = $sql[$i];
137
138 // We are in a string, check for not escaped end of strings except for
139 // backquotes that can't be escaped
140 if ($in_string) {
141 for (; ;) {
142 $i = strpos($sql, $string_start, $i);
143 // No end of string found -> add the current substring to the
144 // returned array
145 if (!$i) {
146 $ret[] = $sql;
147 return true;
148 }
149 // Backquotes or no backslashes before quotes: it's indeed the
150 // end of the string -> exit the loop
151 if ($string_start == '`' || $sql[$i - 1] != '\\') {
152 $string_start = '';
153 $in_string = false;
154 break;
155 }
156 // one or more Backslashes before the presumed end of string...
157
158 // ... first checks for escaped backslashes
159 $j = 2;
160 $escaped_backslash = false;
161 while ($i - $j > 0 && $sql[$i - $j] == '\\') {
162 $escaped_backslash = !$escaped_backslash;
163 ++$j;
164 }
165 // ... if escaped backslashes: it's really the end of the
166 // string -> exit the loop
167 if ($escaped_backslash) {
168 $string_start = '';
169 $in_string = false;
170 break;
171 }
172 // ... else loop
173
174 ++$i;
175
176 // end if...elseif...else
177 } // end for
178 } // end if (in string)
179
180 // lets skip comments (/*, -- and #)
181 elseif (($char == '-' && $sql_len > $i + 2 && $sql[$i + 1] == '-' && $sql[$i + 2] <= ' ') || $char == '#' || ($char == '/' && $sql_len > $i + 1 && $sql[$i + 1] == '*')) {
182 $i = strpos($sql, $char == '/' ? '*/' : "\n", $i);
183 // didn't we hit end of string?
184 if ($i === false) {
185 break;
186 }
187 if ($char == '/') {
188 ++$i;
189 }
190 }
191
192 // We are not in a string, first check for delimiter...
193 elseif ($char == ';') {
194 // if delimiter found, add the parsed part to the returned array
195 $ret[] = ['query' => substr($sql, 0, $i), 'empty' => $nothing];
196 $nothing = true;
197 $sql = ltrim(substr($sql, min($i + 1, $sql_len)));
198 $sql_len = strlen($sql);
199 if ($sql_len) {
200 $i = -1;
201 } else {
202 // The submited statement(s) end(s) here
203 return true;
204 }
205 } // end else if (is delimiter)
206
207 // ... then check for start of a string,...
208 elseif (($char == '"') || ($char == '\'') || ($char == '`')) {
209 $in_string = true;
210 $nothing = false;
211 $string_start = $char;
212 } // end else if (is start of string)
213
214 elseif ($nothing) {
215 $nothing = false;
216 }
217
218 // loic1: send a fake header each 30 sec. to bypass browser timeout
219 $time1 = time();
220 if ($time1 >= $time0 + 30) {
221 $time0 = $time1;
222 header('X-pmaPing: Pong');
223 } // end if
224 } // end for
225
226 // add any rest to the returned array
227 if (!empty($sql) && preg_match('@[^[:space:]]+@', $sql)) {
228 $ret[] = ['query' => $sql, 'empty' => $nothing];
229 }
230
231 return true;
232 }
233 }
234