1<?php
2/**
3 * MyBB 1.8
4 * Copyright 2014 MyBB Group, All Rights Reserved
5 *
6 * Website: http://www.mybb.com
7 * License: http://www.mybb.com/about/license
8 *
9 */
10
11// Disallow direct access to this file for security reasons
12if(!defined("IN_MYBB"))
13{
14	die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
15}
16
17/**
18 * Allows us to refresh cache to prevent over flowing
19 *
20 * @param resource $fp
21 * @param string $contents
22 */
23function clear_overflow($fp, &$contents)
24{
25	global $mybb;
26
27	if($mybb->input['method'] == 'disk')
28	{
29		if($mybb->input['filetype'] == 'gzip')
30		{
31			gzwrite($fp, $contents);
32		}
33		else
34		{
35			fwrite($fp, $contents);
36		}
37	}
38	else
39	{
40		if($mybb->input['filetype'] == "gzip")
41		{
42			echo gzencode($contents);
43		}
44		else
45		{
46			echo $contents;
47		}
48	}
49
50	$contents = '';
51}
52
53$page->add_breadcrumb_item($lang->database_backups, "index.php?module=tools-backupdb");
54
55$plugins->run_hooks("admin_tools_backupdb_begin");
56
57if($mybb->input['action'] == "dlbackup")
58{
59	if(empty($mybb->input['file']))
60	{
61		flash_message($lang->error_file_not_specified, 'error');
62		admin_redirect("index.php?module=tools-backupdb");
63	}
64
65	$plugins->run_hooks("admin_tools_backupdb_dlbackup");
66
67	$file = basename($mybb->input['file']);
68	$ext = get_extension($file);
69
70	if(file_exists(MYBB_ADMIN_DIR.'backups/'.$file) && filetype(MYBB_ADMIN_DIR.'backups/'.$file) == 'file' && ($ext == 'gz' || $ext == 'sql'))
71	{
72		$plugins->run_hooks("admin_tools_backupdb_dlbackup_commit");
73
74		// Log admin action
75		log_admin_action($file);
76
77		header('Content-disposition: attachment; filename='.$file);
78		header("Content-type: ".$ext);
79		header("Content-length: ".filesize(MYBB_ADMIN_DIR.'backups/'.$file));
80
81		$handle = fopen(MYBB_ADMIN_DIR.'backups/'.$file, 'rb');
82		while(!feof($handle))
83		{
84			echo fread($handle, 8192);
85		}
86		fclose($handle);
87	}
88	else
89	{
90		flash_message($lang->error_invalid_backup, 'error');
91		admin_redirect("index.php?module=tools-backupdb");
92	}
93}
94
95if($mybb->input['action'] == "delete")
96{
97	if($mybb->get_input('no'))
98	{
99		admin_redirect("index.php?module=tools-backupdb");
100	}
101
102	$file = basename($mybb->input['file']);
103
104	if(!trim($mybb->input['file']) || !file_exists(MYBB_ADMIN_DIR.'backups/'.$file))
105	{
106		flash_message($lang->error_backup_doesnt_exist, 'error');
107		admin_redirect("index.php?module=tools-backupdb");
108	}
109
110	$plugins->run_hooks("admin_tools_backupdb_delete");
111
112	if($mybb->request_method == "post")
113	{
114		$delete = @unlink(MYBB_ADMIN_DIR.'backups/'.$file);
115
116		if($delete)
117		{
118			$plugins->run_hooks("admin_tools_backupdb_delete_commit");
119
120			// Log admin action
121			log_admin_action($file);
122
123			flash_message($lang->success_backup_deleted, 'success');
124			admin_redirect("index.php?module=tools-backupdb");
125		}
126		else
127		{
128			flash_message($lang->error_backup_not_deleted, 'error');
129			admin_redirect("index.php?module=tools-backupdb");
130		}
131	}
132	else
133	{
134		$page->output_confirm_action("index.php?module=tools-backupdb&amp;action=delete&amp;file={$mybb->input['file']}", $lang->confirm_backup_deletion);
135	}
136}
137
138if($mybb->input['action'] == "backup")
139{
140	$plugins->run_hooks("admin_tools_backupdb_backup");
141
142	if($mybb->request_method == "post")
143	{
144		if(empty($mybb->input['tables']) || !is_array($mybb->input['tables']))
145		{
146			flash_message($lang->error_tables_not_selected, 'error');
147			admin_redirect("index.php?module=tools-backupdb&action=backup");
148		}
149
150		@set_time_limit(0);
151
152		if($mybb->input['method'] == 'disk')
153		{
154			$file = MYBB_ADMIN_DIR.'backups/backup_'.date("_Ymd_His_").random_str(16);
155
156			if($mybb->input['filetype'] == 'gzip')
157			{
158				if(!function_exists('gzopen')) // check zlib-ness
159				{
160					flash_message($lang->error_no_zlib, 'error');
161					admin_redirect("index.php?module=tools-backupdb&action=backup");
162				}
163
164				$fp = gzopen($file.'.incomplete.sql.gz', 'w9');
165			}
166			else
167			{
168				$fp = fopen($file.'.incomplete.sql', 'w');
169			}
170		}
171		else
172		{
173			$file = 'backup_'.substr(md5($mybb->user['uid'].TIME_NOW), 0, 10).random_str(54);
174			if($mybb->input['filetype'] == 'gzip')
175			{
176				if(!function_exists('gzopen')) // check zlib-ness
177				{
178					flash_message($lang->error_no_zlib, 'error');
179					admin_redirect("index.php?module=tools-backupdb&action=backup");
180				}
181
182				// Send headers for gzip file
183				header('Content-Type: application/x-gzip');
184				header('Content-Disposition: attachment; filename="'.$file.'.sql.gz"');
185			}
186			else
187			{
188				// Send standard headers for .sql
189				header('Content-Type: text/x-sql');
190				header('Content-Disposition: attachment; filename="'.$file.'.sql"');
191			}
192		}
193		$db->set_table_prefix('');
194
195		$time = date('dS F Y \a\t H:i', TIME_NOW);
196		$header = "-- MyBB Database Backup\n-- Generated: {$time}\n-- -------------------------------------\n\n";
197		$contents = $header;
198		foreach($mybb->input['tables'] as $table)
199		{
200			if(!$db->table_exists($db->escape_string($table)))
201			{
202				continue;
203			}
204			if($mybb->input['analyzeoptimize'] == 1)
205			{
206				$db->optimize_table($table);
207				$db->analyze_table($table);
208			}
209
210			$field_list = array();
211			$fields_array = $db->show_fields_from($table);
212			foreach($fields_array as $field)
213			{
214				$field_list[] = $field['Field'];
215			}
216
217			$fields = "`".implode("`,`", $field_list)."`";
218			if($mybb->input['contents'] != 'data')
219			{
220				$structure = $db->show_create_table($table).";\n";
221				$contents .= $structure;
222
223				if(isset($fp))
224				{
225					clear_overflow($fp, $contents);
226				}
227			}
228
229			if($mybb->input['contents'] != 'structure')
230			{
231				if($db->engine == 'mysqli')
232				{
233					$query = mysqli_query($db->read_link, "SELECT * FROM {$db->table_prefix}{$table}", MYSQLI_USE_RESULT);
234				}
235				else
236				{
237					$query = $db->simple_select($table);
238				}
239
240				while($row = $db->fetch_array($query))
241				{
242					$insert = "INSERT INTO {$table} ($fields) VALUES (";
243					$comma = '';
244					foreach($field_list as $field)
245					{
246						if(!isset($row[$field]) || is_null($row[$field]))
247						{
248							$insert .= $comma."NULL";
249						}
250						else if($db->engine == 'mysqli')
251						{
252							$insert .= $comma."'".mysqli_real_escape_string($db->read_link, $row[$field])."'";
253						}
254						else
255						{
256							$insert .= $comma."'".$db->escape_string($row[$field])."'";
257						}
258						$comma = ',';
259					}
260					$insert .= ");\n";
261					$contents .= $insert;
262
263					if(isset($fp))
264					{
265						clear_overflow($fp, $contents);
266					}
267				}
268				$db->free_result($query);
269			}
270		}
271
272		$db->set_table_prefix(TABLE_PREFIX);
273
274		if($mybb->input['method'] == 'disk')
275		{
276			if($mybb->input['filetype'] == 'gzip')
277			{
278				gzwrite($fp, $contents);
279				gzclose($fp);
280				rename($file.'.incomplete.sql.gz', $file.'.sql.gz');
281			}
282			else
283			{
284				fwrite($fp, $contents);
285				fclose($fp);
286				rename($file.'.incomplete.sql', $file.'.sql');
287			}
288
289			if($mybb->input['filetype'] == 'gzip')
290			{
291				$ext = '.sql.gz';
292			}
293			else
294			{
295				$ext = '.sql';
296			}
297
298			$plugins->run_hooks("admin_tools_backupdb_backup_disk_commit");
299
300			// Log admin action
301			log_admin_action("disk", $file.$ext);
302
303			$file_from_admindir = 'index.php?module=tools-backupdb&amp;action=dlbackup&amp;file='.basename($file).$ext;
304			flash_message("<span><em>{$lang->success_backup_created}</em></span><p>{$lang->backup_saved_to}<br />{$file}{$ext} (<a href=\"{$file_from_admindir}\">{$lang->download}</a>)</p>", 'success');
305			admin_redirect("index.php?module=tools-backupdb");
306		}
307		else
308		{
309			$plugins->run_hooks("admin_tools_backupdb_backup_download_commit");
310
311			// Log admin action
312			log_admin_action("download");
313
314			if($mybb->input['filetype'] == 'gzip')
315			{
316				echo gzencode($contents);
317			}
318			else
319			{
320				echo $contents;
321			}
322		}
323
324		exit;
325	}
326
327	$page->extra_header = "	<script type=\"text/javascript\">
328	function changeSelection(action, prefix)
329	{
330		var select_box = document.getElementById('table_select');
331
332		for(var i = 0; i < select_box.length; i++)
333		{
334			if(action == 'select')
335			{
336				select_box[i].selected = true;
337			}
338			else if(action == 'deselect')
339			{
340				select_box[i].selected = false;
341			}
342			else if(action == 'forum' && prefix != 0)
343			{
344				select_box[i].selected = false;
345				var row = select_box[i].value;
346				var subString = row.substring(prefix.length, 0);
347				if(subString == prefix)
348				{
349					select_box[i].selected = true;
350				}
351			}
352		}
353	}
354	</script>\n";
355
356	$page->add_breadcrumb_item($lang->new_database_backup);
357	$page->output_header($lang->new_database_backup);
358
359	$sub_tabs['database_backup'] = array(
360		'title' => $lang->database_backups,
361		'link' => "index.php?module=tools-backupdb"
362	);
363
364	$sub_tabs['new_backup'] = array(
365		'title' => $lang->new_backup,
366		'link' => "index.php?module=tools-backupdb&amp;action=backup",
367		'description' => $lang->new_backup_desc
368	);
369
370	$page->output_nav_tabs($sub_tabs, 'new_backup');
371
372	// Check if file is writable, before allowing submission
373	if(!is_writable(MYBB_ADMIN_DIR."/backups"))
374	{
375		$lang->update_button = '';
376		$page->output_alert($lang->alert_not_writable);
377		$cannot_write = true;
378	}
379
380	$table = new Table;
381	$table->construct_header($lang->table_selection);
382	$table->construct_header($lang->backup_options);
383
384	$table_selects = array();
385	$table_list = $db->list_tables($config['database']['database']);
386	foreach($table_list as $id => $table_name)
387	{
388		$table_selects[$table_name] = $table_name;
389	}
390
391	$form = new Form("index.php?module=tools-backupdb&amp;action=backup", "post", "table_selection", 0, "table_selection");
392
393	$table->construct_cell("{$lang->table_select_desc}\n<br /><br />\n<a href=\"javascript:changeSelection('select', 0);\">{$lang->select_all}</a><br />\n<a href=\"javascript:changeSelection('deselect', 0);\">{$lang->deselect_all}</a><br />\n<a href=\"javascript:changeSelection('forum', '".TABLE_PREFIX."');\">{$lang->select_forum_tables}</a>\n<br /><br />\n<div class=\"form_row\">".$form->generate_select_box("tables[]", $table_selects, false, array('multiple' => true, 'id' => 'table_select', 'size' => 20))."</div>", array('rowspan' => 5, 'width' => '50%', 'style' => 'border-bottom: 0px'));
394	$table->construct_row();
395
396	$table->construct_cell("<strong>{$lang->file_type}</strong><br />\n{$lang->file_type_desc}<br />\n<div class=\"form_row\">".$form->generate_radio_button("filetype", "gzip", $lang->gzip_compressed, array('checked' => 1))."<br />\n".$form->generate_radio_button("filetype", "plain", $lang->plain_text)."</div>", array('width' => '50%'));
397	$table->construct_row();
398	$table->construct_cell("<strong>{$lang->save_method}</strong><br />\n{$lang->save_method_desc}<br /><div class=\"form_row\">".$form->generate_radio_button("method", "disk", $lang->backup_directory)."<br />\n".$form->generate_radio_button("method", "download", $lang->download, array('checked' => 1))."</div>", array('width' => '50%'));
399	$table->construct_row();
400	$table->construct_cell("<strong>{$lang->backup_contents}</strong><br />\n{$lang->backup_contents_desc}<br /><div class=\"form_row\">".$form->generate_radio_button("contents", "both", $lang->structure_and_data, array('checked' => 1))."<br />\n".$form->generate_radio_button("contents", "structure", $lang->structure_only)."<br />\n".$form->generate_radio_button("contents", "data", $lang->data_only)."</div>", array('width' => '50%'));
401	$table->construct_row();
402	$table->construct_cell("<strong>{$lang->analyze_and_optimize}</strong><br />\n{$lang->analyze_and_optimize_desc}<br /><div class=\"form_row\">".$form->generate_yes_no_radio("analyzeoptimize")."</div>", array('width' => '50%'));
403	$table->construct_row();
404
405	$table->output($lang->new_database_backup);
406
407	$buttons[] = $form->generate_submit_button($lang->perform_backup);
408	$form->output_submit_wrapper($buttons);
409
410	$form->end();
411
412	$page->output_footer();
413}
414
415if(!$mybb->input['action'])
416{
417	$page->add_breadcrumb_item($lang->backups);
418	$page->output_header($lang->database_backups);
419
420	$sub_tabs['database_backup'] = array(
421		'title' => $lang->database_backups,
422		'link' => "index.php?module=tools-backupdb",
423		'description' => $lang->database_backups_desc
424	);
425
426	$sub_tabs['new_backup'] = array(
427		'title' => $lang->new_backup,
428		'link' => "index.php?module=tools-backupdb&amp;action=backup",
429	);
430
431	$plugins->run_hooks("admin_tools_backupdb_start");
432
433	$page->output_nav_tabs($sub_tabs, 'database_backup');
434
435	$backups = array();
436	$dir = MYBB_ADMIN_DIR.'backups/';
437	$handle = opendir($dir);
438
439	if($handle !== false)
440	{
441		while(($file = readdir($handle)) !== false)
442		{
443			if(filetype(MYBB_ADMIN_DIR.'backups/'.$file) == 'file')
444			{
445				$ext = get_extension($file);
446				if($ext == 'gz' || $ext == 'sql')
447				{
448					$backups[@filemtime(MYBB_ADMIN_DIR.'backups/'.$file)] = array(
449						"file" => $file,
450						"time" => @filemtime(MYBB_ADMIN_DIR.'backups/'.$file),
451						"type" => $ext
452					);
453				}
454			}
455		}
456		closedir($handle);
457	}
458
459	$count = count($backups);
460	krsort($backups);
461
462	$table = new Table;
463	$table->construct_header($lang->backup_filename);
464	$table->construct_header($lang->file_size, array("class" => "align_center"));
465	$table->construct_header($lang->creation_date);
466	$table->construct_header($lang->controls, array("class" => "align_center"));
467
468	foreach($backups as $backup)
469	{
470		$time = "-";
471		if($backup['time'])
472		{
473			$time = my_date('relative', $backup['time']);
474		}
475
476		$table->construct_cell("<a href=\"index.php?module=tools-backupdb&amp;action=dlbackup&amp;file={$backup['file']}\">{$backup['file']}</a>");
477		$table->construct_cell(get_friendly_size(filesize(MYBB_ADMIN_DIR.'backups/'.$backup['file'])), array("class" => "align_center"));
478		$table->construct_cell($time);
479		$table->construct_cell("<a href=\"index.php?module=tools-backupdb&amp;action=backup&amp;action=delete&amp;file={$backup['file']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_backup_deletion}')\">{$lang->delete}</a>", array("class" => "align_center"));
480		$table->construct_row();
481	}
482
483	if($count == 0)
484	{
485		$table->construct_cell($lang->no_backups, array('colspan' => 4));
486		$table->construct_row();
487	}
488
489	$table->output($lang->existing_database_backups);
490	$page->output_footer();
491}
492