Skip to content

Instantly share code, notes, and snippets.

@Firestorm-Graphics
Last active July 9, 2017 16:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Firestorm-Graphics/23862bf5a7111aea675ab748cb0e01d8 to your computer and use it in GitHub Desktop.
Save Firestorm-Graphics/23862bf5a7111aea675ab748cb0e01d8 to your computer and use it in GitHub Desktop.
userspice 4 backup
<?php
/*
UserSpice 4
An Open Source PHP User Management System
by the UserSpice Team at http://UserSpice.com
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, either version 3 of the License, or
(at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Set longer execution time and larger memory limit to deal with large backup sets
*/
ini_set('max_execution_time', 1356);
ini_set('memory_limit','1024M');
require_once 'init.php';
require_once $abs_us_root.$us_url_root.'users/includes/header.php';
require_once $abs_us_root.$us_url_root.'users/includes/navigation.php';
if (!securePage($_SERVER['PHP_SELF'])){die();}
$settingsQ = $db->query("SELECT * FROM settings");
$settings = $settingsQ->first();
$table_view = $db->query("SHOW TABLES");
$tablev = $table_view->results();
$errors = $successes = [];
//:: Admin Backup
$lang = array_merge($lang,array(
"AB_SETSAVED" => "Settings Successfully Saved",
"AB_PATHCREATE" => "Destination path created.",
"AB_PATHERROR" => "Destination path could not be created due to unknown error.",
"AB_PATHEXISTED" => "Destination path already existed. Using the existing folder.",
"AB_BACKUPSUCCESS" => "Backup was successful.",
"AB_BACKUPFAIL" => "Backup failed.",
"AB_DB_FILES_ZIP" => "DB &amp; Files Zipped",
"AB_FILE_RENAMED" => "File renamed to:&nbsp;",
"AB_NOT_RENAME" => "Could not rename backup zip file to contain hash value.",
"AB_ERROR_CREATE" => "Error creating zip file",
"AB_DB_ZIPPED" => "Database Zipped",
"AB_PATHEXIST" => "Backup path already exists or could not be created.",
"AB_T_FILE_ZIP" => "Userspice Files Zipped",
"AB_TABLES_ZIP" => "Tables Zipped",
"AB_BACKUP_DELETE" => "Backup(s) Deleted !",
"AB_PAGENAME" => "System Backup",
"AB_BACKUP_SET" => "Backup Settings",
"AB_BACKUP_DEST" => "Backup Destination",
"AB_BACKUP_DEST_INFO" => "relative to the z_us_root.php file",
"AB_BACKUP_SOURCE" => "Backup Source",
"AB_DB_TM_FILES" => "Database &amp; Userspice Files",
"AB_DB_FILES" => "Database Only",
"AB_TM_FILES" => "Userspice Files Only",
"AB_SINGLE_TBL" => "Single Table",
"AB_SELECT_TBL" => "Select Table",
"AB_DB_TBLS" => "DB Tables",
"AB_SAVE_SETTINGS" => "&nbsp;Save Settings&nbsp;",
"AB_BACKUP_BTN" => "&nbsp;Backup&nbsp;",
"AB_EXIST_BACKUP" => "Existing Backups&nbsp;",
"AB_DATE" => "Date",
"AB_BACKUP_FILE" => "Backup File",
"AB_FILE_SIZE" => "File Size",
"AB_ACTIONS" => "Actions",
"AB_DELETE_B" => "&nbsp;Delete Backup&nbsp;",
"AB_BACKUP_NOT" => "Backup(s) not deleted !",
"WENT_WRONG" => "Something went wrong",
"AB_DB_ALL_FILES" => "Database &amp; ALL Files (Experimental)",
));
if(isset($_GET['sc1'])){
$successes[] = lang('AB_SETSAVED');
}
if(isset($_GET['del'])){
$successes[] = "deleted backup";
}
//Forms posted
if(!empty($_POST)) {
if(!empty($_POST['save'])){
if($settings->backup_dest != $_POST['backup_dest']) {
$backup_dest = Input::get('backup_dest');
$fields=array('backup_dest'=>$backup_dest);
$db->update('settings',1,$fields);
}
if($settings->backup_source != $_POST['backup_source']) {
$backup_source = Input::get('backup_source');
$fields=array('backup_source'=>$backup_source);
$db->update('settings',1,$fields);
}
if($settings->backup_table != $_POST['backup_table']) {
$backup_table = Input::get('backup_table');
$fields=array('backup_table'=>$backup_table);
$db->update('settings',1,$fields);
}
Redirect::to('admin_backup.php?sc1=Settings+saved!');
}
if(!empty($_POST['backup'])){
//Create backup destination folder: $settings->backup_dest
//$backup_dest = $settings->backup_dest;
$backup_dest = "@".$settings->backup_dest;//::from us v4.2.9a
$backupTable = $settings->backup_table;
if($settings->backup_source != "db_table") {
$backupSource = $settings->backup_source;
}
elseif($settings->backup_source == "db_table") {
$backupSource = $settings->backup_source.'_'.$backupTable;
}
$destPath = $abs_us_root.$us_url_root.$backup_dest;
if(!file_exists($destPath)){
if (mkdir($destPath)){
$destPathSuccess = true;
$successes[] = lang('AB_PATHCREATE');
}else{
$destPathSuccess = false;
$errors[] = lang('AB_PATHERROR');
}
}else{
$successes[] = lang('AB_PATHEXISTED');
}
// Generate backup path
$backupDateTimeString = date("Y-m-d\TH-i-s");
$backupPath = $abs_us_root.$us_url_root.$backup_dest.'backup_'.$backupSource.'_'.$backupDateTimeString.'/';
if(!file_exists($backupPath)){
if (mkdir($backupPath)){
$backupPathSuccess = true;
}else{
$backupPathSuccess = false;
}
}
if($backupPathSuccess) {
// Since the backup path is just created with a timestamp,
// no need to check if these subfolders exist or if they are writable
mkdir($backupPath.'files');
mkdir($backupPath.'sql');
}
// Backup All Files & Directories In Root and DB
if($backupPathSuccess && $settings->backup_source == 'everything'){
// Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with .
$backupItems = [];
$backupItems[] = $abs_us_root.$us_url_root;
$backupItems[] = $abs_us_root.$us_url_root.'users';
$backupItems[] = $abs_us_root.$us_url_root.'usersc';
if(backupObjects($backupItems,$backupPath.'files/')){
$successes[] = lang('AB_BACKUPSUCCESS');
}else{
$errors[] = lang('AB_BACKUPFAIL');
}
backupUsTables($backupPath);
$targetZipFile = backupZip($backupPath,true);
if($targetZipFile){
$successes[] = lang('AB_DB_FILES_ZIP');
$backupZipHash = hash_file('sha1', $targetZipFile);
$backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip';
if(rename($targetZipFile,$backupZipHashFilename)){
$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename;
}else{
$errors[] = lang('AB_NOT_RENAME');
}
}else{
$errors[] = lang('AB_ERROR_CREATE');
}
}
// Backup Terminus files & all db tables
if($backupPathSuccess && $settings->backup_source == 'db_us_files'){
// Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with .
$backupItems = [];
$backupItems[] = $abs_us_root.$us_url_root.'users';
$backupItems[] = $abs_us_root.$us_url_root.'usersc';
if(backupObjects($backupItems,$backupPath.'files/')){
$successes[] = lang('AB_BACKUPSUCCESS');
}else{
$errors[] = lang('AB_BACKUPFAIL');
}
backupUsTables($backupPath);
$targetZipFile = backupZip($backupPath,true);
if($targetZipFile){
$successes[] = lang('AB_DB_FILES_ZIP');
$backupZipHash = hash_file('sha1', $targetZipFile);
$backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip';
if(rename($targetZipFile,$backupZipHashFilename)){
$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename;
}else{
$errors[] = lang('AB_NOT_RENAME');
}
}else{
$errors[] = lang('AB_ERROR_CREATE');
}
}
// Backup all db tables only
if($backupPathSuccess && $settings->backup_source == 'db_only'){
backupUsTables($backupPath);
$targetZipFile = backupZip($backupPath,true);
if($targetZipFile){
$successes[] = lang('AB_DB_ZIPPED');
$backupZipHash = hash_file('sha1', $targetZipFile);
$backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip';
if(rename($targetZipFile,$backupZipHashFilename)){
$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename;
}else{
$errors[] = lang('AB_NOT_RENAME');
}
}else{
$errors[] = lang('AB_ERROR_CREATE');
}
}elseif(!$backupPathSuccess){
$errors[] = lang('AB_PATHEXIST');
}else{
// Unknown state? Do nothing.
}
// Backup terminus files only
if($backupPathSuccess && $settings->backup_source == 'us_files'){
// Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with .
$backupItems = [];
$backupItems[] = $abs_us_root.$us_url_root.'users';
$backupItems[] = $abs_us_root.$us_url_root.'usersc';
if(backupObjects($backupItems,$backupPath.'files/')){
$successes[] = lang('AB_BACKUPSUCCESS');
}else{
$errors[] = lang('AB_BACKUPFAIL');
}
$targetZipFile = backupZip($backupPath,true);
if($targetZipFile){
$successes[] = lang('AB_T_FILE_ZIP');
$backupZipHash = hash_file('sha1', $targetZipFile);
$backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip';
if(rename($targetZipFile,$backupZipHashFilename)){
$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename;
}else{
$errors[] = lang('AB_NOT_RENAME');
}
}else{
$errors[] = lang('AB_ERROR_CREATE');
}
}
// Backup single db table only
if($backupPathSuccess && $settings->backup_source == 'db_table'){
backupUsTable($backupPath);
$targetZipFile = backupZip($backupPath,true);
if($targetZipFile){
$successes[] = lang('AB_TABLES_ZIP');
$backupZipHash = hash_file('sha1', $targetZipFile);
$backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip';
if(rename($targetZipFile,$backupZipHashFilename)){
$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename;
}else{
$errors[] = lang('AB_NOT_RENAME');
}
}else{
$errors[] = lang('AB_ERROR_CREATE');
}
}
}
//Delete backup
if(!empty($_POST['deleteFile'])){
$deletions = $_POST['delete'];
$backup_dest = "@".$settings->backup_dest;//::from 4.2.9a
foreach($deletions as $delete) {
if(!unlink($abs_us_root.$us_url_root.$backup_dest.$delete)) {
$errors[] = lang('AB_BACKUP_NOT');
}else{
$successes[] = lang('AB_BACKUP_DELETE');
}
}
}
}
$backup_dest = "@".$settings->backup_dest;//::from 4.2.9a
// Get array of existing backup zip files
$allBackupFiles = glob($abs_us_root.$us_url_root.$backup_dest.'backup*.zip');
$allBackupFilesSize = [];
foreach($allBackupFiles as $backupFile){
$allBackupFilesSize[] = size($backupFile);
}
$pagename = lang('AB_PAGENAME');
?>
<div id="page-wrapper">
<div class="container">
<!-- Page Heading -->
<div class="row">
<!-- Main Center Column -->
<div class="col-xs-12">
<!-- Content Goes Here. Class width can be adjusted -->
<h2><?=$pageName?> </h2>
<?php resultBlock($errors,$successes); ?>
<form class="form-horizontal form-label-left" action="<?=$_SERVER['PHP_SELF']?>" name="backup" method="POST">
<!-- backup_dest Option -->
<div class="form-group">
<label for="backup_dest" class="control-label col-md-3 col-sm-3 col-xs-12" style="margin-top: 10px;">
<?=lang('AB_BACKUP_DEST');?>
</label>
<div class="col-md-5 col-sm-5 col-xs-12" style="margin-top: 10px;">
<input class="form-control" type="text" name="backup_dest" id="backup_dest" placeholder="Backup Destination" value="<?=$settings->backup_dest?>">
<span class="text-danger"><?=lang('AB_BACKUP_DEST_INFO');?></span>
</div>
</div>
<!-- backup_source Option -->
<div class="form-group">
<label for="backup_source" class="control-label col-md-3 col-sm-3 col-xs-12" style="margin-top: 10px;">
<?=lang('AB_BACKUP_SOURCE');?>
</label>
<div class="col-md-5 col-sm-5 col-xs-12" style="margin-top: 10px;">
<select id="backup_source" class="form-control" name="backup_source">
<option value="everything" <?php if($settings->backup_source =='everything') ;?>><?=lang('AB_DB_ALL_FILES');?></option>
<option value="db_us_files" <?php if($settings->backup_source =='db_us_files') echo 'selected="selected"';?>><?=lang('AB_DB_TM_FILES');?></option>
<option value="db_only" <?php if($settings->backup_source =='db_only') echo 'selected="selected"';?>><?=lang('AB_DB_FILES');?></option>
<option value="us_files" <?php if($settings->backup_source =='us_files') echo 'selected="selected"';?>><?=lang('AB_TM_FILES');?></option>
<option value="db_table" <?php if($settings->backup_source =='db_table') echo 'selected="selected"';?>><?=lang('AB_SINGLE_TBL');?></option>
</select>
</div>
</div>
<?php if($settings->backup_source =='db_table') { ?>
<div class="form-group">
<label for="backup_source" class="control-label col-md-3 col-sm-3 col-xs-12" style="margin-top: 10px;">
<?=lang('AB_SELECT_TBL');?>
</label>
<div class="col-md-5 col-sm-5 col-xs-12" style="margin-top: 10px;">
<select id="backup_table" class="form-control" name="backup_table">
<?php foreach($tablev as $v) { ?>
<option value="<?=end($v);?>" <?php if($settings->backup_table == end($v)) echo 'selected="selected"';?>><?=end($v);?></option>
<?php } ?>
</select>
</div>
</div>
<?php } ?>
<div class="control-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12"><?=lang('AB_DB_TBLS');?></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<input id="tags_1" type="text" class="tags form-control" value="tables" data-tagsinput-init="true" style="display: none;">
<div id="tags_1_tagsinput" class="tagsinput" style="width: auto; min-height: 100px; height: 100px;">
<?php foreach($tablev as $v) { ?>
<span class="tag"><?=end($v);?>&nbsp;&nbsp;</span>
<?php } ?>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="ln_solid"></div>
<button class='btn btn-success' type='submit' name="save" value='Save Settings' onclick="window.location='<?=$_SERVER['PHP_SELF']; ?>';"><i class="fa fa-database"></i><?=lang('AB_SAVE_SETTINGS');?></button>
<button class='btn btn-success' type='submit' name="backup" value='Backup' onclick="window.location='<?=$_SERVER['PHP_SELF']; ?>';"><i class="fa fa-database"></i><?=lang('AB_BACKUP_BTN');?></button>
</form>
</div><!--/.col-*-->
</div><!--/.row-->
<!-- Existing Backups -->
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<h2><?=lang('AB_EXIST_BACKUP');?><span class="badge bg-green" style="color: white;"><?=sizeof($allBackupFiles)?></span></h2>
<div class="col-md-12 col-sm-12 col-xs-12">
<form name="delete" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">
<table class='table table-responsive table-striped' cellspacing="0" width="100%" >
<thead>
<tr class="headings">
<th>
<input type="checkbox" class="flat" name="select-all" id="check-all" style="width: 10px!important;"/>
</th><!-- select all boxes -->
<th class="column-title" style="width: 150px;"><?=lang('AB_DATE');?></th>
<th class="column-title" style="width: 600px;"><?=lang('AB_BACKUP_FILE');?></th>
<th class="column-title" style="width: 100px;"><?=lang('AB_FILE_SIZE');?></th>
<th class="column-title text-center" style="width: 10%;"><?=lang('AB_ACTIONS');?></th>
</tr>
</thead>
<tbody>
<?php
$i=0;
foreach($allBackupFiles as $backupFile){
$objectName=explode('/',$backupFile);
$filename=end($objectName);
$fileDate=date("F d Y H:i:s.",filemtime($backupFile));
?>
<tr>
<td class="a-center ">
<input type='checkbox' class="flat" name='delete[<?=$filename?>]' value='<?=$filename?>' style="width: 10px!important;"/>
</td>
<td class=" " style="width: 150px;"><?=$fileDate?></td>
<td class=" " style="width: 600px;"><?=$filename?></td>
<td class=" " style="width: 100px;"><?=$allBackupFilesSize[$i]?></td>
<td class="text-center last" style="width: 10%;">
<a class="label label-success bg-green" href="<?=$us_url_root.$backup_dest.$filename?>"><i class="fa fa-download"></i></a>
</td>
</tr>
<?php $i++;} ?>
</tbody>
</table>
<br><br>
<div class="clearfix"></div>
<div class="ln_solid"></div>
<button class="btn btn-danger" onclick="window.location='<?=$us_url_root?>users/admin_backup.php';" type="submit" name="deleteFile" value="delete"><i class="fa fa-trash"></i><?=lang('AB_DELETE_B');?></button>
</form>
</div>
</div><!--/.col-*-->
</div><!--/.row-->
</div>
</div>
</div>
</div>
<?php require_once $abs_us_root.$us_url_root.'users/includes/page_footer.php';?>
<?php require_once $abs_us_root.$us_url_root.'users/includes/html_footer.php';?>
<?php
/*
UserSpice 4
An Open Source PHP User Management System
by the UserSpice Team at http://UserSpice.com
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, either version 3 of the License, or
(at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>.
*/
//bold("<br><br>custom helpers included");
function csv_to_array($filename='', $delimiter=','){
/**
* Convert a comma separated file into an associated array.
* The first row should contain the array keys.
*
* Example:
*
* @param string $filename Path to the CSV file
* @param string $delimiter The separator used in the file
* @return array
* @link http://gist.github.com/385876
* @author Jay Williams <http://myd3.com/>
* @copyright Copyright (c) 2010, Jay Williams
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
if(!file_exists($filename) || !is_readable($filename))
return FALSE;
$header = NULL;
$data = array();
if (($handle = fopen($filename, 'r')) !== FALSE)
{
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
{
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
fclose($handle);
}
return $data;
//Example
//print_r(csv_to_array('example.csv'));
}
function recurse_copy($src,$dst) {
/*
FROM http://php.net/manual/en/function.copy.php
*/
global $settings;
$dest = '@'.rtrim($settings->backup_dest, '/');
$dir = opendir($src);
@mkdir($dst,0755,true);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..') && ($file != $dest)) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
function zipData($source, $destination) {
/*
* PHP: Recursively Backup Files & Folders to ZIP-File
* (c) 2012-2014: Marvin Menzerath - http://menzerath.eu
* From https://gist.github.com/MarvinMenzerath/4185113
*/
// Make sure the script can handle large folders/files
//ini_set('max_execution_time', 600);
//ini_set('memory_limit','1024M');
// Start the backup!
//zipData('/path/to/folder', '/path/to/backup.zip');
global $successes,$errors;
if (file_exists($source)) {
$zip = new ZipArchive();
if ($zip->open($destination, ZIPARCHIVE::CREATE)) {
$source = realpath($source);
if (is_dir($source)) {
//:: from 4.2.9a
//:: lets exclude files prepended with @
class BackupDirFilter extends RecursiveFilterIterator {
public function accept() {
return '@' !== substr($this->current()->getFilename(), 0, 1);
}
}
//:: from 4.2.9a
$iterator = new RecursiveDirectoryIterator($source);
// skip dot files while iterating
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$filter = new BackupDirFilter($iterator);
//$files = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);
$files = new RecursiveIteratorIterator($filter, RecursiveIteratorIterator::SELF_FIRST);
//$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = realpath($file);
//Following are the original lines, replaced '/' with DIRECTORY_SEPARATOR to support linux and windows
/*
if (is_dir($file)) {
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
} else if (is_file($file)) {
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
*/
if (is_dir($file)) {
$zip->addEmptyDir(str_replace($source . DIRECTORY_SEPARATOR, '', $file . DIRECTORY_SEPARATOR));
} else if (is_file($file)) {
$zip->addFromString(str_replace($source . DIRECTORY_SEPARATOR, '', $file), file_get_contents($file));
}
}
} else if (is_file($source)) {
$zip->addFromString(basename($source), file_get_contents($source));
}
}
return $zip->close();
}
return false;
}
function rrmdir($src) {
/*
From http://php.net/manual/en/function.rmdir.php
*/
if($src==null){
return false;
}
$dir = opendir($src);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
$full = $src . '/' . $file;
if ( is_dir($full) ) {
rrmdir($full);
}
else {
unlink($full);
}
}
}
closedir($dir);
rmdir($src);
return true;
}
function delete_dir($dir)
{
/*
From: http://uk1.php.net/manual/en/function.copy.php#104020
*/
if (is_link($dir)) {
unlink($dir);
} elseif (!file_exists($dir)) {
return;
} elseif (is_dir($dir)) {
foreach (scandir($dir) as $file) {
if ($file != '.' && $file != '..') {
delete_dir("$dir/$file");
}
}
rmdir($dir);
} elseif (is_file($dir)) {
unlink($dir);
} else {
echo "WARNING: Cannot delete $dir (unknown file type)\n";
}
}
function backupObjects($backupItems,$backupPath){
/*
Inputs:
$backupItems (the array of all file and folder objects to be backed up)
$backupPath (the directory to which files will be copied)
*/
global $errors,$successes;
/*
Cycle through items to backup
If it is a file, then use copy()
If it is a directory, then use utility.php:recurse_copy
Else do nothing since unrecognized object
*/
foreach($backupItems as $backupItem){
/*
Build the target file name as $backupPath.end(explode('/',$backupItem))
*/
$pathArray = explode('/',$backupItem);
$backupItemFilename = end($pathArray);
$targetFilename = $backupPath.$backupItemFilename;
if(is_file($backupItem)){
copy($backupItem,$targetFilename);
$successes[] = 'Copied file: '.$backupItem.' to '.$targetFilename;
}elseif(is_dir($backupItem)){
recurse_copy($backupItem,$targetFilename);
$successes[] = 'Copied directory: '.$backupItem.' to '.$targetFilename;
}else{
/*
Do nothing because it isn't a normal file or directory
*/
$errors[] = 'Encountered an object that was not a file or a directory: '.$targetFilename;
return false;
}
}
$successes[] = 'Backup completed successfully.';
return true;
}
function backupZip($backupPath,$delBackupPath=false){
global $errors,$successes;
/*
Add $backupPath to a zipfile named end(explode('/',$backupPath)).'.zip'
*/
$zipCreated = false;
if (extension_loaded('zip')){
/*
$targetZipFile is the $backupPath minus the trailing slash, plus .zip
*/
$targetZipFile = substr($backupPath,0,strlen($backupPath)-1).'.zip';
if(zipData($backupPath, $targetZipFile)){
$successes[] = 'Successfully created '.$targetZipFile.' from '.$backupPath.'';
$zipCreated=true;
}
}else{
$errors[] = 'The "zip" PHP extension is not installed. Cannot create zip file.';
$zipCreated=false;
return false;
}
/*
If $zipCreated=true, then recursively delete the backup directory.
If $zipCreated=false, then leave folder and inform user to download folder if desired.
*/
if($zipCreated && $delBackupPath){
/*
$removePath is the same as $backupPath but without the trailing slash
*/
$removePath = substr($backupPath,0,strlen($backupPath)-1);
rrmdir($removePath);
$successes[] = 'The backup folder '.$removePath.' has been removed. Please download '.$targetZipFile.' directly.';
}else{
$successes[] = 'The backup folder '.$removePath.' has NOT been removed. Please downloaded folder directly.';
}
return $targetZipFile;
}
function backupUsTables($backupPath) {
global $errors, $successes;
try {
$dbHost = Config::get('mysql/host');
$dbDatabase = Config::get('mysql/db');
$dbUsername = Config::get('mysql/username');
$dbPassword = Config::get('mysql/password');
$usDump = Shuttle_Dumper::create(array(
'host' => $dbHost,
'username' => $dbUsername,
'password' => $dbPassword,
'db_name' => $dbDatabase
));
$usDumpFilename = $backupPath.'sql/'.$dbDatabase.'.sql';
$usDump->dump($usDumpFilename);
$successes[]='Tables have been backed up to '.$usDumpFilename.'.';
} catch(Shuttle_Exception $e) {
echo "<span class=\"alert alert-danger col-md-12\">" . $e->getMessage() . "</span>";
}
}
function backupUsTable($backupPath) {
global $errors, $successes, $backupPath;
$db = DB::getInstance();
$settingsQ = $db->query("SELECT * FROM settings");
$settings = $settingsQ->first();
try {
$dbHost = Config::get('mysql/host');
$dbDatabase = Config::get('mysql/db');
$dbUsername = Config::get('mysql/username');
$dbPassword = Config::get('mysql/password');
$sel_table = $settings->backup_table;
$usDump = Shuttle_Dumper::create(array(
'host' => $dbHost,
'username' => $dbUsername,
'password' => $dbPassword,
'db_name' => $dbDatabase,
'include_tables' => array($sel_table),
));
$usDumpFilename = $backupPath.'sql/'.$sel_table.'_'.$dbDatabase.'.sql';
$usDump->dump($usDumpFilename);
$successes[]='Tables have been backed up to '.$usDumpFilename.'.';
} catch(Shuttle_Exception $e) {
echo "<span class=\"alert alert-danger col-md-12\">" . $e->getMessage() . "</span>";
}
}
function extractZip($restoreFile,$restoreDest){
global $errors,$successes;
/*
From: http://php.net/manual/en/ziparchive.extractto.php
*/
$zip = new ZipArchive;
if ($zip->open($restoreFile) === TRUE) {
$zip->extractTo($restoreDest);
$zip->close();
$successes[] = 'Extracted file';
return true;
} else {
$errors[] = 'Failed to open zip file';
return false;
}
}
function importSqlFile($sqlFile){
global $errors, $successes;
/*
From: http://stackoverflow.com/questions/19751354/how-to-import-sql-file-in-mysql-database-using-php
*/
$db = DB::getInstance();
// Temporary variable, used to store current query
$templine = '';
// Read in entire file
$lines = file($sqlFile);
// Loop through each line
foreach ($lines as $line)
{
// Skip it if it's a comment
if (substr($line, 0, 2) == '--' || $line == '') continue;
// Add this line to the current segment
$templine .= $line;
// If it has a semicolon at the end, it's the end of the query
if (substr(trim($line), -1, 1) == ';')
{
// Perform the query
$queryResult = $db->query($templine);
// Reset temp variable to empty
if($queryResult){
//$successes[]='Query successful: '.$templine;
}else{
$errors[] = 'Query NOT successful: '.$templine;
return false;
}
$templine = '';
}
}
return true;
}
?>
//:: Add this to helpers.php DO NOT replace
require_once("backup_util.php");
// Readeable file size
function size($path) {
$bytes = sprintf('%u', filesize($path));
if ($bytes > 0) {
$unit = intval(log($bytes, 1024));
$units = array('B', 'KB', 'MB', 'GB');
if (array_key_exists($unit, $units) === true) {
return sprintf('%d %s', $bytes / pow(1024, $unit), $units[$unit]);
}
}
return $bytes;
}
//:: Add this line to init.php BELOW require_once $abs_us_root.$us_url_root.'users/classes/phpmailer/PHPMailerAutoload.php';
require_once $abs_us_root.$us_url_root.'users/classes/Shuttle_Dumper.php';
//:: add this to language.php
//:: Admin Backup
$lang = array_merge($lang,array(
"AB_SETSAVED" => "Settings Successfully Saved",
"AB_PATHCREATE" => "Destination path created.",
"AB_PATHERROR" => "Destination path could not be created due to unknown error.",
"AB_PATHEXISTED" => "Destination path already existed. Using the existing folder.",
"AB_BACKUPSUCCESS" => "Backup was successful.",
"AB_BACKUPFAIL" => "Backup failed.",
"AB_DB_FILES_ZIP" => "DB &amp; Files Zipped",
"AB_FILE_RENAMED" => "File renamed to:&nbsp;",
"AB_NOT_RENAME" => "Could not rename backup zip file to contain hash value.",
"AB_ERROR_CREATE" => "Error creating zip file",
"AB_DB_ZIPPED" => "Database Zipped",
"AB_PATHEXIST" => "Backup path already exists or could not be created.",
"AB_T_FILE_ZIP" => "Userspice Files Zipped",
"AB_TABLES_ZIP" => "Tables Zipped",
"AB_BACKUP_DELETE" => "Backup(s) Deleted !",
"AB_PAGENAME" => "System Backup",
"AB_BACKUP_SET" => "Backup Settings",
"AB_BACKUP_DEST" => "Backup Destination",
"AB_BACKUP_DEST_INFO" => "relative to the z_us_root.php file",
"AB_BACKUP_SOURCE" => "Backup Source",
"AB_DB_TM_FILES" => "Database &amp; Userspice Files",
"AB_DB_FILES" => "Database Only",
"AB_TM_FILES" => "Userspice Files Only",
"AB_SINGLE_TBL" => "Single Table",
"AB_SELECT_TBL" => "Select Table",
"AB_DB_TBLS" => "DB Tables",
"AB_SAVE_SETTINGS" => "&nbsp;Save Settings&nbsp;",
"AB_BACKUP_BTN" => "&nbsp;Backup&nbsp;",
"AB_EXIST_BACKUP" => "Existing Backups&nbsp;",
"AB_DATE" => "Date",
"AB_BACKUP_FILE" => "Backup File",
"AB_FILE_SIZE" => "File Size",
"AB_ACTIONS" => "Actions",
"AB_DELETE_B" => "&nbsp;Delete Backup&nbsp;",
"AB_BACKUP_NOT" => "Backup(s) not deleted !",
"WENT_WRONG" => "Something went wrong",
"AB_DB_ALL_FILES" => "Database &amp; ALL Files (Experimental)",
));
<?php
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
//::
//:: This will patch your database for backups
//::
//:: WARNING ! BACKUP YOUR DATABASE MANUALY BEFORE RUNNING THIS PATCH
//::
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
require_once 'users/init.php';
require_once $abs_us_root.$us_url_root.'users/includes/header.php';
require_once $abs_us_root.$us_url_root.'users/includes/navigation.php';
//:: Add columns to "settings" table
$settingsQ = $db->query("ALTER TABLE settings
ADD COLUMN backup_dest varchar(255) NOT NULL,
ADD COLUMN backup_source varchar(255) NOT NULL,
ADD COLUMN backup_table varchar(255) NOT NULL");
$fields0 = array(
'backup_dest' => '',
'backup_source' => '',
'backup_table' => '',
);
$setQ = $db->insert('settings',$fields0);
//:: Add pages to "pages" table
$fields1 = array(
'id' => '44',
'page' => 'users/admin_backup.php',
'private' => 1,
);
$adminset = $db->insert('pages',$fields1);
//:: Add permissions to "permission_page_matches" table
$tomFields1 = array(
'id' => 31,
'permission_id' => 2,
'page_id' => 44,
);
$permUpdate1 = $db->insert('permission_page_matches',$tomFields1);
bold ("<br><br>You're good to go. Delete PATCH FILE and bask in the glory that is UserSpice");
?>
<?php
//bold("<br><br>Shuttle Dumper included");
/**
* Abstract dump file: provides common interface for writing
* data to dump files.
*/
abstract class Shuttle_Dump_File {
/**
* File Handle
*/
protected $fh;
/**
* Location of the dump file on the disk
*/
protected $file_location;
abstract function write($string);
abstract function end();
static function create($filename) {
if (self::is_gzip($filename)) {
return new Shuttle_Dump_File_Gzip($filename);
}
return new Shuttle_Dump_File_Plaintext($filename);
}
function __construct($file) {
$this->file_location = $file;
$this->fh = $this->open();
if (!$this->fh) {
throw new Shuttle_Exception("Couldn't create gz file");
}
}
public static function is_gzip($filename) {
return preg_match('~gz$~i', $filename);
}
}
/**
* Plain text implementation. Uses standard file functions in PHP.
*/
class Shuttle_Dump_File_Plaintext extends Shuttle_Dump_File {
function open() {
return fopen($this->file_location, 'w');
}
function write($string) {
return fwrite($this->fh, $string);
}
function end() {
return fclose($this->fh);
}
}
/**
* Gzip implementation. Uses gz* functions.
*/
class Shuttle_Dump_File_Gzip extends Shuttle_Dump_File {
function open() {
return gzopen($this->file_location, 'wb9');
}
function write($string) {
return gzwrite($this->fh, $string);
}
function end() {
return gzclose($this->fh);
}
}
/**
* MySQL insert statement builder.
*/
class Shuttle_Insert_Statement {
private $rows = array();
private $length = 0;
private $table;
function __construct($table) {
$this->table = $table;
}
function reset() {
$this->rows = array();
$this->length = 0;
}
function add_row($row) {
$row = '(' . implode(",", $row) . ')';
$this->rows[] = $row;
$this->length += strlen($row);
}
function get_sql() {
if (empty($this->rows)) {
return false;
}
return 'INSERT INTO `' . $this->table . '` VALUES ' .
implode(",\n", $this->rows) . '; ';
}
function get_length() {
return $this->length;
}
}
/**
* Main facade
*/
abstract class Shuttle_Dumper {
/**
* Maximum length of single insert statement
*/
const INSERT_THRESHOLD = 838860;
/**
* @var Shuttle_DBConn
*/
public $db;
/**
* @var Shuttle_Dump_File
*/
public $dump_file;
/**
* End of line style used in the dump
*/
public $eol = "\r\n";
/**
* Specificed tables to include
*/
public $include_tables;
/**
* Specified tables to exclude
*/
public $exclude_tables = array();
/**
* Factory method for dumper on current hosts's configuration.
*/
static function create($db_options) {
$db = Shuttle_DBConn::create($db_options);
$db->connect();
if (self::has_shell_access()
&& self::is_shell_command_available('mysqldump')
&& self::is_shell_command_available('gzip')
) {
$dumper = new Shuttle_Dumper_ShellCommand($db);
} else {
$dumper = new Shuttle_Dumper_Native($db);
}
if (isset($db_options['include_tables'])) {
$dumper->include_tables = $db_options['include_tables'];
}
if (isset($db_options['exclude_tables'])) {
$dumper->exclude_tables = $db_options['exclude_tables'];
}
return $dumper;
}
function __construct(Shuttle_DBConn $db) {
$this->db = $db;
}
public static function has_shell_access() {
if (!is_callable('shell_exec')) {
return false;
}
$disabled_functions = ini_get('disable_functions');
return stripos($disabled_functions, 'shell_exec') === false;
}
public static function is_shell_command_available($command) {
if (preg_match('~win~i', PHP_OS)) {
/*
On Windows, the `where` command checks for availabilty in PATH. According
to the manual(`where /?`), there is quiet mode:
....
/Q Returns only the exit code, without displaying the list
of matched files. (Quiet mode)
....
*/
$output = array();
exec('where /Q ' . $command, $output, $return_val);
if (intval($return_val) === 1) {
return false;
} else {
return true;
}
} else {
$last_line = exec('which ' . $command);
$last_line = trim($last_line);
// Whenever there is at least one line in the output,
// it should be the path to the executable
if (empty($last_line)) {
return false;
} else {
return true;
}
}
}
/**
* Create an export file from the tables with that prefix.
* @param string $export_file_location the file to put the dump to.
* Note that whenever the file has .gz extension the dump will be comporessed with gzip
* @param string $table_prefix Allow to export only tables with particular prefix
* @return void
*/
abstract public function dump($export_file_location, $table_prefix='');
protected function get_tables($table_prefix) {
if (!empty($this->include_tables)) {
return $this->include_tables;
}
// $tables will only include the tables and not views.
// TODO - Handle views also, edits to be made in function 'get_create_table_sql' line 336
$tables = $this->db->fetch_numeric('
SHOW FULL TABLES WHERE Table_Type = "BASE TABLE" AND Tables_in_'.$this->db->name.' LIKE "' . $this->db->escape_like($table_prefix) . '%"
');
$tables_list = array();
foreach ($tables as $table_row) {
$table_name = $table_row[0];
if (!in_array($table_name, $this->exclude_tables)) {
$tables_list[] = $table_name;
}
}
return $tables_list;
}
}
class Shuttle_Dumper_ShellCommand extends Shuttle_Dumper {
function dump($export_file_location, $table_prefix='') {
$command = 'mysqldump -h ' . escapeshellarg($this->db->host) .
' -u ' . escapeshellarg($this->db->username) .
' --password=' . escapeshellarg($this->db->password) .
' ' . escapeshellarg($this->db->name);
$include_all_tables = empty($table_prefix) &&
empty($this->include_tables) &&
empty($this->exclude_tables);
if (!$include_all_tables) {
$tables = $this->get_tables($table_prefix);
$command .= ' ' . implode(' ', array_map('escapeshellarg', $tables));
}
$error_file = tempnam(sys_get_temp_dir(), 'err');
$command .= ' 2> ' . escapeshellarg($error_file);
if (Shuttle_Dump_File::is_gzip($export_file_location)) {
$command .= ' | gzip';
}
$command .= ' > ' . escapeshellarg($export_file_location);
exec($command, $output, $return_val);
if ($return_val !== 0) {
$error_text = file_get_contents($error_file);
unlink($error_file);
throw new Shuttle_Exception('Couldn\'t export database: ' . $error_text);
}
unlink($error_file);
}
}
class Shuttle_Dumper_Native extends Shuttle_Dumper {
public function dump($export_file_location, $table_prefix='') {
$eol = $this->eol;
$this->dump_file = Shuttle_Dump_File::create($export_file_location);
$this->dump_file->write("-- Generation time: " . date('r') . $eol);
$this->dump_file->write("-- Host: " . $this->db->host . $eol);
$this->dump_file->write("-- DB name: " . $this->db->name . $eol);
$this->dump_file->write("/*!40030 SET NAMES UTF8 */;$eol");
$this->dump_file->write("/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;$eol");
$this->dump_file->write("/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;$eol");
$this->dump_file->write("/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;$eol");
$this->dump_file->write("/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;$eol");
$this->dump_file->write("/*!40103 SET TIME_ZONE='+00:00' */;$eol");
$this->dump_file->write("/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;$eol");
$this->dump_file->write("/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;$eol");
$this->dump_file->write("/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;$eol");
$this->dump_file->write("/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;$eol$eol");
$tables = $this->get_tables($table_prefix);
foreach ($tables as $table) {
$this->dump_table($table);
}
$this->dump_file->write("$eol$eol");
$this->dump_file->write("/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;$eol");
$this->dump_file->write("/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;$eol");
$this->dump_file->write("/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;$eol");
$this->dump_file->write("/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;$eol");
$this->dump_file->write("/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;$eol");
$this->dump_file->write("/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;$eol");
$this->dump_file->write("/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;$eol$eol");
unset($this->dump_file);
}
protected function dump_table($table) {
$eol = $this->eol;
$this->dump_file->write("DROP TABLE IF EXISTS `$table`;$eol");
$create_table_sql = $this->get_create_table_sql($table);
$this->dump_file->write($create_table_sql . $eol . $eol);
$data = $this->db->query("SELECT * FROM `$table`");
$insert = new Shuttle_Insert_Statement($table);
while ($row = $this->db->fetch_row($data)) {
$row_values = array();
foreach ($row as $value) {
$row_values[] = $this->db->escape($value);
}
$insert->add_row( $row_values );
if ($insert->get_length() > self::INSERT_THRESHOLD) {
// The insert got too big: write the SQL and create
// new insert statement
$this->dump_file->write($insert->get_sql() . $eol);
$insert->reset();
}
}
$sql = $insert->get_sql();
if ($sql) {
$this->dump_file->write($insert->get_sql() . $eol);
}
$this->dump_file->write($eol . $eol);
}
public function get_create_table_sql($table) {
$create_table_sql = $this->db->fetch('SHOW CREATE TABLE `' . $table . '`');
return $create_table_sql[0]['Create Table'] . ';';
}
}
class Shuttle_DBConn {
public $host;
public $username;
public $password;
public $name;
protected $connection;
function __construct($options) {
$this->host = $options['host'];
if (empty($this->host)) {
$this->host = '127.0.0.1';
}
$this->username = $options['username'];
$this->password = $options['password'];
$this->name = $options['db_name'];
}
static function create($options) {
if (class_exists('mysqli')) {
$class_name = "Shuttle_DBConn_Mysqli";
} else {
$class_name = "Shuttle_DBConn_Mysql";
}
return new $class_name($options);
}
}
class Shuttle_DBConn_Mysql extends Shuttle_DBConn {
function connect() {
$this->connection = @mysql_connect($this->host, $this->username, $this->password);
if (!$this->connection) {
throw new Shuttle_Exception("Couldn't connect to the database: " . mysql_error());
}
$select_db_res = mysql_select_db($this->name, $this->connection);
if (!$select_db_res) {
throw new Shuttle_Exception("Couldn't select database: " . mysql_error($this->connection));
}
return true;
}
function query($q) {
if (!$this->connection) {
$this->connect();
}
$res = mysql_query($q);
if (!$res) {
throw new Shuttle_Exception("SQL error: " . mysql_error($this->connection));
}
return $res;
}
function fetch_numeric($query) {
return $this->fetch($query, MYSQL_NUM);
}
function fetch($query, $result_type=MYSQL_ASSOC) {
$result = $this->query($query, $this->connection);
$return = array();
while ( $row = mysql_fetch_array($result, $result_type) ) {
$return[] = $row;
}
return $return;
}
function escape($value) {
if (is_null($value)) {
return "NULL";
}
return "'" . mysql_real_escape_string($value) . "'";
}
function escape_like($search) {
return str_replace(array('_', '%'), array('\_', '\%'), $search);
}
function get_var($sql) {
$result = $this->query($sql);
$row = mysql_fetch_array($result);
return $row[0];
}
function fetch_row($data) {
return mysql_fetch_assoc($data);
}
}
class Shuttle_DBConn_Mysqli extends Shuttle_DBConn {
function connect() {
$this->connection = @new MySQLi($this->host, $this->username, $this->password, $this->name);
if ($this->connection->connect_error) {
throw new Shuttle_Exception("Couldn't connect to the database: " . $this->connection->connect_error);
}
return true;
}
function query($q) {
if (!$this->connection) {
$this->connect();
}
$res = $this->connection->query($q);
if (!$res) {
throw new Shuttle_Exception("SQL error: " . $this->connection->error);
}
return $res;
}
function fetch_numeric($query) {
return $this->fetch($query, MYSQLI_NUM);
}
function fetch($query, $result_type=MYSQLI_ASSOC) {
$result = $this->query($query, $this->connection);
$return = array();
while ( $row = $result->fetch_array($result_type) ) {
$return[] = $row;
}
return $return;
}
function escape($value) {
if (is_null($value)) {
return "NULL";
}
return "'" . $this->connection->real_escape_string($value) . "'";
}
function escape_like($search) {
return str_replace(array('_', '%'), array('\_', '\%'), $search);
}
function get_var($sql) {
$result = $this->query($sql);
$row = $result->fetch_array($result, MYSQLI_NUM);
return $row[0];
}
function fetch_row($data) {
return $data->fetch_array(MYSQLI_ASSOC);
}
}
class Shuttle_Exception extends Exception {};
@Firestorm-Graphics
Copy link
Author

Shuttle_Dumper.php goes into users/classes/ folder
backup_util.php goes into users/helpers/ folder

patch.php can be placed anywhere within userspice, just navigate to it in the browser and it will patch your db, delete it afterwords.
read commenting at top of each file for instruction wear it should be placed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment