Warning: chmod(): Operation not permitted in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [0] in function chmod in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [1] in function include_once in /var/www/hopeinstoughton_www/wp-settings.php on line 560 [2] in function require_once in /var/www/hopeinstoughton_www/wp-config.php on line 85 [3] in function require_once in /var/www/hopeinstoughton_www/wp-load.php on line 50 [4] in function require_once in /var/www/hopeinstoughton_www/wp-blog-header.php on line 13 [5] in function require in /var/www/hopeinstoughton_www/index.php on line 17
| Server IP : 94.177.8.99 / Your IP : 216.73.217.165 Web Server : Apache/2.4.58 (Ubuntu) System : Linux aries 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : www-data ( 33) PHP Version : 8.1.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/patientapps_support/modules/pkpCore/model/ |
Upload File : |
<?php
// define points in time for an event
class Schedule {
const SUN = 0;
const MON = 1;
const TUE = 2;
const WED = 3;
const THU = 4;
const FRI = 5;
const SAT = 6;
private $interval = FALSE;
private $dow = []; // what days of the week should a task be run
private $weekly = FALSE;
private $monthly = FALSE;
// private $daily = FALSE; // daily is assumed
private $hourly = FALSE;
private $at = FALSE;
private $tz = 'UTC';
private $between = FALSE;
private $between_not = FALSE;
private $callback = FALSE;
public function timezone($x = 'UTC') { // defaults to utc
// evaluate the tz here, store a delta?
$this->tz = $x;
}
// Run the task every x minutes
// unlike linux crontab, this is not based on the minute of the hour, but from 1-jan 1980
// so "every 7 minutes" would be called about 205 times per day (60min * 24h / 7min)
public function everyXMinutes() {
if (func_num_args()) {
$this->interval = func_get_arg(0);
return $this;
}
return $this->interval;
}
public function monthly($day) { // day = -1 for last day of month
if ($this->monthly === FALSE) {
$this->monthly = [];
}
$this->monthly[$day] = 1; // then add specific time: at()
ksort($this->monthly);
return $this;
}
private function _timeToMinutes($hhmm) { // must be 24hr format
list($h, $m) = explode(':', $hhmm . ':');
$h = intval($h, 10);
if ($h < 0) $h = 0;
if ($h > 23) $h = 23;
$m = intval($m, 10);
if ($m < 0) $m = 0;
if ($m > 59) $m = 59;
return $h * 60 + $m;
}
// specific times with the chosen day => monthly(15)->at('13:00', '13:13')->at('15:00')->at(['15:30', '15:31'])
// must be 24hr format: hh:mm
//(does not make sense when used with Between and NotBetween, nor does it make sense if everyXMinutes() is used )
public function at() {
$c = func_num_args();
if ($c > 1) {
$list = func_get_args();
} elseif ($c == 1) {
$list = func_get_arg(0);
if (!is_array($list)) $list = [$list];
} else {
return $this;
}
foreach($list as &$item) {
$item = $this->_timeToMinutes($item);
}
if ($this->at === FALSE) $this->at = [];
$this->at = $this->at + $list;
sort($this->at);
return $this;
}
public function between($time1, $time2) { // if $time1 > $time2 then assumes: not between($time2, $time1)
$minutes1 = $this->_timeToMinutes($time1);
$minutes2 = $this->_timeToMinutes($time2);
if ($minutes1 > $minutes2) return $this->NotBetween($time2, $time1);
$this->between = [$minutes1, $minutes2];
return $this;
}
public function notbetween($time1, $time2) { // if $time1 > $time2 then assumes: not between($time2, $time1)
$minutes1 = $this->_timeToMinutes($time1);
$minutes2 = $this->_timeToMinutes($time2);
if ($minutes1 > $minutes2) return $this->Between($time2, $time1);
$this->between_not = [$minutes1, $minutes2];
return $this;
}
public function sundays() {
$this->weekly = TRUE;
$this->dow[self::SUN] = 1;
return $this;
}
public function mondays() {
$this->weekly = TRUE;
$this->dow[self::MON] = 1;
return $this;
}
public function tuesdays() {
$this->weekly = TRUE;
$this->dow[self::TUE] = 1;
return $this;
}
public function wednesdays() {
$this->weekly = TRUE;
$this->dow[self::WED] = 1;
return $this;
}
public function thursdays() {
$this->weekly = TRUE;
$this->dow[self::THU] = 1;
return $this;
}
public function fridays() {
$this->weekly = TRUE;
$this->dow[self::FRI] = 1;
return $this;
}
public function saturdays() {
$this->weekly = TRUE;
$this->dow[self::SAT] = 1;
return $this;
}
public function weekdays() {
$this->weekly = TRUE;
$this->dow[self::MON] = 1;
$this->dow[self::TUE] = 1;
$this->dow[self::WED] = 1;
$this->dow[self::THU] = 1;
$this->dow[self::FRI] = 1;
return $this;
}
public function hourly($minute = 0) { // run hourly at :minute
$this->hourly = $minute;
return $this;
}
// Required field - specify the callback function
public function Execute() {
if (func_num_args()) {
$this->callback = func_get_arg(0);
return $this;
}
return $this->callback;
}
private function get_topmost_script() {
$backtrace = debug_backtrace(
defined('DEBUG_BACKTRACE_IGNORE_ARGS')
? DEBUG_BACKTRACE_IGNORE_ARGS
: FALSE);
$top_frame = array_pop($backtrace);
return $top_frame['file'];
}
// return event identifier, based on $callback
public function ID() {
$salt = '';
if (is_array($this->callback)) {
$salt = get_class($this->callback[0]) . '->' . $this->callback[1];
}
if ($salt == '') $salt = $this->get_topmost_script(); // get the parent file
return sha1($salt);
}
// return start time of current event, or false if it is not now.
public function EventTime($now) {
// set timezone
$current = $this->_timeToArray($now);
$next_event = FALSE;
if ($this->interval !== FALSE) {
$next_event = $this->_nextInterval($current);
} elseif ($this->hourly !== FALSE) {
$next_event = $this->_getHourly($current);
}
if ($this->weekly) {
$dow = $next_event['dow'];
if (!isset($this->dow[$dow])) return FALSE; // wrong day
}
if ($this->monthly !== FALSE) {
$ok = FALSE;
if (isset($this->monthly[$next_event['d']])) $ok = TRUE;
if ($next_event['d'] == $next_event['dim'] && isset($this->monthly[-1])) $ok = TRUE;
if (!$ok) return FALSE; // not on any of the specific days of the month
}
$minutes = $next_event['h'] * 60 + $next_event['i'];
// if Between range specified, and not in range then return FALSE; "not at this time"
if ($this->between !== FALSE) {
if ($minutes < $this->between[0] || $minutes > $this->between[1]) return FALSE;
}
// if not Between range specified, and in range then return FALSE;
if ($this->between_not !== FALSE) {
if ($minutes >= $this->between[0] && $minutes <= $this->between[1]) return FALSE;
}
// specific times?
if (count($this->at)) {
if (!$this->_checkSpecificTimes($minutes)) return FALSE;
}
return $next_event === FALSE ? FALSE : $next_event['time'];
}
private function _getFirstMatchingDate($current) {
$day = $current['d'];
$limit = 12; // don't look more than 12 months in advance
if ($this->monthly !== FALSE) {
$min = $day;
do {
$suitable_days = $this->monthly;
$dim = $current['dim'];
if (isset($suitable_days[-1])) {
unset($suitable_days[-1]);
$suitable_days[$dim] = 1;
}
// find the day of the month that on/after the current day
$ok = FALSE;
foreach($this->monthly as $day => $filler) {
if (($min !== FALSE && $min < $day) || ($day > $dim)) continue;
$ok = TRUE;
break;
}
// if we have a good DOM, make sure it is also a good DOW
if ($this->weekly && $ok) {
$tempdate = $current;
$tempdate['d'] = $day;
$this->_updateEventTime($tempdate);
$dow = $tempdate['dow'];
if (empty($this->dow[$dow])) $ok = FALSE;
}
if (!$ok) { // move on to next month
$limit--;
if (!$limit) return FALSE; // unable to find suitable day within the next 12 months
$this->_nextMonth($current);
}
$min = FALSE; // all dates are ok on future months
} while (!$ok);
} elseif ($this->weekly) {
// at least one day of the week should be suitable
for($i = 0; $i < 7; $i++) {
$dow = $current['dow'];
if (!empty($this->dow[$dow])) break;
$this->_NextDay($current);
}
$day = $current['d'];
}
$dt = gmmktime(0, 0, 0, $current['m'], $day, $current['y']);
return $dt;
}
// what time should the next event run?
public function NextEvent($now) {
$current = $this->_timeToArray($now);
$next_event = FALSE;
// use between and not between to get list of ranges within that day
$ranges = $this->_between_ranges();
// find the first time >= now()
for($i = 0; $i < 2; $i++) { // today or tomorrow
if ($this->weekly || $this->monthly !== FALSE) {
$next_event = $this->_getFirstMatchingDate($current);
$tomorrow = strtotime('+ 1 day', $current['mid']);
if ($next_event >= $tomorrow) {
$current = $this->_timeToArray($next_event); // we have moved on to a day in the future
}
} else {
$next_event = gmmktime(0, 0, 0, $current['m'], $current['d'], $current['y']);
}
if ($this->at !== FALSE) {
foreach($this->at as $marker) {
$time = $next_event + $marker * 60;
if ($time >= $now) return $time;
}
// if interval used, get next valid time
// return first valid time in Between ranges
} elseif ($this->interval !== FALSE) {
$found = $this->_nextInterval_Range($current, $ranges);
if ($found !== FALSE) return $found;
} elseif ($this->hourly !== FALSE) {
$found = $this->_getHourly_Range($current, $ranges);
if ($found !== FALSE) return $found;
}
$this->_NextDay($current);
}
return FALSE;
}
private function _removeSlice(&$res, $slice) {
foreach($res as $index => &$timeslot) {
if ($slice[0] <= $timeslot[0] && $slice[1] >= $timeslot[1]) { // time completely covers slice - remove it
unset($res[$index]);
} else if ($slice[0] >= $timeslot[0] && $slice[1] <= $timeslot[1]) { // time completely within this slice - make a hole
$res[] = [$slice[1], $timeslot[1]];
$timeslot[1] = $slice[0];
return;
} elseif ($slice[0] >= $timeslot[0] && $slice[0] <= $timeslot[1]) { // start time within this slice, trim end time
$timeslot[1] = $slice[0];
} elseif ($slice[1] >= $timeslot[0] && $slice[1] <= $timeslot[1]) { // end time within this slice, trim start time
$timeslot[0] = $slice[1];
}
}
}
// return a list of segments where time is suitable
private function _between_ranges() {
$result = [];
if ($this->between === FALSE) {
$result[] = [0, 60 * 24 - 1];
} else {
$result[] = $this->between;
}
if ($this->between_not !== FALSE) {
$this->_removeSlice($result, $this->between_not);
}
return $result;
}
private function _checkSpecificTimes($minutes) {
return in_array($minutes, $this->at);
}
private function _timeToArray($now) {
$current_time = time(); // get time current time
// adjust for Event timezone offset
list($dd,$dow,$mm,$hh,$ii,$ss,$dim,$yy) = explode(',', gmdate('j,w,n,G,i,s,t,Y', $current_time));
$now -= intval($ss, 10);
$node = [
'time' => $now,
'd' => intval($dd, 10),
'dow' => $dow, // day of week. 0 = Sunday
'dim' => $dim, // days in month
'm' => $mm,
'h' => $hh,
'i' => intval($ii, 10),
's' => intval($ss, 10),
'y' => $yy,
];
$node['ofs'] = $node['h'] * 60 + $node['i']; // minutes past midnight
$node['mid'] = $now - 60 * $node['ofs']; // midnight
return $node;
}
private function _updateEventTime(&$event) {
$event['time'] = mktime($event['h'], $event['i'], 0, $event['m'], $event['d'], $event['y']);
list($event['dow'],$event['dim']) = explode(',', gmdate('w,t', $event['time']));
$event['ofs'] = $event['h'] * 60 + $event['i']; // minutes past midnight
$event['mid'] = $event['time'] - 60 * $event['ofs']; // midnight
}
private function _nextDay(&$event) {
$event['d']++;
$event['h'] = $event['i'] = 0;
if ($event['d'] > $event['dim']) {
$this->_nextMonth($event);
} else {
$this->_updateEventTime($event);
}
}
private function _nextMonth(&$event) {
$event['m']++;
$event['d'] -= $event['dim'];
if ($event['m'] > 12) {
$event['m'] = 1;
$event['y']++;
}
$this->_updateEventTime($event);
}
private function _normalize(&$event) {
while($event['i'] > 59) {
$event['h']++;
$event['i'] -= 60;
}
while($event['h'] > 23) {
$event['d']++;
$event['h'] -= 24;
}
while($event['d'] > $event['dim']) {
$this->_nextMonth($event);
}
while($event['m'] > 12) { //bug: won't handle Feb and leap years
$event['m'] -= 12;
$event['y']++;
}
}
private function _nextInterval($next_event) {
$since = intval($next_event['time'] / 60) % $this->interval; // how many minutes since last event?
if (!$since) return $next_event; // now is good :)
$delta_minutes = $this->interval - $since; // minutes to next interval
$next_event['i'] += $delta_minutes;
$this->_normalize($next_event);
$this->_updateEventTime($next_event);
return $next_event;
}
// determine the next Interval event that falls within $range
private function _nextInterval_Range($next_event, $range) {
foreach($range as $timeslot) {
$first = $this->_getFirstIntervalInTimeSlot($next_event, $timeslot);
if ($first !== FALSE) return $first;
}
return FALSE;
}
private function _getHourly($next_event) {
$current_minute = $next_event['i'];
$next_event['i'] = $this->hourly;
if ($current_minute > $this->hourly) {
$next_event['h']++;
$this->_normalize($next_event);
}
$this->_updateEventTime($next_event);
return $next_event;
}
private function _getHourly_range($next_event, $range) {
foreach($range as $timeslot) {
$first = $this->_getFirstHourlyInTimeSlot($next_event, $timeslot);
if ($first !== FALSE) return $first;
}
return FALSE;
}
// get the time of the next event, if it falls within the timeslot
private function _getFirstIntervalInTimeSlot($next_event, $timeslot) {
$end = $next_event['mid'] + $timeslot[1] * 60;
if ($next_event['time'] > $end) return FALSE; // this timeslot has expired - ignore it
$start = $next_event['mid'] + $timeslot[0] * 60;
if ($next_event['time'] > $start) $start = $next_event['time'];
$since = intval($start / 60) % $this->interval;
if (!$since) return $start; // now is good
$delta_minutes = $this->interval - $since; // minutes to next interval
$event_time = $start + $delta_minutes * 60;
return $event_time > $end ? FALSE : $event_time; // next interval does not occur in this timeslot
}
// get the time of the next event, if it falls within the timeslot
private function _getFirstHourlyInTimeSlot($next_event, $timeslot) {
$end = $next_event['mid'] + $timeslot[1] * 60;
if ($next_event['time'] > $end) return FALSE; // this timeslot has expired - ignore it
$start = $next_event['mid'] + $timeslot[0] * 60;
while ($next_event['time'] < $start) {
$next_event['time']+= 3600;
$next_event['h']++;
}
$event_time = $next_event['h'] * 60 + $this->hourly;
$event_time = $next_event['mid'] + $event_time * 60;
if ($next_event['i'] >= $this->hourly) { // passed desired minute, so try next hour
$event_time += 3600;
}
return $event_time > $end ? FALSE : $event_time; // next interval does not occur in this timeslot
}
public function __toString() {
if (!is_callable($this->callback)) return '(inactive)';
$next_event = '';
if (is_array($this->callback)) {
$classname = get_class($this->callback[0]) . '->' . $this->callback[1];
$next_event .= $classname;
} else {
$next_event .= "(unknown callback)";
}
$next = $this->nextEvent(time());
$next = $next === FALSE ? 'Unknown' : gmdate('D, Y-m-d H:i:s \(\U\T\C\)', $next);
$next_event .= ', next event: ' . $next;
return $next_event;
}
}
/*
->cron('* * * * *'); Run the task on a custom Cron schedule
->hourly(); Run the task every hour
>between('8:00', '17:00');
->hourlyAt(17); Run the task every hour at 17 mins past the hour
//->daily(); Run the task every day at midnight
//->dailyAt('13:00'); Run the task every day at 13:00
->twiceDaily(1, 13); Run the task daily at 1:00 & 13:00
//->weekly(); Run the task every week (not used.)
->between($start, $end); Limit the task to run between start and end times
->when(Closure); Limit the task based on a truth test
->unlessBetween('23:00', '4:00');
->between('7:00', '22:00');
$schedule->command('emails:send')->daily()->when(function () {
return true;
});
->withoutOverlapping();
->onOneServer();
->sendOutputTo($filePath); >appendOutputTo($filePath); >emailOutputTo('foo@example.com');
->before(function () {
// Task is about to start...
})
->after(function () {
// Task is complete...
});
->pingBefore($url)
->thenPing($url);
->monthly(); Run the task every month
->monthlyOn(4, '15:00'); Run the task every month on the 4th at 15:00
->quarterly(); Run the task every quarter
->yearly(); Run the task every year
->timezone('America/New_York'); Set the timezone
*/