Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
acp_database.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 /**
015 * @ignore
016 */
017 if (!defined('IN_PHPBB'))
018 {
019 exit;
020 }
021
022 class acp_database
023 {
024 var $db_tools;
025 var $u_action;
026 public $page_title;
027
028 function main($id, $mode)
029 {
030 global $cache, $db, $user, $template, $table_prefix, $request;
031 global $phpbb_root_path, $phpbb_container, $phpbb_log;
032
033 $this->db_tools = $phpbb_container->get('dbal.tools');
034
035 $user->add_lang('acp/database');
036
037 $this->tpl_name = 'acp_database';
038 $this->page_title = 'ACP_DATABASE';
039
040 $action = $request->variable('action', '');
041
042 $form_key = 'acp_database';
043 add_form_key($form_key);
044
045 $template->assign_vars(array(
046 'MODE' => $mode
047 ));
048
049 switch ($mode)
050 {
051 case 'backup':
052
053 $this->page_title = 'ACP_BACKUP';
054
055 switch ($action)
056 {
057 case 'download':
058 $type = $request->variable('type', '');
059 $table = array_intersect($this->db_tools->sql_list_tables(), $request->variable('table', array('')));
060 $format = $request->variable('method', '');
061
062 if (!count($table))
063 {
064 trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
065 }
066
067 if (!check_form_key($form_key))
068 {
069 trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
070 }
071
072 @set_time_limit(1200);
073 @set_time_limit(0);
074
075 $time = time();
076
077 $filename = 'backup_' . $time . '_' . unique_id();
078
079 /** @var phpbb\db\extractor\extractor_interface $extractor Database extractor */
080 $extractor = $phpbb_container->get('dbal.extractor');
081 $extractor->init_extractor($format, $filename, $time, false, true);
082
083 $extractor->write_start($table_prefix);
084
085 foreach ($table as $table_name)
086 {
087 // Get the table structure
088 if ($type == 'full')
089 {
090 $extractor->write_table($table_name);
091 }
092 else
093 {
094 // We might wanna empty out all that junk :D
095 switch ($db->get_sql_layer())
096 {
097 case 'sqlite3':
098 $extractor->flush('DELETE FROM ' . $table_name . ";\n");
099 break;
100
101 case 'mssql_odbc':
102 case 'mssqlnative':
103 $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n");
104 break;
105
106 case 'oracle':
107 $extractor->flush('TRUNCATE TABLE ' . $table_name . "/\n");
108 break;
109
110 default:
111 $extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n");
112 }
113 }
114
115 // Only supported types are full and data, therefore always write the data
116 $extractor->write_data($table_name);
117 }
118
119 $extractor->write_end();
120
121 $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_BACKUP');
122
123 trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action));
124 break;
125
126 default:
127 $tables = $this->db_tools->sql_list_tables();
128 asort($tables);
129 foreach ($tables as $table_name)
130 {
131 if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0)
132 {
133 $template->assign_block_vars('tables', array(
134 'TABLE' => $table_name
135 ));
136 }
137 }
138 unset($tables);
139
140 $template->assign_vars(array(
141 'U_ACTION' => $this->u_action . '&action=download'
142 ));
143
144 $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2');
145
146 foreach ($available_methods as $type => $module)
147 {
148 if (!@extension_loaded($module))
149 {
150 continue;
151 }
152
153 $template->assign_block_vars('methods', array(
154 'TYPE' => $type
155 ));
156 }
157
158 $template->assign_block_vars('methods', array(
159 'TYPE' => 'text'
160 ));
161 break;
162 }
163 break;
164
165 case 'restore':
166
167 $this->page_title = 'ACP_RESTORE';
168
169 switch ($action)
170 {
171 case 'submit':
172 $delete = $request->variable('delete', '');
173 $file = $request->variable('file', '');
174
175 $backup_info = $this->get_backup_file($phpbb_root_path . 'store/', $file);
176
177 if (empty($backup_info) || !is_readable($backup_info['file_name']))
178 {
179 trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
180 }
181
182 if ($delete)
183 {
184 if (confirm_box(true))
185 {
186 unlink($backup_info['file_name']);
187 $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_DELETE');
188 trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action));
189 }
190 else
191 {
192 confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file)));
193 }
194 }
195 else if (confirm_box(true))
196 {
197 switch ($backup_info['extension'])
198 {
199 case 'sql':
200 $fp = fopen($backup_info['file_name'], 'rb');
201 $read = 'fread';
202 $seek = 'fseek';
203 $eof = 'feof';
204 $close = 'fclose';
205 $fgetd = 'fgetd';
206 break;
207
208 case 'sql.bz2':
209 $fp = bzopen($backup_info['file_name'], 'r');
210 $read = 'bzread';
211 $seek = '';
212 $eof = 'feof';
213 $close = 'bzclose';
214 $fgetd = 'fgetd_seekless';
215 break;
216
217 case 'sql.gz':
218 $fp = gzopen($backup_info['file_name'], 'rb');
219 $read = 'gzread';
220 $seek = 'gzseek';
221 $eof = 'gzeof';
222 $close = 'gzclose';
223 $fgetd = 'fgetd';
224 break;
225
226 default:
227 trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
228 return;
229 }
230
231 switch ($db->get_sql_layer())
232 {
233 case 'mysqli':
234 case 'sqlite3':
235 while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false)
236 {
237 $db->sql_query($sql);
238 }
239 break;
240
241 case 'postgres':
242 $delim = ";\n";
243 while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false)
244 {
245 $query = trim($sql);
246
247 if (substr($query, 0, 13) == 'CREATE DOMAIN')
248 {
249 list(, , $domain) = explode(' ', $query);
250 $sql = "SELECT domain_name
251 FROM information_schema.domains
252 WHERE domain_name = '$domain';";
253 $result = $db->sql_query($sql);
254 if (!$db->sql_fetchrow($result))
255 {
256 $db->sql_query($query);
257 }
258 $db->sql_freeresult($result);
259 }
260 else
261 {
262 $db->sql_query($query);
263 }
264
265 if (substr($query, 0, 4) == 'COPY')
266 {
267 while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.')
268 {
269 if ($sub === false)
270 {
271 trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING);
272 }
273 pg_put_line($db->get_db_connect_id(), $sub . "\n");
274 }
275 pg_put_line($db->get_db_connect_id(), "\\.\n");
276 pg_end_copy($db->get_db_connect_id());
277 }
278 }
279 break;
280
281 case 'oracle':
282 while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false)
283 {
284 $db->sql_query($sql);
285 }
286 break;
287
288 case 'mssql_odbc':
289 case 'mssqlnative':
290 while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false)
291 {
292 $db->sql_query($sql);
293 }
294 break;
295 }
296
297 $close($fp);
298
299 // Purge the cache due to updated data
300 $cache->purge();
301
302 $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_RESTORE');
303 trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action));
304 break;
305 }
306 else
307 {
308 confirm_box(false, $user->lang['RESTORE_SELECTED_BACKUP'], build_hidden_fields(array('file' => $file)));
309 }
310
311 default:
312 $backup_files = $this->get_file_list($phpbb_root_path . 'store/');
313
314 if (!empty($backup_files))
315 {
316 krsort($backup_files);
317
318 foreach ($backup_files as $name => $file)
319 {
320 $template->assign_block_vars('files', array(
321 'FILE' => sha1($file),
322 'NAME' => $user->format_date($name, 'd-m-Y H:i', true),
323 'SUPPORTED' => true,
324 ));
325 }
326 }
327
328 $template->assign_vars(array(
329 'U_ACTION' => $this->u_action . '&action=submit'
330 ));
331 break;
332 }
333 break;
334 }
335 }
336
337 /**
338 * Get backup file from file hash
339 *
340 * @param string $directory Relative path to directory
341 * @param string $file_hash Hash of selected file
342 *
343 * @return array Backup file data or empty array if unable to find file
344 */
345 protected function get_backup_file($directory, $file_hash)
346 {
347 $backup_data = [];
348
349 $file_list = $this->get_file_list($directory);
350 $supported_extensions = $this->get_supported_extensions();
351
352 foreach ($file_list as $file)
353 {
354 preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches);
355 if (sha1($file) === $file_hash && in_array($matches[2], $supported_extensions))
356 {
357 $backup_data = [
358 'file_name' => $directory . $file,
359 'extension' => $matches[2],
360 ];
361 break;
362 }
363 }
364
365 return $backup_data;
366 }
367
368 /**
369 * Get backup file list for directory
370 *
371 * @param string $directory Relative path to backup directory
372 *
373 * @return array List of backup files in specified directory
374 */
375 protected function get_file_list($directory)
376 {
377 $supported_extensions = $this->get_supported_extensions();
378
379 $dh = @opendir($directory);
380
381 $backup_files = [];
382
383 if ($dh)
384 {
385 while (($file = readdir($dh)) !== false)
386 {
387 if (preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches))
388 {
389 if (in_array($matches[2], $supported_extensions))
390 {
391 $backup_files[(int) $matches[1]] = $file;
392 }
393 }
394 }
395 closedir($dh);
396 }
397
398 return $backup_files;
399 }
400
401 /**
402 * Get supported extensions for backup
403 *
404 * @return array List of supported extensions
405 */
406 protected function get_supported_extensions()
407 {
408 $extensions = ['sql'];
409 $available_methods = ['sql.gz' => 'zlib', 'sql.bz2' => 'bz2'];
410
411 foreach ($available_methods as $type => $module)
412 {
413 if (!@extension_loaded($module))
414 {
415 continue;
416 }
417 $extensions[] = $type;
418 }
419
420 return $extensions;
421 }
422 }
423
424 // get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P)
425 function get_usable_memory()
426 {
427 $val = trim(@ini_get('memory_limit'));
428
429 if (preg_match('/(\\d+)([mkg]?)/i', $val, $regs))
430 {
431 $memory_limit = (int) $regs[1];
432 switch ($regs[2])
433 {
434
435 case 'k':
436 case 'K':
437 $memory_limit *= 1024;
438 break;
439
440 case 'm':
441 case 'M':
442 $memory_limit *= 1048576;
443 break;
444
445 case 'g':
446 case 'G':
447 $memory_limit *= 1073741824;
448 break;
449 }
450
451 // how much memory PHP requires at the start of export (it is really a little less)
452 if ($memory_limit > 6100000)
453 {
454 $memory_limit -= 6100000;
455 }
456
457 // allow us to consume half of the total memory available
458 $memory_limit /= 2;
459 }
460 else
461 {
462 // set the buffer to 1M if we have no clue how much memory PHP will give us :P
463 $memory_limit = 1048576;
464 }
465
466 return $memory_limit;
467 }
468
469 function sanitize_data_mssql($text)
470 {
471 $data = preg_split('/[\n\t\r\b\f]/', $text);
472 preg_match_all('/[\n\t\r\b\f]/', $text, $matches);
473
474 $val = array();
475
476 foreach ($data as $value)
477 {
478 if (strlen($value))
479 {
480 $val[] = "'" . $value . "'";
481 }
482 if (count($matches[0]))
483 {
484 $val[] = 'char(' . ord(array_shift($matches[0])) . ')';
485 }
486 }
487
488 return implode('+', $val);
489 }
490
491 function sanitize_data_oracle($text)
492 {
493 // $data = preg_split('/[\0\n\t\r\b\f\'"\/\\\]/', $text);
494 // preg_match_all('/[\0\n\t\r\b\f\'"\/\\\]/', $text, $matches);
495 $data = preg_split('/[\0\b\f\'\/]/', $text);
496 preg_match_all('/[\0\r\b\f\'\/]/', $text, $matches);
497
498 $val = array();
499
500 foreach ($data as $value)
501 {
502 if (strlen($value))
503 {
504 $val[] = "'" . $value . "'";
505 }
506 if (count($matches[0]))
507 {
508 $val[] = 'chr(' . ord(array_shift($matches[0])) . ')';
509 }
510 }
511
512 return implode('||', $val);
513 }
514
515 function sanitize_data_generic($text)
516 {
517 $data = preg_split('/[\n\t\r\b\f]/', $text);
518 preg_match_all('/[\n\t\r\b\f]/', $text, $matches);
519
520 $val = array();
521
522 foreach ($data as $value)
523 {
524 if (strlen($value))
525 {
526 $val[] = "'" . $value . "'";
527 }
528 if (count($matches[0]))
529 {
530 $val[] = "'" . array_shift($matches[0]) . "'";
531 }
532 }
533
534 return implode('||', $val);
535 }
536
537 // modified from PHP.net
538 function fgetd(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
539 {
540 $record = '';
541 $delim_len = strlen($delim);
542
543 while (!$eof($fp))
544 {
545 $pos = strpos($record, $delim);
546 if ($pos === false)
547 {
548 $record .= $read($fp, $buffer);
549 if ($eof($fp) && ($pos = strpos($record, $delim)) !== false)
550 {
551 $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR);
552 return substr($record, 0, $pos);
553 }
554 }
555 else
556 {
557 $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR);
558 return substr($record, 0, $pos);
559 }
560 }
561
562 return false;
563 }
564
565 function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
566 {
567 static $array = array();
568 static $record = '';
569
570 if (!count($array))
571 {
572 while (!$eof($fp))
573 {
574 if (strpos($record, $delim) !== false)
575 {
576 $array = explode($delim, $record);
577 $record = array_pop($array);
578 break;
579 }
580 else
581 {
582 $record .= $read($fp, $buffer);
583 }
584 }
585 if ($eof($fp) && strpos($record, $delim) !== false)
586 {
587 $array = explode($delim, $record);
588 $record = array_pop($array);
589 }
590 }
591
592 if (count($array))
593 {
594 return array_shift($array);
595 }
596
597 return false;
598 }
599