Files
Froxlor/lib/Froxlor/System/Cronjob.php
2023-07-26 10:13:50 +02:00

361 lines
10 KiB
PHP

<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* 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 2
* 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, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
namespace Froxlor\System;
use Exception;
use Froxlor\Cron\TaskId;
use Froxlor\Database\Database;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
use PDO;
class Cronjob
{
/**
* Function checkLastGuid
*
* Checks if the system's last guid is not higher than the one saved
* in froxlor's database. If it's higher, froxlor needs to
* set its last guid to this one to avoid conflicts with libnss-users
*
* @return null
*/
public static function checkLastGuid()
{
$mylog = FroxlorLogger::getInstanceOf();
$group_lines = [];
$group_guids = [];
$update_to_guid = 0;
$froxlor_guid = 0;
$result_stmt = Database::query("SELECT MAX(`guid`) as `fguid` FROM `" . TABLE_PANEL_CUSTOMERS . "`");
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
$froxlor_guid = $result['fguid'];
// possibly no customers yet or f*cked up lastguid settings
if ($froxlor_guid < Settings::Get('system.lastguid')) {
$froxlor_guid = Settings::Get('system.lastguid');
}
$g_file = '/etc/group';
if (file_exists($g_file)) {
if (is_readable($g_file)) {
if (true == ($groups = file_get_contents($g_file))) {
$group_lines = explode("\n", $groups);
foreach ($group_lines as $group) {
$group_guids[] = explode(":", $group);
}
foreach ($group_guids as $group) {
/**
* nogroup | nobody have very high guids
* ignore them
*/
if ($group[0] == 'nogroup' || $group[0] == 'nobody') {
continue;
}
$guid = isset($group[2]) ? (int)$group[2] : 0;
if ($guid > $update_to_guid) {
$update_to_guid = $guid;
}
}
// if it's lower, then froxlor's highest guid is the last
if ($update_to_guid < $froxlor_guid) {
$update_to_guid = $froxlor_guid;
} elseif ($update_to_guid == $froxlor_guid) {
// if it's equal, that means we already have a collision
// to ensure it won't happen again, increase the guid by one
$update_to_guid = (int)$update_to_guid++;
}
// now check if it differs from our settings
if ($update_to_guid != Settings::Get('system.lastguid')) {
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
'Updating froxlor last guid to ' . $update_to_guid);
Settings::Set('system.lastguid', $update_to_guid);
}
} else {
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
'File /etc/group not readable; cannot check for latest guid');
}
} else {
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
'File /etc/group not readable; cannot check for latest guid');
}
} else {
$mylog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE,
'File /etc/group does not exist; cannot check for latest guid');
}
}
/**
* Inserts a task into the PANEL_TASKS-Table
*
* @param int $type Type of task
* @param string $params Parameter (possible to pass multiple times)
*
* @throws Exception
* @author Froxlor team <team@froxlor.org> (2010-)
*/
public static function inserttask(int $type, ...$params)
{
// prepare the insert-statement
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_TASKS . "` SET `type` = :type, `data` = :data
");
if ($type == TaskId::REBUILD_VHOST || $type == TaskId::REBUILD_DNS || $type == TaskId::CREATE_FTP || $type == TaskId::CREATE_QUOTA || $type == TaskId::REBUILD_CRON) {
// 4 = bind -> if bind disabled -> no task
if ($type == TaskId::REBUILD_DNS && Settings::Get('system.bind_enable') == '0') {
return;
}
// 10 = quota -> if quota disabled -> no task
if ($type == TaskId::CREATE_QUOTA && Settings::Get('system.diskquota_enabled') == '0') {
return;
}
// delete previously inserted tasks if they are the same as we only need ONE
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = :type
");
Database::pexecute($del_stmt, [
'type' => $type
]);
// insert the new task
Database::pexecute($ins_stmt, [
'type' => $type,
'data' => ''
]);
} elseif ($type == TaskId::CREATE_HOME && count($params) == 4 && $params[0] != '' && $params[1] != '' && $params[2] != '' && ($params[3] == 0 || $params[3] == 1)) {
$data = [];
$data['loginname'] = $params[0];
$data['uid'] = $params[1];
$data['gid'] = $params[2];
$data['store_defaultindex'] = $params[3];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::CREATE_HOME,
'data' => $data
]);
} elseif ($type == TaskId::DELETE_CUSTOMER_FILES && isset($params[0]) && $params[0] != '') {
$data = [];
$data['loginname'] = $params[0];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_CUSTOMER_FILES,
'data' => $data
]);
} elseif ($type == TaskId::DELETE_EMAIL_DATA && count($params) == 2 && $params[0] != '' && $params[1] != '') {
$data = [];
$data['loginname'] = $params[0];
$data['email'] = $params[1];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_EMAIL_DATA,
'data' => $data
]);
} elseif ($type == TaskId::DELETE_FTP_DATA && count($params) == 2 && $params[0] != '' && $params[1] != '') {
$data = [];
$data['loginname'] = $params[0];
$data['homedir'] = $params[1];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_FTP_DATA,
'data' => $data
]);
} elseif ($type == TaskId::DELETE_DOMAIN_PDNS && isset($params[0]) && $params[0] != '' && Settings::Get('system.bind_enable') == '1' && Settings::Get('system.dns_server') == 'PowerDNS') {
// -> if bind disabled or dns-server not PowerDNS -> no task
$data = [];
$data['domain'] = $params[0];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_DOMAIN_PDNS,
'data' => $data
]);
} elseif ($type == TaskId::DELETE_DOMAIN_SSL && isset($params[0]) && $params[0] != '') {
$data = [];
$data['domain'] = $params[0];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_DOMAIN_SSL,
'data' => $data
]);
} elseif ($type == TaskId::CREATE_CUSTOMER_DATADUMP && isset($params[0]) && is_array($params[0])) {
$data = json_encode($params[0]);
Database::pexecute($ins_stmt, [
'type' => TaskId::CREATE_CUSTOMER_DATADUMP,
'data' => $data
]);
}
}
/**
* returns an array of all cronjobs and when they last were executed
*
* @return array
*/
public static function getCronjobsLastRun(): array
{
$query = "SELECT `lastrun`, `desc_lng_key` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `isactive` = '1' ORDER BY `cronfile` ASC";
$result = Database::query($query);
$cronjobs_last_run = [];
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
$cronjobs_last_run[] = [
'title' => lng('crondesc.' . $row['desc_lng_key']),
'lastrun' => $row['lastrun']
];
}
return $cronjobs_last_run;
}
/**
* @param string $module
* @param int $isactive
* @return void
* @throws Exception
*/
public static function toggleCronStatus(string $module, int $isactive = 0)
{
if ($isactive != 1) {
$isactive = 0;
}
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `isactive` = :active WHERE `module` = :module
");
Database::pexecute($upd_stmt, [
'active' => $isactive,
'module' => $module
]);
}
/**
* returns an array of tasks that are queued to be run by the cronjob
*
* @return array
*/
public static function getOutstandingTasks(): array
{
$query = "SELECT * FROM `" . TABLE_PANEL_TASKS . "` ORDER BY `type` ASC";
$result = Database::query($query);
$tasks = [];
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if ($row['data'] != '') {
$row['data'] = json_decode($row['data'], true);
}
$task_id = $row['type'];
if (TaskId::isValid($task_id)) {
$task_constname = TaskId::convertToConstant($task_id);
$lngParams = [];
if (is_array($row['data'])) {
// task includes loginname
if (isset($row['data']['loginname'])) {
$lngParams = [$row['data']['loginname']];
}
// task includes domain data
if (isset($row['data']['domain'])) {
$lngParams = [$row['data']['domain']];
}
}
$task = [
'desc' => lng('tasks.' . $task_constname, $lngParams)
];
} else {
// unknown
$task = ['desc' => "ERROR: Unknown task type '" . $row['type'] . "'"];
}
$tasks[] = $task;
}
if (empty($tasks)) {
$tasks = [['desc' => lng('tasks.noneoutstanding')]];
}
return $tasks;
}
/**
* Send notification to system admin via email
*
* @param string $message
* @param string $subject
*
* @return void
*/
public static function notifyMailToAdmin(string $message, string $subject = "[froxlor] Important notice")
{
$mail = new Mailer(true);
$mailerror = false;
$mailerr_msg = "";
try {
$mail->Subject = $subject;
$mail->AltBody = $message;
$mail->MsgHTML(nl2br($message));
$mail->AddAddress(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
$mail->Send();
} catch (\PHPMailer\PHPMailer\Exception $e) {
$mailerr_msg = $e->errorMessage();
$mailerror = true;
} catch (Exception $e) {
$mailerr_msg = $e->getMessage();
$mailerror = true;
}
$mail->ClearAddresses();
if ($mailerror) {
echo 'Error sending mail: ' . $mailerr_msg . "\n";
}
}
/**
* @param string $cronname
* @return void
* @throws Exception
*/
public static function updateLastRunOfCron(string $cronname)
{
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `lastrun` = UNIX_TIMESTAMP() WHERE `cronfile` = :cron;
");
Database::pexecute($upd_stmt, [
'cron' => $cronname
]);
}
}