diff --git a/customer_extras.php b/customer_extras.php index 06a27a09..96907cb3 100644 --- a/customer_extras.php +++ b/customer_extras.php @@ -16,7 +16,6 @@ * @package Panel * */ - define('AREA', 'customer'); require './lib/init.php'; @@ -38,9 +37,10 @@ if ($page == 'overview') { ); $paging = new paging($userinfo, TABLE_PANEL_HTPASSWDS, $fields); $result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTPASSWDS . "` - WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit() - ); - Database::pexecute($result_stmt, array("customerid" => $userinfo['customerid'])); + WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit()); + Database::pexecute($result_stmt, array( + "customerid" => $userinfo['customerid'] + )); $paging->setEntries(Database::num_rows()); $sortcode = $paging->getHtmlSortCode($lng); $arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s); @@ -58,38 +58,49 @@ if ($page == 'overview') { $row['path'] = makeCorrectDir($row['path']); $row = htmlentities_array($row); eval("\$htpasswds.=\"" . getTemplate("extras/htpasswds_htpasswd") . "\";"); - $count++; + $count ++; } - $i++; + $i ++; } eval("echo \"" . getTemplate("extras/htpasswds") . "\";"); } elseif ($action == 'delete' && $id != 0) { $result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTPASSWDS . "` WHERE `customerid`= :customerid - AND `id`= :id" - ); - Database::pexecute($result_stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + AND `id`= :id"); + Database::pexecute($result_stmt, array( + "customerid" => $userinfo['customerid'], + "id" => $id + )); $result = $result_stmt->fetch(PDO::FETCH_ASSOC); if (isset($result['username']) && $result['username'] != '') { if (isset($_POST['send']) && $_POST['send'] == 'send') { $stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_HTPASSWDS . "` WHERE `customerid`= :customerid - AND `id`= :id" - ); - Database::pexecute($stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + AND `id`= :id"); + Database::pexecute($stmt, array( + "customerid" => $userinfo['customerid'], + "id" => $id + )); $log->logAction(USR_ACTION, LOG_INFO, "deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'"); inserttask('1'); - redirectTo($filename, array('page' => $page, 's' => $s)); + redirectTo($filename, array( + 'page' => $page, + 's' => $s + )); } else { if (strpos($result['path'], $userinfo['documentroot']) === 0) { - $result['path'] = str_replace($userinfo['documentroot'], "/", $result['path']); + $result['path'] = str_replace($userinfo['documentroot'], "/", $result['path']); } - ask_yesno('extras_reallydelete', $filename, array('id' => $id, 'page' => $page, 'action' => $action), $result['username'] . ' (' . $result['path'] . ')'); + ask_yesno('extras_reallydelete', $filename, array( + 'id' => $id, + 'page' => $page, + 'action' => $action + ), $result['username'] . ' (' . $result['path'] . ')'); } } } elseif ($action == 'add') { @@ -104,8 +115,7 @@ if ($page == 'overview') { $username_path_check_stmt = Database::prepare("SELECT `id`, `username`, `path` FROM `" . TABLE_PANEL_HTPASSWDS . "` WHERE `username`= :username AND `path`= :path - AND `customerid`= :customerid" - ); + AND `customerid`= :customerid"); $params = array( "username" => $username, "path" => $path, @@ -121,16 +131,22 @@ if ($page == 'overview') { $password = crypt($_POST['directory_password']); } - if (!$_POST['path']) { + if (! $_POST['path']) { standard_error('invalidpath'); } if ($username == '') { - standard_error(array('stringisempty', 'myloginname')); + standard_error(array( + 'stringisempty', + 'myloginname' + )); } elseif ($username_path_check['username'] == $username && $username_path_check['path'] == $path) { standard_error('userpathcombinationdupe'); } elseif ($_POST['directory_password'] == '') { - standard_error(array('stringisempty', 'mypassword')); + standard_error(array( + 'stringisempty', + 'mypassword' + )); } elseif ($path == '') { standard_error('patherror'); } elseif ($_POST['directory_password'] == $username) { @@ -141,8 +157,7 @@ if ($page == 'overview') { `username` = :username, `password` = :password, `path` = :path, - `authname` = :authname" - ); + `authname` = :authname"); $params = array( "customerid" => $userinfo['customerid'], "username" => $username, @@ -153,12 +168,15 @@ if ($page == 'overview') { Database::pexecute($stmt, $params); $log->logAction(USR_ACTION, LOG_INFO, "added htpasswd for '" . $username . " (" . $path . ")'"); inserttask('1'); - redirectTo($filename, array('page' => $page, 's' => $s)); + redirectTo($filename, array( + 'page' => $page, + 's' => $s + )); } } else { $pathSelect = makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']); - $htpasswd_add_data = include_once dirname(__FILE__).'/lib/formfields/customer/extras/formfield.htpasswd_add.php'; + $htpasswd_add_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.htpasswd_add.php'; $htpasswd_add_form = htmlform::genHTMLForm($htpasswd_add_data); $title = $htpasswd_add_data['htpasswd_add']['title']; @@ -169,9 +187,11 @@ if ($page == 'overview') { } elseif ($action == 'edit' && $id != 0) { $result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTPASSWDS . "` WHERE `customerid`= :customerid - AND `id`= :id" - ); - Database::pexecute($result_stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + AND `id`= :id"); + Database::pexecute($result_stmt, array( + "customerid" => $userinfo['customerid'], + "id" => $id + )); $result = $result_stmt->fetch(PDO::FETCH_ASSOC); if (isset($result['username']) && $result['username'] != '') { @@ -208,19 +228,21 @@ if ($page == 'overview') { } if ($pwd_sql != '' || $auth_sql != '') { - if ($pwd_sql !='' && $auth_sql != '') { - $pwd_sql.= ', '; + if ($pwd_sql != '' && $auth_sql != '') { + $pwd_sql .= ', '; } $stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "` - SET ".$pwd_sql.$auth_sql." + SET " . $pwd_sql . $auth_sql . " WHERE `customerid`= :customerid - AND `id`= :id" - ); + AND `id`= :id"); Database::pexecute($stmt, $params); $log->logAction(USR_ACTION, LOG_INFO, "edited htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'"); inserttask('1'); - redirectTo($filename, array('page' => $page, 's' => $s)); + redirectTo($filename, array( + 'page' => $page, + 's' => $s + )); } } else { if (strpos($result['path'], $userinfo['documentroot']) === 0) { @@ -229,7 +251,7 @@ if ($page == 'overview') { $result = htmlentities_array($result); - $htpasswd_edit_data = include_once dirname(__FILE__).'/lib/formfields/customer/extras/formfield.htpasswd_edit.php'; + $htpasswd_edit_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.htpasswd_edit.php'; $htpasswd_edit_form = htmlform::genHTMLForm($htpasswd_edit_data); $title = $htpasswd_edit_data['htpasswd_edit']['title']; @@ -252,9 +274,10 @@ if ($page == 'overview') { ); $paging = new paging($userinfo, TABLE_PANEL_HTACCESS, $fields); $result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTACCESS . "` - WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit() - ); - Database::pexecute($result_stmt, array("customerid" => $userinfo['customerid'])); + WHERE `customerid`= :customerid " . $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit()); + Database::pexecute($result_stmt, array( + "customerid" => $userinfo['customerid'] + )); $paging->setEntries(Database::num_rows()); $sortcode = $paging->getHtmlSortCode($lng); $arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s); @@ -278,49 +301,60 @@ if ($page == 'overview') { $row['options_cgi'] = str_replace('0', $lng['panel']['no'], $row['options_cgi']); $row = htmlentities_array($row); eval("\$htaccess.=\"" . getTemplate("extras/htaccess_htaccess") . "\";"); - $count++; + $count ++; } - $i++; + $i ++; } eval("echo \"" . getTemplate("extras/htaccess") . "\";"); } elseif ($action == 'delete' && $id != 0) { $result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTACCESS . "` WHERE `customerid` = :customerid - AND `id` = :id" - ); - Database::pexecute($result_stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + AND `id` = :id"); + Database::pexecute($result_stmt, array( + "customerid" => $userinfo['customerid'], + "id" => $id + )); $result = $result_stmt->fetch(PDO::FETCH_ASSOC); if (isset($result['customerid']) && $result['customerid'] != '' && $result['customerid'] == $userinfo['customerid']) { if (isset($_POST['send']) && $_POST['send'] == 'send') { // do we have to remove the symlink and folder in suexecpath? - if ((int)Settings::Get('perl.suexecworkaround') == 1) { + if ((int) Settings::Get('perl.suexecworkaround') == 1) { $loginname = getCustomerDetail($result['customerid'], 'loginname'); - $suexecpath = makeCorrectDir(Settings::Get('perl.suexecpath').'/'.$loginname.'/'.md5($result['path']).'/'); - $perlsymlink = makeCorrectFile($result['path'].'/cgi-bin'); + $suexecpath = makeCorrectDir(Settings::Get('perl.suexecpath') . '/' . $loginname . '/' . md5($result['path']) . '/'); + $perlsymlink = makeCorrectFile($result['path'] . '/cgi-bin'); // remove symlink if (file_exists($perlsymlink)) { - safe_exec('rm -f '.escapeshellarg($perlsymlink)); + safe_exec('rm -f ' . escapeshellarg($perlsymlink)); $log->logAction(USR_ACTION, LOG_DEBUG, "deleted suexecworkaround symlink '" . $perlsymlink . "'"); } // remove folder in suexec-path if (file_exists($suexecpath)) { - safe_exec('rm -rf '.escapeshellarg($suexecpath)); + safe_exec('rm -rf ' . escapeshellarg($suexecpath)); $log->logAction(USR_ACTION, LOG_DEBUG, "deleted suexecworkaround path '" . $suexecpath . "'"); } } $stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_HTACCESS . "` WHERE `customerid`= :customerid - AND `id`= :id" - ); - Database::pexecute($stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + AND `id`= :id"); + Database::pexecute($stmt, array( + "customerid" => $userinfo['customerid'], + "id" => $id + )); $log->logAction(USR_ACTION, LOG_INFO, "deleted htaccess for '" . str_replace($userinfo['documentroot'], '/', $result['path']) . "'"); inserttask('1'); - redirectTo($filename, array('page' => $page, 's' => $s)); + redirectTo($filename, array( + 'page' => $page, + 's' => $s + )); } else { - ask_yesno('extras_reallydelete_pathoptions', $filename, array('id' => $id, 'page' => $page, 'action' => $action), str_replace($userinfo['documentroot'], '/', $result['path'])); + ask_yesno('extras_reallydelete_pathoptions', $filename, array( + 'id' => $id, + 'page' => $page, + 'action' => $action + ), str_replace($userinfo['documentroot'], '/', $result['path'])); } } } elseif ($action == 'add') { @@ -330,16 +364,18 @@ if ($page == 'overview') { $path = makeCorrectDir($userinfo['documentroot'] . '/' . $path); $path_dupe_check_stmt = Database::prepare("SELECT `id`, `path` FROM `" . TABLE_PANEL_HTACCESS . "` WHERE `path`= :path - AND `customerid`= :customerid" - ); - Database::pexecute($path_dupe_check_stmt, array("path" => $path, "customerid" => $userinfo['customerid'])); + AND `customerid`= :customerid"); + Database::pexecute($path_dupe_check_stmt, array( + "path" => $path, + "customerid" => $userinfo['customerid'] + )); $path_dupe_check = $path_dupe_check_stmt->fetch(PDO::FETCH_ASSOC); - if (!$_POST['path']) { + if (! $_POST['path']) { standard_error('invalidpath'); } - if (isset($_POST['options_cgi']) && (int)$_POST['options_cgi'] != 0) { + if (isset($_POST['options_cgi']) && (int) $_POST['options_cgi'] != 0) { $options_cgi = '1'; } else { $options_cgi = '0'; @@ -372,8 +408,7 @@ if ($page == 'overview') { `error404path` = :error404path, `error403path` = :error403path, `error500path` = :error500path, - `options_cgi` = :options_cgi' - ); + `options_cgi` = :options_cgi'); $params = array( "customerid" => $userinfo['customerid'], "path" => $path, @@ -387,13 +422,16 @@ if ($page == 'overview') { $log->logAction(USR_ACTION, LOG_INFO, "added htaccess for '" . $path . "'"); inserttask('1'); - redirectTo($filename, array('page' => $page, 's' => $s)); + redirectTo($filename, array( + 'page' => $page, + 's' => $s + )); } } else { $pathSelect = makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']); $cperlenabled = customerHasPerlEnabled($userinfo['customerid']); - $htaccess_add_data = include_once dirname(__FILE__).'/lib/formfields/customer/extras/formfield.htaccess_add.php'; + $htaccess_add_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.htaccess_add.php'; $htaccess_add_form = htmlform::genHTMLForm($htaccess_add_data); $title = $htaccess_add_data['htaccess_add']['title']; @@ -404,9 +442,11 @@ if ($page == 'overview') { } elseif (($action == 'edit') && ($id != 0)) { $result_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_HTACCESS . "` WHERE `customerid` = :customerid - AND `id` = :id" - ); - Database::pexecute($result_stmt, array("customerid" => $userinfo['customerid'], "id" => $id)); + AND `id` = :id"); + Database::pexecute($result_stmt, array( + "customerid" => $userinfo['customerid'], + "id" => $id + )); $result = $result_stmt->fetch(PDO::FETCH_ASSOC); if ((isset($result['customerid'])) && ($result['customerid'] != '') && ($result['customerid'] == $userinfo['customerid'])) { @@ -426,12 +466,7 @@ if ($page == 'overview') { $error403path = correctErrorDocument($_POST['error403path']); $error500path = correctErrorDocument($_POST['error500path']); - if (($option_indexes != $result['options_indexes']) - || ($error404path != $result['error404path']) - || ($error403path != $result['error403path']) - || ($error500path != $result['error500path']) - || ($options_cgi != $result['options_cgi']) - ) { + if (($option_indexes != $result['options_indexes']) || ($error404path != $result['error404path']) || ($error403path != $result['error403path']) || ($error500path != $result['error500path']) || ($options_cgi != $result['options_cgi'])) { inserttask('1'); $stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTACCESS . "` SET `options_indexes` = :options_indexes, @@ -440,8 +475,7 @@ if ($page == 'overview') { `error500path` = :error500path, `options_cgi` = :options_cgi WHERE `customerid` = :customerid - AND `id` = :id" - ); + AND `id` = :id"); $params = array( "customerid" => $userinfo['customerid'], "options_indexes" => $_POST['options_indexes'] == '1' ? '1' : '0', @@ -455,7 +489,10 @@ if ($page == 'overview') { $log->logAction(USR_ACTION, LOG_INFO, "edited htaccess for '" . str_replace($userinfo['documentroot'], '/', $result['path']) . "'"); } - redirectTo($filename, array('page' => $page, 's' => $s)); + redirectTo($filename, array( + 'page' => $page, + 's' => $s + )); } else { if (strpos($result['path'], $userinfo['documentroot']) === 0) { $result['path'] = str_replace($userinfo['documentroot'], "/", $result['path']); @@ -466,12 +503,12 @@ if ($page == 'overview') { $result['error500path'] = $result['error500path']; $cperlenabled = customerHasPerlEnabled($userinfo['customerid']); /* - $options_indexes = makeyesno('options_indexes', '1', '0', $result['options_indexes']); - $options_cgi = makeyesno('options_cgi', '1', '0', $result['options_cgi']); - */ + * $options_indexes = makeyesno('options_indexes', '1', '0', $result['options_indexes']); + * $options_cgi = makeyesno('options_cgi', '1', '0', $result['options_cgi']); + */ $result = htmlentities_array($result); - $htaccess_edit_data = include_once dirname(__FILE__).'/lib/formfields/customer/extras/formfield.htaccess_edit.php'; + $htaccess_edit_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.htaccess_edit.php'; $htaccess_edit_form = htmlform::genHTMLForm($htaccess_edit_data); $title = $htaccess_edit_data['htaccess_edit']['title']; @@ -481,4 +518,66 @@ if ($page == 'overview') { } } } -} +} elseif ($page == 'backup') { + if ($action == '') { + $log->logAction(USR_ACTION, LOG_NOTICE, "viewed customer_extras::backup"); + + if (isset($_POST['send']) && $_POST['send'] == 'send') { + + if (! $_POST['path']) { + standard_error('invalidpath'); + } + + $path = makeCorrectDir(validate($_POST['path'], 'path')); + $path = makeCorrectDir($userinfo['documentroot'] . '/' . $path); + + $backup_dbs = isset($_POST['backup_dbs']) ? intval($_POST['backup_dbs']) : 0; + $backup_mail = isset($_POST['backup_mail']) ? intval($_POST['backup_mail']) : 0; + $backup_web = isset($_POST['backup_web']) ? intval($_POST['backup_web']) : 0; + + if ($backup_dbs != '1') { + $backup_dbs = '0'; + } + + if ($backup_mail != '1') { + $backup_mail = '0'; + } + + if ($backup_web != '1') { + $backup_web = '0'; + } + + $task_data = array( + 'customerid' => $userinfo['customerid'], + 'uid' => $userinfo['guid'], + 'gid' => $userinfo['guid'], + 'loginname' => $userinfo['loginname'], + 'destdir' => $path, + 'backup_dbs' => $backup_dbs, + 'backup_mail' => $backup_mail, + 'backup_web' => $backup_web + ); + inserttask('20', $task_data); + + standard_success('backupscheduled'); + } else { + + // check whether there is a backup-job for this customer + $sel_stmt = Database::prepare("SELECT * FROM `".TABLE_PANEL_TASKS."` WHERE `type` = '20'"); + Database::pexecute($sel_stmt); + while ($entry = $sel_stmt->fetch()) + { + $data = unserialize($entry['data']); + if ($data['customerid'] == $userinfo['customerid']) { + standard_error('customerhasongoingbackupjob'); + } + } + $pathSelect = makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']); + $backup_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.backup.php'; + $backup_form = htmlform::genHTMLForm($backup_data); + $title = $backup_data['backup']['title']; + $image = $backup_data['backup']['image']; + eval("echo \"" . getTemplate("extras/backup") . "\";"); + } + } +} \ No newline at end of file diff --git a/install/froxlor.sql b/install/froxlor.sql index ae2ec259..5bece437 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -556,7 +556,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('panel', 'password_special_char_required', '0'), ('panel', 'password_special_char', '!?<>§$%+#=@'), ('panel', 'version', '0.9.35.1'), - ('panel', 'db_version', '201603150'); + ('panel', 'db_version', '201604270'); DROP TABLE IF EXISTS `panel_tasks`; @@ -765,7 +765,8 @@ INSERT INTO `cronjobs_run` (`id`, `module`, `cronfile`, `interval`, `isactive`, (4, 'froxlor/ticket', 'ticketarchive', '1 MONTH', '1', 'cron_ticketarchive'), (5, 'froxlor/reports', 'usage_report', '1 DAY', '1', 'cron_usage_report'), (6, 'froxlor/core', 'mailboxsize', '6 HOUR', '1', 'cron_mailboxsize'), - (7, 'froxlor/letsencrypt', 'letsencrypt', '5 MINUTE', '0', 'cron_letsencrypt'); + (7, 'froxlor/letsencrypt', 'letsencrypt', '5 MINUTE', '0', 'cron_letsencrypt'), + (8, 'froxlor/backup', 'backup', '1 DAY', '1', 'cron_backup'); diff --git a/install/updates/froxlor/0.9/update_0.9.inc.php b/install/updates/froxlor/0.9/update_0.9.inc.php index 2b435653..c34c0dc3 100644 --- a/install/updates/froxlor/0.9/update_0.9.inc.php +++ b/install/updates/froxlor/0.9/update_0.9.inc.php @@ -3292,3 +3292,21 @@ if (isFroxlorVersion('0.9.35')) { updateToVersion('0.9.35.1'); } + +if (isFroxlorVersion('0.9.35.1') && isDatabaseVersion('201603150')) { + + showUpdateStep("Adding new backup-cron entry"); + $stmt = Database::prepare(" + INSERT INTO `" . TABLE_PANEL_CRONRUNS . "` SET + `module` = 'froxlor/backup', + `cronfile` = 'backup', + `interval` = '1 DAY', + `desc_lng_key` = 'cron_backup', + `lastrun` = 0, + `isactive` = 0" + ); + Database::pexecute($stmt); + lastStepStatus(0); + + updateToDbVersion('201604270'); +} diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 68ffa009..6837da0a 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -84,7 +84,7 @@ return array( 'value' => $result['registration_date'], 'size' => 10 ), - 'termination_date' => array( + 'termination_date' => array( 'label' => $lng['domains']['termination_date'], 'desc' => $lng['panel']['dateformat'], 'type' => 'text', diff --git a/lib/formfields/customer/extras/formfield.backup.php b/lib/formfields/customer/extras/formfield.backup.php new file mode 100644 index 00000000..82c9259b --- /dev/null +++ b/lib/formfields/customer/extras/formfield.backup.php @@ -0,0 +1,70 @@ + (2010-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Formfields + * + */ +return array( + 'backup' => array( + 'title' => $lng['extras']['backup'], + 'image' => 'icons/backup_big.png', + 'sections' => array( + 'section_a' => array( + 'title' => $lng['extras']['backup'], + 'image' => 'icons/backup_big.png', + 'fields' => array( + 'path' => array( + 'label' => $lng['panel']['path'], + 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? $lng['panel']['pathDescription'] : null).(isset($pathSelect['note']) ? '
'.$pathSelect['value'] : ''), + 'type' => $pathSelect['type'], + 'select_var' => $pathSelect['value'], + 'value' => $pathSelect['value'] + ), + 'backup_web' => array( + 'label' => $lng['extras']['backup_web'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array('1') + ), + 'backup_mail' => array( + 'label' => $lng['extras']['backup_mail'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array('1') + ), + 'backup_dbs' => array( + 'label' => $lng['extras']['backup_dbs'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array('1') + ) + ) + ) + ) + ) +); diff --git a/lib/functions/filedir/function.createCustomerBackup.php b/lib/functions/filedir/function.createCustomerBackup.php new file mode 100644 index 00000000..20cff168 --- /dev/null +++ b/lib/functions/filedir/function.createCustomerBackup.php @@ -0,0 +1,116 @@ + (2010-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Functions + * + */ + +/** + * depending on the give choice, the customers web-data, email-data and databases are being backup'ed + * + * @param array $data + * + * @return void + * + */ +function createCustomerBackup($data = null, $customerdocroot = null, &$cronlog) +{ + $cronlog->logAction(CRON_ACTION, LOG_INFO, 'Creating Backup for user "'.$data['loginname'].'"'); + + // create tmp folder + $tmpdir = makeCorrectDir($data['destdir'] . '/.tmp/'); + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "'.$tmpdir.'"'); + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir)); + safe_exec('mkdir -p ' . escapeshellarg($tmpdir)); + $create_backup_tar = false; + + // MySQL databases + if ($data['backup_dbs'] == 1) { + + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "'.makeCorrectDir($tmpdir . '/mysql').'"'); + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(makeCorrectDir($tmpdir . '/mysql'))); + safe_exec('mkdir -p ' . escapeshellarg(makeCorrectDir($tmpdir . '/mysql'))); + + // get all customer database-names + $sel_stmt = Database::prepare("SELECT `databasename` FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid"); + Database::pexecute($sel_stmt, array( + 'cid' => $data['customerid'] + )); + + Database::needRoot(true); + Database::needSqlData(); + $sql_root = Database::getSqlData(); + Database::needRoot(false); + + while ($row = $sel_stmt->fetch()) { + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql')); + $bool_false = false; + safe_exec('mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -p' . $sql_root['passwd'] . ' ' . $row['databasename'] . ' > ' . makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, array('>')); + $create_backup_tar = true; + } + + unset($sql_root); + } + + // E-mail data + if ($data['backup_mail'] == 1) { + + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "'.makeCorrectDir($tmpdir . '/mail').'"'); + safe_exec('mkdir -p ' . escapeshellarg(makeCorrectDir($tmpdir . '/mail'))); + + // get all customer mail-accounts + $sel_stmt = Database::prepare("SELECT CONCAT(`homedir`, `maildir`) as acc_path FROM `" . TABLE_MAIL_USERS . "` WHERE `customerid` = :cid"); + Database::pexecute($sel_stmt, array( + 'cid' => $data['customerid'] + )); + + $tar_file_list = ""; + while ($row = $sel_stmt->fetch()) { + $tar_file_list .= $row['acc_path'] . " "; + } + + if (! empty($tar_file_list)) { + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' ' . escapeshellarg(trim($tar_file_list))); + safe_exec('tar cfz ' . escapeshellarg(makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' ' . escapeshellarg(trim($tar_file_list))); + $create_backup_tar = true; + } + } + + // Web data + if ($data['backup_web'] == 1) { + + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'Creating web-folder "'.makeCorrectDir($tmpdir . '/web').'"'); + safe_exec('mkdir -p ' . escapeshellarg(makeCorrectDir($tmpdir . '/web'))); + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude ' . escapeshellarg($tmpdir) .' ' . escapeshellarg($customerdocroot)); + safe_exec('tar cfz ' . escapeshellarg(makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude ' . escapeshellarg($tmpdir) .' ' . escapeshellarg($customerdocroot)); + $create_backup_tar = true; + } + + if ($create_backup_tar) + { + $backup_file = makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-backup_' . date('YmdHi', time()) . '.tar.gz'); + $cronlog->logAction(CRON_ACTION, LOG_INFO, 'Creating backup-file "'.$backup_file.'"'); + // pack all archives in tmp-dir to one + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($tmpdir)); + safe_exec('tar cfz ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($tmpdir)); + // move to destination directory + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir'])); + safe_exec('mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir'])); + // remove tmp-files + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> rm -rf '.escapeshellarg($tmpdir)); + safe_exec('rm -rf '.escapeshellarg($tmpdir)); + // set owner to customer + $cronlog->logAction(CRON_ACTION, LOG_DEBUG, 'shell> chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($data['destdir'])); + safe_exec('chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($data['destdir'])); + } +} diff --git a/lib/functions/froxlor/function.inserttask.php b/lib/functions/froxlor/function.inserttask.php index 41f7750b..3f2cdbde 100644 --- a/lib/functions/froxlor/function.inserttask.php +++ b/lib/functions/froxlor/function.inserttask.php @@ -101,5 +101,10 @@ function inserttask($type, $param1 = '', $param2 = '', $param3 = '', $param4 = ' $data = serialize($data); Database::pexecute($ins_stmt, array('type' => '8', 'data' => $data)); + } elseif ($type == '20' + && is_array($param1) + ) { + $data = serialize($param1); + Database::pexecute($ins_stmt, array('type' => '20', 'data' => $data)); } } diff --git a/lib/navigation/00.froxlor.main.php b/lib/navigation/00.froxlor.main.php index eb7e7d21..cb6f0401 100644 --- a/lib/navigation/00.froxlor.main.php +++ b/lib/navigation/00.froxlor.main.php @@ -124,11 +124,15 @@ return array ( 'url' => 'customer_extras.php?page=htaccess', 'label' => $lng['menue']['extras']['pathoptions'], ), - array ( - 'url' => 'customer_logger.php?page=log', - 'label' => $lng['menue']['logger']['logger'], - 'show_element' => ( Settings::Get('logger.enabled') == true ) - ), + array ( + 'url' => 'customer_logger.php?page=log', + 'label' => $lng['menue']['logger']['logger'], + 'show_element' => ( Settings::Get('logger.enabled') == true ) + ), + array ( + 'url' => 'customer_extras.php?page=backup', + 'label' => $lng['menue']['extras']['backup'], + ), ), ), 'traffic' => array ( diff --git a/lng/english.lng.php b/lng/english.lng.php index 242ff7c5..8e0d72f0 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1974,3 +1974,12 @@ $lng['domains']['termination_date_overview'] = 'canceled until '; $lng['panel']['set'] = 'Apply'; $lng['customer']['selectserveralias_addinfo'] = 'This option can be set when editing the domain. Its initial value is inherited from the parent-domain.'; $lng['error']['mailaccistobedeleted'] = "Another account with the same name (%s) is currently being deleted and can therefore not be added at this moment."; + +$lng['menue']['extras']['backup'] = 'Backup'; +$lng['extras']['backup'] = 'Create backup'; +$lng['extras']['backup_web'] = 'Backup web-data'; +$lng['extras']['backup_mail'] = 'Backup mail-data'; +$lng['extras']['backup_dbs'] = 'Backup databases'; +$lng['error']['customerhasongoingbackupjob'] = 'There is already a backup job waiting to be processed, please be patient.'; +$lng['success']['backupscheduled'] = 'Your backup job has been scheduled. Please wait for it to be processed'; +$lng['crondesc']['cron_backup'] = 'Process backup jobs'; diff --git a/lng/german.lng.php b/lng/german.lng.php index 38815cc9..6fe024b2 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1627,3 +1627,12 @@ $lng['domains']['termination_date_overview'] = 'gekündigt zum '; $lng['panel']['set'] = 'Setzen'; $lng['customer']['selectserveralias_addinfo'] = 'Diese Option steht beim Bearbeiten der Domain zur Verfügung. Als Initial-Wert wird die Einstellung der Hauptdomain vererbt.'; $lng['error']['mailaccistobedeleted'] = "Ein vorheriges Konto mit dem gleichen Namen (%s) wird aktuell noch gelöscht und kann daher derzeit nicht angelegt werden"; + +$lng['menue']['extras']['backup'] = 'Sicherung'; +$lng['extras']['backup'] = 'Sicherung erstellen'; +$lng['extras']['backup_web'] = 'Web-Daten sichern'; +$lng['extras']['backup_mail'] = 'E-Mail Daten sichern'; +$lng['extras']['backup_dbs'] = 'Datenbanken sichern'; +$lng['error']['customerhasongoingbackupjob'] = 'Es gibt noch einen austehenden Backup-Job. Bitte haben Sie etwas Geduld.'; +$lng['success']['backupscheduled'] = 'Ihre Sicherung wurde erfolgreich geplant. Bitte warten Sie nun, bis diese abgearbeitet wurde.'; +$lng['crondesc']['cron_backup'] = 'Ausstehende Sicherungen erstellen'; diff --git a/scripts/jobs/cron_backup.php b/scripts/jobs/cron_backup.php new file mode 100644 index 00000000..abecaca4 --- /dev/null +++ b/scripts/jobs/cron_backup.php @@ -0,0 +1,108 @@ + + * @author Froxlor team (2010-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Cron + * + * @since 0.9.35.1 + * + */ + +// Check Traffic-Lock +if (function_exists('pcntl_fork')) { + $BackupLock = makeCorrectFile(dirname($lockfile)."/froxlor_cron_backup.lock"); + if (file_exists($BackupLock) + && is_numeric($BackupPid=file_get_contents($BackupLock)) + ) { + if (function_exists('posix_kill')) { + $BackupPidStatus = @posix_kill($BackupPid,0); + } else { + system("kill -CHLD " . $BackupPid . " 1> /dev/null 2> /dev/null", $BackupPidStatus); + $BackupPidStatus = $BackupPidStatus ? false : true; + } + if ($BackupPidStatus) { + $cronlog->logAction(CRON_ACTION, LOG_INFO, 'Backup run already in progress'); + return 1; + } + } + // Create Backup Log and Fork + // We close the database - connection before we fork, so we don't share resources with the child + Database::needRoot(false); // this forces the connection to be set to null + $BackupPid = pcntl_fork(); + // Parent + if ($BackupPid) { + file_put_contents($BackupLock, $BackupPid); + // unnecessary to recreate database connection here + return 0; + + } + //Child + elseif ($BackupPid == 0) { + posix_setsid(); + fclose($debugHandler); + // re-create db + Database::needRoot(false); + } + //Fork failed + else { + return 1; + } + +} else { + if (extension_loaded('pcntl')) { + $msg = "PHP compiled with pcntl but pcntl_fork function is not available."; + } else { + $msg = "PHP compiled without pcntl."; + } + $cronlog->logAction(CRON_ACTION, LOG_WARNING, $msg." Not forking backup-cron, this may take a long time!"); +} + +$cronlog->logAction(CRON_ACTION, LOG_INFO, 'cron_backup: started - creating customer backup'); + +$result_tasks_stmt = Database::query(" + SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20' ORDER BY `id` ASC +"); + +$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :id"); + +while ($row = $result_tasks_stmt->fetch(PDO::FETCH_ASSOC)) { + + if ($row['data'] != '') { + $row['data'] = unserialize($row['data']); + } + + if (is_array($row['data'])) { + + if (isset($row['data']['customerid']) + && isset($row['data']['loginname']) + && isset($row['data']['destdir']) + ) { + $row['data']['destdir'] = makeCorrectDir($row['data']['destdir']); + $customerdocroot = makeCorrectDir(Settings::Get('system.documentroot_prefix').'/'.$row['data']['loginname'].'/'); + + if (!file_exists($row['data']['destdir']) + && $row['data']['destdir'] != '/' + && $row['data']['destdir'] != Settings::Get('system.documentroot_prefix') + && $row['data']['destdir'] != $customerdocroot + ) { + $cronlog->logAction(CRON_ACTION, LOG_NOTICE, 'Creating backup-destination path for customer: ' . escapeshellarg($row['data']['destdir'])); + safe_exec('mkdir -p '.escapeshellarg($row['data']['destdir'])); + } + + createCustomerBackup($row['data'], $customerdocroot, $cronlog); + } + } + + // remove entry + Database::pexecute($del_stmt, array('id' => $row['id'])); +} diff --git a/scripts/jobs/cron_tasks.php b/scripts/jobs/cron_tasks.php index a614613b..b452c2d4 100644 --- a/scripts/jobs/cron_tasks.php +++ b/scripts/jobs/cron_tasks.php @@ -30,8 +30,9 @@ require_once makeCorrectFile(dirname(__FILE__) . '/cron_tasks.inc.http.35.nginx_ * LOOK INTO TASKS TABLE TO SEE IF THERE ARE ANY UNDONE JOBS */ $cronlog->logAction(CRON_ACTION, LOG_INFO, "cron_tasks: Searching for tasks to do"); +// no type 99 (regenerate cron.d-file) and no type 20 (customer backup) $result_tasks_stmt = Database::query(" - SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' ORDER BY `id` ASC + SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `id` ASC "); $num_results = Database::num_rows(); $resultIDs = array(); @@ -395,7 +396,7 @@ while ($row = $result_tasks_stmt->fetch(PDO::FETCH_ASSOC)) { } } } - } + } } } } diff --git a/templates/Sparkle/customer/extras/backup.tpl b/templates/Sparkle/customer/extras/backup.tpl new file mode 100644 index 00000000..6e71243e --- /dev/null +++ b/templates/Sparkle/customer/extras/backup.tpl @@ -0,0 +1,26 @@ +$header +
+
+

+ {$title}  + {$title} +

+
+ +
+ +
+ + + + + + + {$backup_form} +
+
+ +
+ +
+$footer