00001 <?php
00002
00015
00016
00017 import('classes.plugins.GenericPlugin');
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 class AcronPlugin extends GenericPlugin {
00029
00030 function isSitePlugin() {
00031
00032 return true;
00033 }
00034
00035 function register($category, $path) {
00036 if (!Config::getVar('general', 'installed')) return false;
00037 if (parent::register($category, $path)) {
00038
00039 $this->addLocaleData();
00040 $this->parseCrontab();
00041
00042 HookRegistry::register('LoadHandler',array(&$this, 'callback'));
00043
00044 return true;
00045 }
00046 return false;
00047 }
00048
00049 function callback($hookName, $args) {
00050 $isEnabled = $this->getSetting(0, 0, 'enabled');
00051 if($isEnabled) {
00052 $taskDao =& DAORegistry::getDao('ScheduledTaskDAO');
00053
00054
00055 $scheduledTasks = $this->getSetting(0, 0, 'crontab');
00056 if(!$scheduledTasks) {
00057 $this->parseCrontab();
00058 $scheduledTasks = $this->getSetting(0, 0, 'crontab');
00059 }
00060
00061 $tasks = $this->getSetting(0, 0, 'crontab');
00062
00063 foreach($tasks as $task) {
00064
00065 $lastRuntime = $taskDao->getLastRunTime($task['className']);
00066
00067 if (isset($task['frequency'])) {
00068 $canExecute = $this->checkFrequency($task['className'], $task['frequency'], $lastRuntime);
00069 } else {
00070
00071
00072 $canExecute = true;
00073 }
00074
00075 if ($canExecute) {
00076
00077 $className = $task['className'];
00078
00079 $pos = strrpos($className, '.');
00080 if ($pos === false) {
00081 $baseClassName = $className;
00082 } else {
00083 $baseClassName = substr($className, $pos+1);
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093 $taskDao->updateLastRunTime($className, $lastRuntime);
00094
00095
00096 import($className);
00097 $task = new $baseClassName($args);
00098 $task->execute();
00099 }
00100 }
00101 }
00102
00103 return false;
00104 }
00105
00106
00107
00108
00109 function parseCrontab() {
00110 $xmlParser = new XMLParser();
00111
00112
00113 $tree = $xmlParser->parse(Config::getVar('general', 'registry_dir') . '/scheduledTasks.xml');
00114
00115 if (!$tree) {
00116 $xmlParser->destroy();
00117
00118
00119 fatalError('Error parsing scheduled tasks XML.');
00120 }
00121
00122 $tasks = array();
00123
00124 foreach ($tree->getChildren() as $task) {
00125 $frequency = $task->getChildByName('frequency');
00126
00127 $args = array();
00128 $index = 0;
00129 while(($arg = $task->getChildByName('arg', $index)) != null) {
00130 array_push($args, $arg->getValue());
00131 $index++;
00132 }
00133
00134 $tasks[] = array(
00135 'className' => $task->getAttribute('class'),
00136 'frequency' => $frequency ? $frequency->getAttributes() : null,
00137 'args' => $args
00138 );
00139 }
00140
00141 $xmlParser->destroy();
00142
00143
00144 $this->updateSetting(0, 0, 'crontab', $tasks, 'object');
00145 }
00146
00154 function checkFrequency($className, $frequency, $lastRunTime) {
00155 $isValid = true;
00156
00157
00158 if (isset($frequency['dayofweek'])) {
00159 $isValid = $this->isInRange($frequency['dayofweek'], (int)date('w'), $lastRunTime, 'day', strtotime('-1 week'));
00160 }
00161
00162 if ($isValid) {
00163
00164 if (isset($frequency['month'])) {
00165 $isValid = $this->isInRange($frequency['month'], (int)date('n'), $lastRunTime, 'month', strtotime('-1 year'));
00166 }
00167 }
00168
00169 if ($isValid) {
00170
00171 if (isset($frequency['day'])) {
00172 $isValid = $this->isInRange($frequency['day'], (int)date('j'), $lastRunTime, 'day', strtotime('-1 month'));
00173 }
00174 }
00175
00176 if ($isValid) {
00177
00178 if (isset($frequency['hour'])) {
00179 $isValid = $this->isInRange($frequency['hour'], (int)date('G'), $lastRunTime, 'hour', strtotime('-1 day'));
00180 }
00181 }
00182
00183 if ($isValid) {
00184
00185 if (isset($frequency['minute'])) {
00186 $isValid = $this->isInRange($frequency['minute'], (int)date('i'), $lastRunTime, 'min', strtotime('-1 hour'));
00187 }
00188 }
00189
00190 return $isValid;
00191 }
00192
00202 function isInRange($rangeStr, $currentValue, $lastTimestamp, $timeCompareStr, $cutoffTimestamp) {
00203 $isValid = false;
00204 $rangeArray = explode(',', $rangeStr);
00205
00206 if ($cutoffTimestamp > $lastTimestamp) {
00207
00208 $isValid = true;
00209 }
00210
00211 for ($i = 0, $count = count($rangeArray); !$isValid && ($i < $count); $i++) {
00212 if ($rangeArray[$i] == '*') {
00213
00214 $isValid = true;
00215
00216 } if (is_numeric($rangeArray[$i])) {
00217
00218 $isValid = ($currentValue == (int)$rangeArray[$i]);
00219
00220 } else if (preg_match('/^(\d*)\-(\d*)$/', $rangeArray[$i], $matches)) {
00221
00222 $isValid = $this->isInNumericRange($currentValue, (int)$matches[1], (int)$matches[2]);
00223
00224 } else if (preg_match('/^(.+)\/(\d+)$/', $rangeArray[$i], $matches)) {
00225
00226 $skipRangeStr = $matches[1];
00227 $skipFactor = (int)$matches[2];
00228
00229 if ($skipRangeStr == '*') {
00230 $isValid = true;
00231
00232 } else if (preg_match('/^(\d*)\-(\d*)$/', $skipRangeStr, $matches)) {
00233 $isValid = $this->isInNumericRange($currentValue, (int)$matches[1], (int)$matches[2]);
00234 }
00235
00236 if ($isValid) {
00237
00238 $isValid = (strtotime("-$skipFactor $timeCompareStr") > $lastTimestamp);
00239 }
00240 }
00241 }
00242
00243 return $isValid;
00244 }
00245
00253 function isInNumericRange($value, $min, $max) {
00254 return ($value >= $min && $value <= $max);
00255 }
00256
00257 function getName() {
00258 return 'AcronPlugin';
00259 }
00260
00261 function getDisplayName() {
00262 return __('plugins.generic.acron.name');
00263 }
00264
00265 function getDescription() {
00266 return __('plugins.generic.acron.description');
00267 }
00268
00269 function getManagementVerbs() {
00270 $isEnabled = $this->getSetting(0, 0, 'enabled');
00271
00272 $verbs = array();
00273 $verbs[] = array(
00274 ($isEnabled?'disable':'enable'),
00275 __($isEnabled?'manager.plugins.disable':'manager.plugins.enable')
00276 );
00277 $verbs[] = array(
00278 'reload', __('plugins.generic.acron.reload')
00279 );
00280 return $verbs;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290 function manage($verb, $args, &$message) {
00291 switch ($verb) {
00292 case 'enable':
00293 $this->updateSetting(0, 0, 'enabled', true);
00294 $message = __('plugins.generic.acron.enabled');
00295 break;
00296 case 'disable':
00297 $this->updateSetting(0, 0, 'enabled', false);
00298 $message = __('plugins.generic.acron.disabled');
00299 break;
00300 case 'reload':
00301 $this->parseCrontab();
00302 }
00303 return false;
00304 }
00305 }
00306 ?>