2024-04-22 14:24:04 +02:00
< ? php if ( ! defined ( 'BASEPATH' )) exit ( 'No direct script access allowed' );
2024-04-24 21:35:07 +02:00
class cron extends CI_Controller {
2024-05-08 13:29:43 +02:00
private $min_php_version ;
2024-04-23 01:23:54 +02:00
function __construct () {
2024-04-22 14:24:04 +02:00
parent :: __construct ();
2024-04-22 23:58:35 +02:00
if ( ENVIRONMENT == 'maintenance' && $this -> session -> userdata ( 'user_id' ) == '' ) {
2024-06-08 11:01:59 +02:00
echo __ ( " Maintenance Mode is active. Try again later. " ) . " \n " ;
2024-04-22 23:58:35 +02:00
redirect ( 'user/login' );
2024-04-22 14:24:04 +02:00
}
2024-04-26 00:50:06 +02:00
$this -> load -> model ( 'cron_model' );
2024-05-08 13:29:43 +02:00
// Minimum PHP Version for the Cron Manager
$this -> min_php_version = '8.1.0' ;
2024-04-22 14:24:04 +02:00
}
public function index () {
2024-04-22 23:58:35 +02:00
2024-04-24 17:23:21 +02:00
$this -> load -> model ( 'user_model' );
2024-04-24 21:35:07 +02:00
if ( ! $this -> user_model -> authorize ( 99 )) {
2024-08-16 10:08:44 +02:00
$this -> session -> set_flashdata ( 'error' , __ ( " You're not allowed to do that! " ));
2024-04-24 21:35:07 +02:00
redirect ( 'dashboard' );
}
2024-04-22 23:58:35 +02:00
2024-04-22 14:24:04 +02:00
$this -> load -> helper ( 'file' );
$footerData = [];
2024-04-26 00:50:06 +02:00
$footerData [ 'scripts' ] = [
'assets/js/cronstrue.min.js?' . filemtime ( realpath ( __DIR__ . " /../../assets/js/cronstrue.min.js " )),
'assets/js/sections/cron.js?' . filemtime ( realpath ( __DIR__ . " /../../assets/js/sections/cron.js " ))
];
2024-04-22 14:24:04 +02:00
2024-06-08 11:01:59 +02:00
$data [ 'page_title' ] = __ ( " Cron Manager " );
2024-04-22 14:24:04 +02:00
$data [ 'crons' ] = $this -> cron_model -> get_crons ();
2024-08-21 21:21:26 +02:00
$data [ 'cron_allow_insecure' ] = $this -> config -> item ( 'cron_allow_insecure' ) ? ? false ;
2024-04-22 14:24:04 +02:00
2024-04-26 22:03:59 +02:00
$mastercron = array ();
$mastercron = $this -> get_mastercron_status ();
$data [ 'mastercron' ] = $mastercron ;
2024-05-08 13:29:43 +02:00
$data [ 'min_php_version' ] = $this -> min_php_version ;
2024-04-26 22:03:59 +02:00
2024-04-22 14:24:04 +02:00
$this -> load -> view ( 'interface_assets/header' , $data );
$this -> load -> view ( 'cron/index' );
$this -> load -> view ( 'interface_assets/footer' , $footerData );
}
2024-04-22 23:58:35 +02:00
2024-04-24 17:23:21 +02:00
public function run () {
2024-04-23 01:23:54 +02:00
// This is the main function, which handles all crons, runs them if enabled and writes the 'next run' timestamp to the database
2024-05-08 13:29:43 +02:00
// check for min. PHP version
if ( version_compare ( PHP_VERSION , $this -> min_php_version ) >= 0 ) {
2024-04-23 10:50:57 +02:00
2024-05-08 13:29:43 +02:00
// TODO Add an API Key to the cronjob to improve security?
2024-04-23 01:23:54 +02:00
2024-05-08 13:29:43 +02:00
$crons = $this -> cron_model -> get_crons ();
2024-04-26 00:50:06 +02:00
2024-05-08 13:29:43 +02:00
$status = 'pending' ;
2024-04-23 01:23:54 +02:00
2024-05-08 13:29:43 +02:00
foreach ( $crons as $cron ) {
2024-08-27 07:53:41 +02:00
// Set the status to false by default
$set_status = false ;
2024-05-08 13:29:43 +02:00
if ( $cron -> enabled == 1 ) {
2024-04-26 18:48:54 +02:00
2024-05-08 13:29:43 +02:00
// calculate the crons expression
$data = array (
'expression' => $cron -> expression ,
'timeZone' => null
);
$this -> load -> library ( 'CronExpression' , $data );
2024-04-24 21:35:07 +02:00
2024-05-08 13:29:43 +02:00
$cronjob = $this -> cronexpression ;
$dt = new DateTime ();
$isdue = $cronjob -> isMatching ( $dt );
2024-08-27 07:53:41 +02:00
// Set the status to true, if the cron is enabled by default
2024-08-23 08:54:57 +02:00
$set_status = true ;
2024-04-26 00:50:06 +02:00
2024-05-08 13:29:43 +02:00
$next_run = $cronjob -> getNext ();
$next_run_date = date ( 'Y-m-d H:i:s' , $next_run );
$this -> cron_model -> set_next_run ( $cron -> id , $next_run_date );
2024-04-23 10:50:57 +02:00
2024-05-08 13:29:43 +02:00
if ( $isdue == true ) {
$isdue_result = 'true' ;
2024-04-23 10:50:57 +02:00
2025-01-02 11:54:44 +01:00
log_message ( 'debug' , 'CRON: ' . $cron -> id . ' is due and will be executed.' );
2024-04-23 01:23:54 +02:00
2024-05-08 13:29:43 +02:00
echo " CRON: " . $cron -> id . " -> is due: " . $isdue_result . " \n " ;
echo " CRON: " . $cron -> id . " -> RUNNING... \n " ;
2024-04-23 01:23:54 +02:00
2024-08-23 08:43:11 +02:00
$url = local_url () . $cron -> function ;
2024-08-23 15:00:45 +02:00
if ( ENVIRONMENT == " development " ) {
echo " CRON: " . $cron -> id . " -> URL: " . $url . " \n " ;
}
2024-04-23 01:23:54 +02:00
2024-05-08 13:29:43 +02:00
$ch = curl_init ();
curl_setopt ( $ch , CURLOPT_URL , $url );
curl_setopt ( $ch , CURLOPT_HEADER , false );
curl_setopt ( $ch , CURLOPT_USERAGENT , 'Wavelog Updater' );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
2024-08-21 21:21:26 +02:00
if ( $this -> config -> item ( 'cron_allow_insecure' ) ? ? false == true ) {
2024-08-21 17:02:33 +02:00
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , false );
}
2024-05-08 13:29:43 +02:00
$crun = curl_exec ( $ch );
curl_close ( $ch );
if ( $crun !== false ) {
echo " CRON: " . $cron -> id . " -> CURL Result: " . $crun . " \n " ;
$status = 'healthy' ;
} else {
2024-08-23 00:36:48 +02:00
echo " ERROR: Something went wrong with " . $cron -> id . " ; Message: " . $crun . " \n " ;
2024-05-08 13:29:43 +02:00
$status = 'failed' ;
}
2024-04-23 01:23:54 +02:00
} else {
2024-05-08 13:29:43 +02:00
$isdue_result = 'false' ;
echo " CRON: " . $cron -> id . " -> is due: " . $isdue_result . " -> Next Run: " . $next_run_date . " \n " ;
$status = 'healthy' ;
2024-08-27 07:53:41 +02:00
// Don't set the status as the cronjob is not due
2024-08-23 08:54:57 +02:00
$set_status = false ;
2024-04-23 01:23:54 +02:00
}
} else {
2024-05-08 13:29:43 +02:00
echo 'CRON: ' . $cron -> id . " is disabled. skipped.. \n " ;
$status = 'disabled' ;
2024-08-27 07:53:41 +02:00
// Set the status if the cron needs to be disabled.
$set_status = true ;
2024-04-23 01:23:54 +02:00
2024-05-08 13:29:43 +02:00
// Set the next_run timestamp to null to indicate in the view/database that this cron is disabled
$this -> cron_model -> set_next_run ( $cron -> id , null );
}
2024-08-23 08:50:10 +02:00
if ( $set_status == true ) {
$this -> cron_model -> set_status ( $cron -> id , $status );
}
2024-05-08 13:29:43 +02:00
$this -> cronexpression = null ;
2024-04-23 01:23:54 +02:00
}
2024-04-26 22:03:59 +02:00
2024-05-08 13:29:43 +02:00
$datetime = new DateTime ( " now " , new DateTimeZone ( 'UTC' ));
$datetime = $datetime -> format ( 'Ymd H:i:s' );
$this -> optionslib -> update ( 'mastercron_last_run' , $datetime , 'no' );
} else {
log_message ( 'error' , 'CRON: PHP Version ' . PHP_VERSION . ' not supported. Minimum Version is: ' . $this -> min_php_version );
echo 'CRON: PHP Version ' . PHP_VERSION . ' not supported. Minimum Version is: ' . $this -> min_php_version . " \n " ;
}
2024-04-24 17:23:21 +02:00
}
2024-04-25 16:37:17 +02:00
public function editDialog () {
$cron_query = $this -> cron_model -> cron ( xss_clean ( $this -> input -> post ( 'id' , true )));
2024-04-26 10:50:37 +02:00
$data [ 'cron' ] = $cron_query -> row ();
2024-06-08 11:01:59 +02:00
$data [ 'page_title' ] = __ ( " Edit Cronjob " );
2024-04-25 16:37:17 +02:00
$this -> load -> view ( 'cron/edit' , $data );
}
2024-04-26 00:50:06 +02:00
2024-04-26 13:53:13 +02:00
public function edit () {
$this -> load -> model ( 'user_model' );
if ( ! $this -> user_model -> authorize ( 99 )) {
2024-08-16 10:08:44 +02:00
$this -> session -> set_flashdata ( 'error' , __ ( " You're not allowed to do that! " ));
2024-04-26 13:53:13 +02:00
redirect ( 'dashboard' );
}
2024-04-26 18:58:38 +02:00
$id = xss_clean ( $this -> input -> post ( 'cron_id' , true ));
$description = xss_clean ( $this -> input -> post ( 'cron_description' , true ));
$expression = xss_clean ( $this -> input -> post ( 'cron_expression' , true ));
$enabled = xss_clean ( $this -> input -> post ( 'cron_enabled' , true ));
2024-04-26 13:53:13 +02:00
2024-04-26 18:48:54 +02:00
$data = array (
'expression' => $expression ,
'timeZone' => null
);
$this -> load -> library ( 'CronExpression' , $data );
$cron = $this -> cronexpression ;
if ( $cron -> isValid ()) {
$this -> cron_model -> edit_cron ( $id , $description , $expression , $enabled );
$this -> cronexpression = null ;
header ( " Content-type: application/json " );
2024-04-26 18:58:38 +02:00
echo json_encode ([ 'success' => true , 'messagecategory' => 'success' , 'message' => 'Changes saved for Cronjob "' . $id . '"' ]);
2024-04-26 18:48:54 +02:00
} else {
$this -> session -> set_flashdata ( 'error' , 'The Cron Expression you entered is not valid' );
$this -> cronexpression = null ;
header ( " Content-type: application/json " );
2024-04-26 18:58:38 +02:00
echo json_encode ([ 'success' => false , 'messagecategory' => 'error' , 'message' => 'The expression "' . $expression . '" is not valid. Please try again.' ]);
2024-04-26 18:48:54 +02:00
}
2024-04-26 13:53:13 +02:00
}
2024-04-26 00:50:06 +02:00
public function toogleEnableCronSwitch () {
2024-04-26 18:58:38 +02:00
$id = xss_clean ( $this -> input -> post ( 'id' , true ));
$cron_enabled = xss_clean ( $this -> input -> post ( 'checked' , true ));
2024-04-26 00:50:06 +02:00
if ( $id ? ? '' != '' ) {
2024-04-26 18:58:38 +02:00
$this -> cron_model -> set_cron_enabled ( $id , $cron_enabled );
$data [ 'success' ] = 1 ;
2024-04-26 00:50:06 +02:00
} else {
2024-04-26 18:58:38 +02:00
$data [ 'success' ] = 0 ;
$data [ 'flashdata' ] = 'Not allowed' ;
2024-04-26 00:50:06 +02:00
}
echo json_encode ( $data );
}
public function fetchCrons () {
2024-04-26 18:58:38 +02:00
$hres = [];
2024-04-26 00:50:06 +02:00
$result = $this -> cron_model -> get_crons ();
foreach ( $result as $cron ) {
$single = ( object ) [];
$single -> cron_id = $cron -> id ;
$single -> cron_description = $cron -> description ;
$single -> cron_status = $this -> cronStatus2html ( $cron -> enabled , $cron -> status );
$single -> cron_expression = $this -> cronExpression2html ( $cron -> expression );
2024-11-04 21:25:10 +01:00
$single -> cron_last_run = $cron -> last_run ? ? __ ( " never " );
$single -> cron_next_run = ( $cron -> enabled == '1' ) ? ( $cron -> next_run ? ? __ ( " calculating... " )) : __ ( " never " );
2024-04-26 00:50:06 +02:00
$single -> cron_edit = $this -> cronEdit2html ( $cron -> id );
$single -> cron_enabled = $this -> cronEnabled2html ( $cron -> id , $cron -> enabled );
array_push ( $hres , $single );
2024-04-26 18:58:38 +02:00
}
2024-04-26 00:50:06 +02:00
echo json_encode ( $hres );
}
private function cronStatus2html ( $enabled , $status ) {
2024-04-26 18:58:38 +02:00
if ( $enabled == '1' ) {
2024-04-26 00:50:06 +02:00
if ( $status == 'healthy' ) {
2024-11-04 21:25:10 +01:00
$htmlret = '<span class="badge text-bg-success">' . __ ( " healthy " ) . '</span>' ;
} else if ( $status == 'failed' ) {
$htmlret = '<span class="badge text-bg-danger">' . __ ( " failed " ) . '</span>' ;
} else if ( $status == 'pending' ) {
$htmlret = '<span class="badge text-bg-warning">' . __ ( " pending " ) . '</span>' ;
2024-04-26 00:50:06 +02:00
} else {
2024-04-26 18:58:38 +02:00
$htmlret = '<span class="badge text-bg-warning">' . $status . '</span>' ;
2024-04-26 00:50:06 +02:00
}
} else {
2024-11-04 21:25:10 +01:00
$htmlret = '<span class="badge text-bg-secondary">' . __ ( " disabled " ) . '</span>' ;
2024-04-26 00:50:06 +02:00
}
return $htmlret ;
}
private function cronExpression2html ( $expression ) {
2024-04-26 18:58:38 +02:00
$htmlret = '<code id="humanreadable_tooltip" data-bs-toggle="tooltip">' . $expression . '</code>' ;
2024-04-26 00:50:06 +02:00
return $htmlret ;
}
private function cronEdit2html ( $id ) {
2024-04-26 18:58:38 +02:00
$htmlret = '<button id="' . $id . '" class="editCron btn btn-outline-primary btn-sm"><i class="fas fa-edit"></i></button>' ;
2024-04-26 00:50:06 +02:00
return $htmlret ;
}
private function cronEnabled2html ( $id , $enabled ) {
if ( $enabled == '1' ) {
$checked = 'checked' ;
} else {
$checked = '' ;
}
2024-04-26 18:58:38 +02:00
$htmlret = '<div class="form-check form-switch"><input name="cron_enable_switch" class="form-check-input enableCronSwitch" type="checkbox" role="switch" id="' . $id . '" ' . $checked . '></div>' ;
2024-04-26 00:50:06 +02:00
return $htmlret ;
}
2024-04-26 22:03:59 +02:00
private function get_mastercron_status () {
$warning_timelimit_seconds = 120 ; // yellow - warning please check
$error_timelimit_seconds = 600 ; // red - "not running"
$result = array ();
$last_run = $this -> optionslib -> get_option ( 'mastercron_last_run' ) ? ? null ;
if ( $last_run != null ) {
$timestamp_last_run = DateTime :: createFromFormat ( 'Ymd H:i:s' , $last_run , new DateTimeZone ( 'UTC' ));
$now = new DateTime ();
$diff = $now -> getTimestamp () - $timestamp_last_run -> getTimestamp ();
if ( $diff >= 0 && $diff <= $warning_timelimit_seconds ) {
2024-08-21 17:16:10 +02:00
$result [ 'status' ] = __ ( " OK " );
2024-04-26 22:03:59 +02:00
$result [ 'status_class' ] = 'success' ;
} else {
if ( $diff <= $error_timelimit_seconds ) {
2024-08-21 21:50:46 +02:00
$result [ 'status' ] = sprintf ( __ ( " Last run occurred more than %s seconds ago.%sPlease check your master cron! It should run every minute (* * * * *). " ), $warning_timelimit_seconds , '<br>' );
2024-04-26 22:03:59 +02:00
$result [ 'status_class' ] = 'warning' ;
} else {
2024-08-21 21:50:46 +02:00
$result [ 'status' ] = sprintf ( __ ( " Last run occurred more than %s minutes ago.%sSeems like your Mastercron isn't running!%sIt should run every minute (* * * * *). " ), ( $error_timelimit_seconds / 60 ), '<br>' , '<br>' );
2024-04-26 22:03:59 +02:00
$result [ 'status_class' ] = 'danger' ;
}
}
} else {
2024-08-21 17:16:10 +02:00
$result [ 'status' ] = _pgettext ( " Master Cron " , " Not running " );
2024-04-26 22:03:59 +02:00
$result [ 'status_class' ] = 'danger' ;
}
return $result ;
}
2024-04-22 14:24:04 +02:00
}