<? /* * This file is part of the 'Science Fair In A Box' project * SFIAB Website: http://www.sfiab.ca * * Copyright (C) 2008 James Grant <james@lightbox.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ ?> <? require ('../common.inc.php'); require_once ('../user.inc.php'); user_auth_required('committee', 'config'); // make sure backup/restore folder exists, and htaccess it to deny access if (!file_exists('../data/backuprestore')) mkdir('../data/backuprestore'); if (!file_exists('../data/backuprestore/.htaccess')) file_put_contents('../data/backuprestore/.htaccess', "Order Deny,Allow\r\nDeny From All\r\n"); if (get_value_from_array($_GET, 'action') == 'backup') { $ts = time(); $dump = '#SFIAB SQL BACKUP: ' . date('r', $ts) . "\n"; $dump .= '#SFIAB VERSION: ' . $config['version'] . "\n"; $dump .= '#SFIAB DB VERSION: ' . $config['DBVERSION'] . "\n"; $dump .= '#SFIAB FAIR NAME: ' . $config['fairname'] . "\n"; $dump .= "#-------------------------------------------------\n"; $tableq = $pdo->prepare("SHOW TABLES FROM `$DBNAME`"); $tableq->execute(); while ($tr = $tableq->fetch(PDO::FETCH_NUM)) { $table = $tr[0]; $dump .= "#TABLE: $table\n"; $columnq = $pdo->prepare("SHOW COLUMNS FROM `$table`"); $columnq->execute(); $str = "INSERT INTO `$table` ("; unset($fields); $fields = array(); while ($cr = $columnq->fetch(PDO::FETCH_OBJ)) { $str .= '`' . $cr->Field . '`,'; $fields[] = $cr->Field; } $str = substr($str, 0, -1); $str .= ') VALUES ('; $dataq = $pdo->prepare("SELECT * FROM `$table` ORDER BY `{$fields[0]}`"); $dataq->execute(); while ($data = $dataq->fetch(PDO::FETCH_OBJ)) { $insertstr = $str; foreach ($fields AS $field) { if (is_null($data->$field)) $insertstr .= 'NULL,'; else { $escaped = str_replace('\\', '\\\\', $data->$field); $escaped = str_replace("'", "''", $escaped); $escaped = str_replace("\n", '\n', $escaped); $escaped = str_replace("\r", '\r', $escaped); $insertstr .= "'" . $escaped . "',"; } } $insertstr = substr($insertstr, 0, -1); $insertstr .= ');'; $dump .= $insertstr . "\n"; } } header('Content-Type: text/sql'); header('Content-Disposition: attachment; filename=sfiab_backup_' . date('Y-m-d-H-i-s', $ts) . '.sql'); header('Content-Length: ' . strlen($dump)); // Make IE with SSL work header('Pragma: public'); echo $dump; } else if (get_value_from_array($_POST, 'action') == 'restore') { echo send_header('Database Backup/Restore', array('Committee Main' => 'committee_main.php', 'SFIAB Configuration' => 'config/index.php'), 'backup_restore'); echo i18n('Processing file: %1', array($_FILES['restore']['name'])) . "<br />\n"; echo "<br />\n"; do { // hmm just some random filename $tmpfilename = md5(rand() . time() . $_FILES['restore']['name']); } while (file_exists("../data/backuprestore/$tmpfilename")); move_uploaded_file($_FILES['restore']['tmp_name'], "../data/backuprestore/$tmpfilename"); $fp = fopen("../data/backuprestore/$tmpfilename", 'r'); for ($x = 0; $x < 4; $x++) { $line = fgets($fp, 1024); $hdr[$x] = split(':', trim($line), 2); } fclose($fp); if (trim($hdr[0][0]) == '#SFIAB SQL BACKUP') { echo "<table class=\"tableview\">\n"; $now = date('r'); echo '<tr><th>' . i18n('Information') . '</th><th>' . i18n('Restore File') . '</th><th>' . i18n('Live System') . "</th></tr>\n"; if (trim($hdr[0][1]) < trim($now)) $cl = 'happy'; else { $cl = 'error'; $err = true; } echo "<tr class=\"$cl\"><td>" . i18n('Date/Time') . '</td><td>' . $hdr[0][1] . "</td><td>$now</td></tr>\n"; if (version_compare(trim($hdr[1][1]), $config['version']) == 0) $cl = 'happy'; else { $cl = 'error'; $err = true; } echo "<tr class=\"$cl\"><td>" . i18n('SFIAB Version') . '</td><td>' . $hdr[1][1] . '</td><td>' . $config['version'] . "</td></tr>\n"; if (version_compare(trim($hdr[2][1]), $config['DBVERSION']) == 0) $cl = 'happy'; else { $cl = 'error'; $err = true; } echo "<tr class=\"$cl\"><td>" . i18n('Database Version') . '</td><td>' . $hdr[2][1] . '</td><td>' . $config['DBVERSION'] . "</td></tr>\n"; if (trim($hdr[3][1]) == $config['fairname']) $cl = 'happy'; else { $cl = 'error'; $err = true; } echo "<tr class=\"$cl\"><td>" . i18n('Fair Name') . '</td><td>' . $hdr[3][1] . '</td><td>' . $config['fairname'] . "</td></tr>\n"; echo "</table>\n"; echo "<br />\n"; if ($err) { echo error(i18n('Warning, there are discrepencies between the restore file and your current live system. Proceed at your own risk!')); } echo "<form method=\"post\" action=\"backuprestore.php\">\n"; echo "<input type=\"hidden\" name=\"action\" value=\"restoreproceed\">\n"; echo '<input type="hidden" name="filename" value="' . $_FILES['restore']['name'] . "\">\n"; echo "<input type=\"hidden\" name=\"realfilename\" value=\"$tmpfilename\">\n"; echo '<input type="submit" value="' . i18n('Proceed with Database Restore') . '">'; echo "</form>\n"; echo "<br />\n"; echo '<a href="backuprestore.php">'; echo i18n('If you are not going to proceed, please click here to clean up the temporary files which may contain confidential information!'); echo "</a>\n"; } else { echo error(i18n('This file is NOT a SFIAB SQL BACKUP file')); echo i18n('Only backups created with the SFIAB Backup Creator can be used to restore from.'); echo "<br />\n"; } send_footer(); } else if (get_value_from_array($_POST, 'action') == 'restoreproceed') { echo send_header('Database Backup/Restore', array('Committee Main' => 'committee_main.php', 'SFIAB Configuration' => 'config/index.php'), 'backup_restore'); // make sure the filename's good before we used it if (mb_ereg('^[a-z0-9]{32}$', $_POST['realfilename']) && file_exists('../data/backuprestore/' . $_POST['realfilename'])) { $filename = $_POST['realfilename']; echo i18n('Proceeding with database restore from %1', array($_POST['filename'])) . '...'; $lines = file("../data/backuprestore/$filename"); $err = false; echo '<pre>'; foreach ($lines AS $line) { $line = trim($line); if (mb_ereg('^#TABLE: (.*)', $line, $args)) { // empty out the table $sql = 'TRUNCATE TABLE `' . $args[1] . '`'; // echo $sql."\n"; $stmt = $pdo->prepare($sql); $stmt->execute(); } else if (mb_ereg('^#', $line)) { // just skip it } else { // insert the new data $stmt = $pdo->prepare($line); $stmt->execute(); if ($pdo->errorInfo()) { echo $line . "\n"; echo $pdo->errorInfo() . "\n"; $err = true; } } } echo '</pre>'; if ($err) { echo error(i18n('An error occured while importing the restore database')); } else echo happy(i18n('Database successfully restored')); unlink("../data/backuprestore/$filename"); } else echo error(i18n('Invalid filename')); send_footer(); } else if (get_value_from_array($_POST, 'action') == 'clean_judges') { // select all judges $query = $pdo->prepare('SELECT * FROM users WHERE types LIKE "judge"'); $query->execute(); show_pdo_errors_if_any($pdo); // Go through each judge and test: while ($judge = $query->fetch(PDO::FETCH_ASSOC)) { // if they are deleted if ($judge['deleted'] == 'yes') { // Make types an array if it isn't already. Allows user_purge function to work properly if (!is_array($judge['types'])) { $judge['types'] = array($judge['types']); } user_purge($judge, 'judge'); } else { // Find max year of judge $max_year_query = $pdo->prepare('SELECT year FROM users WHERE uid = ' . $judge['uid'] . ' ORDER BY year DESC limit 1'); $max_year_query->execute(); $judge_max_year = $max_year_query->fetch(PDO::FETCH_ASSOC); // Grab old judge info. // Old judge info consists of all entries in the database that are not the most recent for the specific judge $deletable = $pdo->prepare('SELECT * FROM users WHERE uid =' . $judge['uid'] . ' AND year NOT LIKE ' . $judge_max_year['year']); $deletable->execute(); // and if they have old data from previous fair years if ($deletable->rowCount() > 0) { // delete old data one by one while ($old_judge_data = $deletable->fetch(PDO::FETCH_ASSOC)) { if (!isset($old_judge_data['type']) && !is_array($old_judge_data['type'])) { $old_judge_data['types'] = array($old_judge_data['types']); } user_purge($old_judge_data, 'judge'); } } } } echo send_header('Database Backup/Restore', array('Committee Main' => 'committee_main.php', 'SFIAB Configuration' => 'config/index.php'), 'backup_restore'); $stmt = $pdo->prepare('OPTIMIZE TABLE users, users_judge'); $stmt->execute(); if ($pdo->errorInfo()[0] == 0) { echo happy(i18n('Old judge data purged.')); } else { error(i18n($pdo->errorInfo()[0])); } } else if (get_value_from_array($_POST, 'action') == 'clean_parents') { $query_parents = $pdo->prepare('SELECT * FROM users WHERE types LIKE "parent" AND year !=' . $config['FAIRYEAR']); $query_parents->execute(); while ($parent = $query_parents->fetch(PDO::FETCH_ASSOC)) { if (!is_array($parent['types'])) { $parent['types'] = array($parent['types']); } user_purge($parent, 'parent'); } echo send_header('Database Backup/Restore', array('Committee Main' => 'committee_main.php', 'SFIAB Configuration' => 'config/index.php'), 'backup_restore'); $stmt = $pdo->prepare('OPTIMIZE TABLE users, users_parent'); $stmt->execute(); if ($pdo->errorInfo()[0] == 0) { echo happy(i18n('Old parent data purged.')); } else { error(i18n($pdo->errorInfo()[0])); } } else { echo send_header('Database Backup/Restore', array('Committee Main' => 'committee_main.php', 'SFIAB Configuration' => 'config/index.php'), 'backup_restore'); // we try to remove temp files every time we load this page, who knows, maybe they navigated away // last time instead of clicking the link to come back here $dh = opendir('../data/backuprestore'); $removed = false; while ($fn = readdir($dh)) { if (mb_ereg('[a-z0-9]{32}', $fn)) { unlink("../data/backuprestore/$fn"); $removed = true; } } closedir($dh); if ($removed) { echo happy(i18n('Temporary files successfully removed')); } echo '<h3>' . i18n('Backup Database') . "</h3>\n"; echo '<a href="backuprestore.php?action=backup">' . i18n('Create Database Backup File') . "</a><br />\n"; echo "<br /><br />\n"; echo "<hr />\n"; echo '<h3>' . i18n('Restore Database') . "</h3>\n"; echo error(i18n('WARNING: Importing a backup will completely DESTROY all data currently in the database and replace it with what is in the backup file')); echo "<form method=\"post\" action=\"backuprestore.php\" enctype=\"multipart/form-data\">\n"; echo "<input type=\"hidden\" name=\"action\" value=\"restore\">\n"; echo "<input type=\"file\" name=\"restore\">\n"; echo '<input type="submit" value="' . i18n('Upload Restore File') . "\">\n"; echo "</form>\n"; echo '<br>'; echo '<h3>' . i18n('Clean Database') . "</h3>\n"; echo error(i18n('WARNING: Cleaning the database COMPLETELY DELETES old data on users')); echo '<font size = 4 color="red"> RECOMMENDED: Backup database before using the below buttons</font><br><br>'; echo "<font color=\"red\"> Remove Old Judge Data <ul> <li> All information about who has judged in past fairs will be lost \t <li> All deleted judges will be purged from the system </ul></font>"; echo "<br><font color=\"red\"> Remove Old Emergency Contact / Parent Data<ul> <li> All parent information or other emergency contact information from all previous fair years will be purged from the system \t \t\t\t\t\t\t\t\t\t\t\t\t<li> It will no longer be possible to email any emergency contacts from previous fair years once the button is clicked </ul></font><br>"; echo '<table>'; echo '<tr><td style = "width: 46%">'; echo "<form method=\"post\" action=\"backuprestore.php\" enctype=\"multipart/form-data\">\n"; echo "<input type=\"hidden\" name=\"action\" value=\"clean_judges\">\n"; echo '<input type="submit" onClick="return confirmClick(\'Are you sure you wish to purge old judge data?\')" value="' . i18n('Remove Old Judge Data') . "\">\n"; echo '</form>'; echo '</td><td>'; echo "<form method=\"post\" action=\"backuprestore.php\" enctype=\"multipart/form-data\">\n"; echo "<input type=\"hidden\" name=\"action\" value=\"clean_parents\">\n"; echo '<input type="submit" onClick="return confirmClick(\'Are you sure you wish to purge old parent data?\')" value="' . i18n('Remove Old Emergency Contact / Parent Data') . "\">\n"; echo '</form>'; send_footer(); } ?>