| | |
| | | */ |
| | | |
| | | class cron { |
| | | |
| | | /**#@+ |
| | | |
| | | /**#@+ |
| | | * @access private |
| | | */ |
| | | private $_sMinute = ''; |
| | | private $_sHour = ''; |
| | | private $_sDay = ''; |
| | | private $_sMonth = ''; |
| | | private $_sWDay = ''; |
| | | private $_bParsed = false; |
| | | private $_iNextRun = null; |
| | | private $_aValidValues; |
| | | |
| | | public function __construct() { |
| | | // empty |
| | | $this->_sMinute = ''; |
| | | $this->_sHour = ''; |
| | | $this->_sDay = ''; |
| | | $this->_sMonth = ''; |
| | | $this->_sWDay = ''; |
| | | $this->_bParsed = false; |
| | | $this->_aValidValues = array('minute' => array(), |
| | | 'hour' => array(), |
| | | 'day' => array(), |
| | | 'month' => array(), |
| | | 'weekday' => array()); |
| | | } |
| | | |
| | | private function _calcValidValues() { |
| | | // minute field |
| | | $this->_aValidValues['minute'] = $this->_calcFieldValues('minute', $this->_sMinute); |
| | | $this->_aValidValues['hour'] = $this->_calcFieldValues('hour', $this->_sHour); |
| | | $this->_aValidValues['day'] = $this->_calcFieldValues('day', $this->_sDay); |
| | | $this->_aValidValues['month'] = $this->_calcFieldValues('month', $this->_sMonth); |
| | | $this->_aValidValues['weekday'] = $this->_calcFieldValues('weekday', $this->_sWDay); |
| | | $this->_bParsed = true; |
| | | } |
| | | |
| | | private function _calcFieldValues($sField, $sValue) { |
| | | global $app; |
| | | |
| | | $aValidValues = array(); |
| | | |
| | | // global checks |
| | | $iFrom = 0; |
| | | $iTo = 0; |
| | | switch($sField) { |
| | | case 'minute': |
| | | $iTo = 59; |
| | | break; |
| | | case 'hour': |
| | | $iTo = 23; |
| | | break; |
| | | case 'day': |
| | | $iFrom = 1; |
| | | $iTo = 31; |
| | | break; |
| | | case 'month': |
| | | $sValue = strtr($sValue, array('JAN' => 1, |
| | | 'FEB' => 2, |
| | | 'MAR' => 3, |
| | | 'APR' => 4, |
| | | 'MAY' => 5, |
| | | 'JUN' => 6, |
| | | 'JUL' => 7, |
| | | 'AUG' => 8, |
| | | 'SEP' => 9, |
| | | 'OCT' => 10, |
| | | 'NOV' => 11, |
| | | 'DEC' => 12) |
| | | ); |
| | | $iFrom = 1; |
| | | $iTo = 12; |
| | | break; |
| | | case 'weekday': |
| | | $sValue = strtr($sValue, array('SUN' => 0, |
| | | 'MON' => 1, |
| | | 'TUE' => 2, |
| | | 'WED' => 3, |
| | | 'THU' => 4, |
| | | 'FRI' => 5, |
| | | 'SAT' => 6, |
| | | '7' => 0) |
| | | ); |
| | | $iTo = 6; |
| | | break; |
| | | } |
| | | $aParts = explode(',', $sValue); |
| | | for($a = 0; $a < count($aParts); $a++) { |
| | | $sValue = $aParts[$a]; |
| | | $iValue = $app->functions->intval($sValue); |
| | | |
| | | if($sValue === '*') { |
| | | // everything is valid |
| | | for($i = $iFrom; $i <= $iTo; $i++) { |
| | | $aValidValues[] = $i; |
| | | } |
| | | break; // no need to go any further |
| | | } elseif((string)$iValue == $sValue) { |
| | | if($iValue >= $iFrom && $iValue <= $iTo) $aValidValues[] = $iValue; |
| | | } elseif(preg_match('/^([0-9]+)-([0-9]+)(\/([1-9][0-9]*))?$/', $sValue, $aMatch)) { |
| | | if($aMatch[1] < $iFrom) $aMatch[1] = $iFrom; |
| | | if($aMatch[2] > $iTo) $aMatch[2] = $iTo; |
| | | if(isset($aMatch[3])) { |
| | | for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) { |
| | | if(($i - $aMatch[1]) % $aMatch[4] == 0) $aValidValues[] = $i; |
| | | } |
| | | } else { |
| | | for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) $aValidValues[] = $i; |
| | | } |
| | | } elseif(preg_match('/^\*\/([1-9][0-9]*)$/', $sValue, $aMatch)) { |
| | | for($i = $iFrom; $i <= $iTo; $i++) { |
| | | if($i % $aMatch[1] == 0) $aValidValues[] = $i; |
| | | } |
| | | } |
| | | } |
| | | |
| | | $aValidValues = array_unique($aValidValues); |
| | | sort($aValidValues); |
| | | |
| | | return $aValidValues; |
| | | } |
| | | |
| | | /**#@-*/ |
| | | |
| | | /** |
| | | * Set the cron field values |
| | | * |
| | | * @param string $sMinute the minute field value |
| | | * @param string $sHour the hour field value |
| | | * @param string $sDay the day field value |
| | | * @param string $sWDay the weekday field value |
| | | * @param string $sMonth the month field value |
| | | */ |
| | | public function setCronFields($sMinute = '*', $sHour = '*', $sDay = '*', $sMonth = '*', $sWDay = '*') { |
| | | $this->_sMinute = $sMinute; |
| | | $this->_sHour = $sHour; |
| | | $this->_sDay = $sDay; |
| | | $this->_sMonth = $sMonth; |
| | | $this->_sWDay = $sWDay; |
| | | $this->_bParsed = false; |
| | | } |
| | | |
| | | /** |
| | | * Parse a line of a cron and set the internal field values |
| | | * |
| | | * @param string $sLine cron line |
| | | */ |
| | | public function parseCronLine($sLine) { |
| | | $aFields = preg_split('/[ \t]+/', trim($sLine)); |
| | | for($i = 0; $i < 5; $i++) { |
| | | if(!isset($aFields[$i])) $aFields[$i] = '*'; |
| | | } |
| | | if($aFields[0] == '@yearly' || $aFields[0] == '@annually') $aFields = array(0, 0, 1, 1, '*'); |
| | | elseif($aFields[0] == '@monthly') $aFields = array(0, 0, 1, '*', '*'); |
| | | elseif($aFields[0] == '@weekly') $aFields = array(0, 0, '*', '*', 0); |
| | | elseif($aFields[0] == '@daily' || $aFields[0] == '@midnight') $aFields = array(0, 0, '*', '*', '*'); |
| | | elseif($aFields[0] == '@hourly') $aFields = array(0, '*', '*', '*', '*'); |
| | | |
| | | $this->setCronFields($aFields[0], $aFields[1], $aFields[2], $aFields[3], $aFields[4]); |
| | | } |
| | | |
| | | public function getNextRun($vDate) { |
| | | global $app; |
| | | |
| | | $iTimestamp = ISPConfigDatetime::to_timestamp($vDate); |
| | | if($iTimestamp === false) return $iTimestamp; |
| | | |
| | | if($this->_bParsed == false) $this->_calcValidValues(); |
| | | |
| | | // get the field values for the given Date. |
| | | list($iMinute, $iHour, $iDay, $iWDay, $iMonth, $iYear) = explode(':', ISPConfigDateTime::to_string($vDate, 'custom:%M:%H:%d:%w:%m:%Y')); |
| | | |
| | | $bValid = false; |
| | | $iStartYear = $iYear; |
| | | while($bValid == false) { |
| | | $iCurMinute = $this->_getNextValue('minute', $iMinute, true); |
| | | $iCurHour = $this->_getNextValue('hour', $iHour, true); |
| | | $iCurDay = $this->_getNextValue('day', $iDay, true); |
| | | $iCurMonth = $this->_getNextValue('month', $iMonth, true); |
| | | $iCurWDay = $this->_getNextValue('weekday', $iWDay, true); |
| | | |
| | | $iNextMinute = $this->_getNextValue('minute', $iMinute); |
| | | $iNextHour = $this->_getNextValue('hour', $iHour); |
| | | $iNextDay = $this->_getNextValue('day', $iDay); |
| | | $iNextMonth = $this->_getNextValue('month', $iMonth); |
| | | $iNextWDay = $this->_getNextValue('weekday', $iWDay); |
| | | |
| | | if($iNextMinute > $iMinute && $iHour == $iCurHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) { |
| | | $iMinute = $iNextMinute; |
| | | } elseif($iNextHour > $iHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = $iNextHour; |
| | | } elseif($iNextDay > $iDay && ISPConfigDateTime::last_day($iMonth) >= $iNextDay && $iMonth == $iCurMonth) { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = reset($this->_aValidValues['hour']); |
| | | $iDay = $iNextDay; |
| | | } elseif($iNextMonth > $iMonth) { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = reset($this->_aValidValues['hour']); |
| | | $iDay = reset($this->_aValidValues['day']); |
| | | $iMonth = $iNextMonth; |
| | | } else { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = reset($this->_aValidValues['hour']); |
| | | $iDay = reset($this->_aValidValues['day']); |
| | | $iMonth = reset($this->_aValidValues['month']); |
| | | $iYear++; |
| | | } |
| | | |
| | | $ts = mktime($iHour, $iMinute, 0, $iMonth, $iDay, $iYear); |
| | | //print strftime('%d.%m.%Y (%A) %H:%M', $ts) . "\n"; |
| | | //var_dump($iCurMinute, $iCurHour, $iCurDay, $iCurMonth, $iCurWDay, '--', $iNextMinute, $iNextHour, $iNextDay, $iNextMonth, $iNextWDay); |
| | | if(ISPConfigDateTime::last_day($iMonth, $iYear) >= $iDay && in_array($app->functions->intval(strftime('%w', $ts)), $this->_aValidValues['weekday'], true) === true) { |
| | | $bValid = true; |
| | | } else { |
| | | if($iYear - $iStartYear > 5) { |
| | | if(LOG_PRIORITY <= PRIO_ERROR) $portal->log('No valid run dates for schedule ' . $this->_sMinute . ' ' . $this->_sHour . ' ' . $this->_sDay . ' ' . $this->_sMonth . ' ' . $this->_sWDay . ' in the next 5 years!', PRIO_ERROR, __FILE__, __LINE__); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | //var_dump($vDate, implode('-', array($iYear, $iMonth, $iDay, $iHour, $iNextMinute, 0)), $this->_sMinute, $this->_sHour, $this->_sDay, $this->_sWDay, $this->_sMonth, $this->_aValidValues); |
| | | return $iYear . '-' . $iMonth . '-' . $iDay . ' ' . $iHour . ':' . $iNextMinute . ':0'; |
| | | } |
| | | |
| | | private function _getNextValue($sField, $iValue, $bIncludeCurrent = false) { |
| | | if(!array_key_exists($sField, $this->_aValidValues)) return false; |
| | | |
| | | reset($this->_aValidValues[$sField]); |
| | | while(($cur = each($this->_aValidValues[$sField])) !== false) { |
| | | if($bIncludeCurrent == true && $cur['value'] >= $iValue) return $cur['value']; |
| | | elseif($cur['value'] > $iValue) return $cur['value']; |
| | | } |
| | | return reset($this->_aValidValues[$sField]); |
| | | } |
| | | private $_sMinute = ''; |
| | | private $_sHour = ''; |
| | | private $_sDay = ''; |
| | | private $_sMonth = ''; |
| | | private $_sWDay = ''; |
| | | private $_bParsed = false; |
| | | private $_iNextRun = null; |
| | | private $_aValidValues; |
| | | |
| | | public function __construct() { |
| | | // empty |
| | | $this->_sMinute = ''; |
| | | $this->_sHour = ''; |
| | | $this->_sDay = ''; |
| | | $this->_sMonth = ''; |
| | | $this->_sWDay = ''; |
| | | $this->_bParsed = false; |
| | | $this->_aValidValues = array('minute' => array(), |
| | | 'hour' => array(), |
| | | 'day' => array(), |
| | | 'month' => array(), |
| | | 'weekday' => array()); |
| | | } |
| | | |
| | | private function _calcValidValues() { |
| | | // minute field |
| | | $this->_aValidValues['minute'] = $this->_calcFieldValues('minute', $this->_sMinute); |
| | | $this->_aValidValues['hour'] = $this->_calcFieldValues('hour', $this->_sHour); |
| | | $this->_aValidValues['day'] = $this->_calcFieldValues('day', $this->_sDay); |
| | | $this->_aValidValues['month'] = $this->_calcFieldValues('month', $this->_sMonth); |
| | | $this->_aValidValues['weekday'] = $this->_calcFieldValues('weekday', $this->_sWDay); |
| | | $this->_bParsed = true; |
| | | } |
| | | |
| | | private function _calcFieldValues($sField, $sValue) { |
| | | global $app; |
| | | |
| | | $aValidValues = array(); |
| | | |
| | | // global checks |
| | | $iFrom = 0; |
| | | $iTo = 0; |
| | | switch($sField) { |
| | | case 'minute': |
| | | $iTo = 59; |
| | | break; |
| | | case 'hour': |
| | | $iTo = 23; |
| | | break; |
| | | case 'day': |
| | | $iFrom = 1; |
| | | $iTo = 31; |
| | | break; |
| | | case 'month': |
| | | $sValue = strtr($sValue, array('JAN' => 1, |
| | | 'FEB' => 2, |
| | | 'MAR' => 3, |
| | | 'APR' => 4, |
| | | 'MAY' => 5, |
| | | 'JUN' => 6, |
| | | 'JUL' => 7, |
| | | 'AUG' => 8, |
| | | 'SEP' => 9, |
| | | 'OCT' => 10, |
| | | 'NOV' => 11, |
| | | 'DEC' => 12) |
| | | ); |
| | | $iFrom = 1; |
| | | $iTo = 12; |
| | | break; |
| | | case 'weekday': |
| | | $sValue = strtr($sValue, array('SUN' => 0, |
| | | 'MON' => 1, |
| | | 'TUE' => 2, |
| | | 'WED' => 3, |
| | | 'THU' => 4, |
| | | 'FRI' => 5, |
| | | 'SAT' => 6, |
| | | '7' => 0) |
| | | ); |
| | | $iTo = 6; |
| | | break; |
| | | } |
| | | $aParts = explode(',', $sValue); |
| | | for($a = 0; $a < count($aParts); $a++) { |
| | | $sValue = $aParts[$a]; |
| | | $iValue = $app->functions->intval($sValue); |
| | | |
| | | if($sValue === '*') { |
| | | // everything is valid |
| | | for($i = $iFrom; $i <= $iTo; $i++) { |
| | | $aValidValues[] = $i; |
| | | } |
| | | break; // no need to go any further |
| | | } elseif((string)$iValue == $sValue) { |
| | | if($iValue >= $iFrom && $iValue <= $iTo) $aValidValues[] = $iValue; |
| | | } elseif(preg_match('/^([0-9]+)-([0-9]+)(\/([1-9][0-9]*))?$/', $sValue, $aMatch)) { |
| | | if($aMatch[1] < $iFrom) $aMatch[1] = $iFrom; |
| | | if($aMatch[2] > $iTo) $aMatch[2] = $iTo; |
| | | if(isset($aMatch[3])) { |
| | | for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) { |
| | | if(($i - $aMatch[1]) % $aMatch[4] == 0) $aValidValues[] = $i; |
| | | } |
| | | } else { |
| | | for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) $aValidValues[] = $i; |
| | | } |
| | | } elseif(preg_match('/^\*\/([1-9][0-9]*)$/', $sValue, $aMatch)) { |
| | | for($i = $iFrom; $i <= $iTo; $i++) { |
| | | if($i % $aMatch[1] == 0) $aValidValues[] = $i; |
| | | } |
| | | } |
| | | } |
| | | |
| | | $aValidValues = array_unique($aValidValues); |
| | | sort($aValidValues); |
| | | |
| | | return $aValidValues; |
| | | } |
| | | |
| | | /**#@-*/ |
| | | |
| | | /** |
| | | * Set the cron field values |
| | | * |
| | | * @param string $sMinute the minute field value |
| | | * @param string $sHour the hour field value |
| | | * @param string $sDay the day field value |
| | | * @param string $sWDay the weekday field value |
| | | * @param string $sMonth the month field value |
| | | */ |
| | | |
| | | |
| | | public function setCronFields($sMinute = '*', $sHour = '*', $sDay = '*', $sMonth = '*', $sWDay = '*') { |
| | | $this->_sMinute = $sMinute; |
| | | $this->_sHour = $sHour; |
| | | $this->_sDay = $sDay; |
| | | $this->_sMonth = $sMonth; |
| | | $this->_sWDay = $sWDay; |
| | | $this->_bParsed = false; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Parse a line of a cron and set the internal field values |
| | | * |
| | | * @param string $sLine cron line |
| | | */ |
| | | public function parseCronLine($sLine) { |
| | | $aFields = preg_split('/[ \t]+/', trim($sLine)); |
| | | for($i = 0; $i < 5; $i++) { |
| | | if(!isset($aFields[$i])) $aFields[$i] = '*'; |
| | | } |
| | | if($aFields[0] == '@yearly' || $aFields[0] == '@annually') $aFields = array(0, 0, 1, 1, '*'); |
| | | elseif($aFields[0] == '@monthly') $aFields = array(0, 0, 1, '*', '*'); |
| | | elseif($aFields[0] == '@weekly') $aFields = array(0, 0, '*', '*', 0); |
| | | elseif($aFields[0] == '@daily' || $aFields[0] == '@midnight') $aFields = array(0, 0, '*', '*', '*'); |
| | | elseif($aFields[0] == '@hourly') $aFields = array(0, '*', '*', '*', '*'); |
| | | |
| | | $this->setCronFields($aFields[0], $aFields[1], $aFields[2], $aFields[3], $aFields[4]); |
| | | } |
| | | |
| | | public function getNextRun($vDate) { |
| | | global $app; |
| | | |
| | | $iTimestamp = ISPConfigDatetime::to_timestamp($vDate); |
| | | if($iTimestamp === false) return $iTimestamp; |
| | | |
| | | if($this->_bParsed == false) $this->_calcValidValues(); |
| | | |
| | | // get the field values for the given Date. |
| | | list($iMinute, $iHour, $iDay, $iWDay, $iMonth, $iYear) = explode(':', ISPConfigDateTime::to_string($vDate, 'custom:%M:%H:%d:%w:%m:%Y')); |
| | | |
| | | $bValid = false; |
| | | $iStartYear = $iYear; |
| | | while($bValid == false) { |
| | | $iCurMinute = $this->_getNextValue('minute', $iMinute, true); |
| | | $iCurHour = $this->_getNextValue('hour', $iHour, true); |
| | | $iCurDay = $this->_getNextValue('day', $iDay, true); |
| | | $iCurMonth = $this->_getNextValue('month', $iMonth, true); |
| | | $iCurWDay = $this->_getNextValue('weekday', $iWDay, true); |
| | | |
| | | $iNextMinute = $this->_getNextValue('minute', $iMinute); |
| | | $iNextHour = $this->_getNextValue('hour', $iHour); |
| | | $iNextDay = $this->_getNextValue('day', $iDay); |
| | | $iNextMonth = $this->_getNextValue('month', $iMonth); |
| | | $iNextWDay = $this->_getNextValue('weekday', $iWDay); |
| | | |
| | | if($iNextMinute > $iMinute && $iHour == $iCurHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) { |
| | | $iMinute = $iNextMinute; |
| | | } elseif($iNextHour > $iHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = $iNextHour; |
| | | } elseif($iNextDay > $iDay && ISPConfigDateTime::last_day($iMonth) >= $iNextDay && $iMonth == $iCurMonth) { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = reset($this->_aValidValues['hour']); |
| | | $iDay = $iNextDay; |
| | | } elseif($iNextMonth > $iMonth) { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = reset($this->_aValidValues['hour']); |
| | | $iDay = reset($this->_aValidValues['day']); |
| | | $iMonth = $iNextMonth; |
| | | } else { |
| | | $iMinute = reset($this->_aValidValues['minute']); |
| | | $iHour = reset($this->_aValidValues['hour']); |
| | | $iDay = reset($this->_aValidValues['day']); |
| | | $iMonth = reset($this->_aValidValues['month']); |
| | | $iYear++; |
| | | } |
| | | |
| | | $ts = mktime($iHour, $iMinute, 0, $iMonth, $iDay, $iYear); |
| | | //print strftime('%d.%m.%Y (%A) %H:%M', $ts) . "\n"; |
| | | //var_dump($iCurMinute, $iCurHour, $iCurDay, $iCurMonth, $iCurWDay, '--', $iNextMinute, $iNextHour, $iNextDay, $iNextMonth, $iNextWDay); |
| | | if(ISPConfigDateTime::last_day($iMonth, $iYear) >= $iDay && in_array($app->functions->intval(strftime('%w', $ts)), $this->_aValidValues['weekday'], true) === true) { |
| | | $bValid = true; |
| | | } else { |
| | | if($iYear - $iStartYear > 5) { |
| | | if(LOG_PRIORITY <= PRIO_ERROR) $portal->log('No valid run dates for schedule ' . $this->_sMinute . ' ' . $this->_sHour . ' ' . $this->_sDay . ' ' . $this->_sMonth . ' ' . $this->_sWDay . ' in the next 5 years!', PRIO_ERROR, __FILE__, __LINE__); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | //var_dump($vDate, implode('-', array($iYear, $iMonth, $iDay, $iHour, $iNextMinute, 0)), $this->_sMinute, $this->_sHour, $this->_sDay, $this->_sWDay, $this->_sMonth, $this->_aValidValues); |
| | | return $iYear . '-' . $iMonth . '-' . $iDay . ' ' . $iHour . ':' . $iNextMinute . ':0'; |
| | | } |
| | | |
| | | private function _getNextValue($sField, $iValue, $bIncludeCurrent = false) { |
| | | if(!array_key_exists($sField, $this->_aValidValues)) return false; |
| | | |
| | | reset($this->_aValidValues[$sField]); |
| | | while(($cur = each($this->_aValidValues[$sField])) !== false) { |
| | | if($bIncludeCurrent == true && $cur['value'] >= $iValue) return $cur['value']; |
| | | elseif($cur['value'] > $iValue) return $cur['value']; |
| | | } |
| | | return reset($this->_aValidValues[$sField]); |
| | | } |
| | | |
| | | } |
| | | |
| | | ?> |