[2] | 1 | <?php |
---|
| 2 | /**************************************************************************\ |
---|
| 3 | * phpGroupWare API - Timed Asynchron Services for eGroupWare * |
---|
| 4 | * Written by Ralf Becker <RalfBecker@outdoor-training.de> * |
---|
| 5 | * Class for creating cron-job like timed calls of eGroupWare methods * |
---|
| 6 | * -------------------------------------------------------------------------* |
---|
| 7 | * This library is part of the eGroupWare API * |
---|
| 8 | * http://www.eGroupWare.org * |
---|
| 9 | * ------------------------------------------------------------------------ * |
---|
| 10 | * This program is free software; you can redistribute it and/or modify it * |
---|
| 11 | * under the terms of the GNU General Public License as published by the * |
---|
| 12 | * Free Software Foundation; either version 2 of the License, or (at your * |
---|
| 13 | * option) any later version. * |
---|
| 14 | \**************************************************************************/ |
---|
| 15 | |
---|
| 16 | |
---|
| 17 | /*! |
---|
| 18 | @class asyncservice |
---|
| 19 | @author Ralf Becker |
---|
| 20 | @copyright GPL - GNU General Public License |
---|
| 21 | @abstract The class implements a general eGW service to execute callbacks at a given time. |
---|
| 22 | @discussion see http://www.egroupware.org/wiki/TimedAsyncServices |
---|
| 23 | */ |
---|
| 24 | class asyncservice |
---|
| 25 | { |
---|
| 26 | var $public_functions = array( |
---|
| 27 | 'set_timer' => True, |
---|
| 28 | 'check_run' => True, |
---|
| 29 | 'cancel_timer' => True, |
---|
| 30 | 'read' => True, |
---|
| 31 | 'install' => True, |
---|
| 32 | 'installed' => True, |
---|
| 33 | 'last_check_run' => True |
---|
| 34 | ); |
---|
| 35 | var $php = ''; |
---|
| 36 | var $crontab = ''; |
---|
| 37 | var $db; |
---|
| 38 | var $db_table = 'phpgw_async'; |
---|
| 39 | var $debug = 0; |
---|
| 40 | |
---|
| 41 | /*! |
---|
| 42 | @function asyncservice |
---|
| 43 | @abstract constructor of the class |
---|
| 44 | */ |
---|
| 45 | function asyncservice() |
---|
| 46 | { |
---|
| 47 | $this->db = $GLOBALS['phpgw']->db; |
---|
| 48 | |
---|
| 49 | $this->cronline = PHPGW_SERVER_ROOT . '/phpgwapi/cron/asyncservices.php '.$GLOBALS['phpgw_info']['user']['domain']; |
---|
| 50 | |
---|
| 51 | $this->only_fallback = substr(php_uname(), 0, 7) == "Windows"; // atm cron-jobs dont work on win |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | /*! |
---|
| 55 | @function set_timer |
---|
| 56 | @abstract calculates the next run of the timer and puts that with the rest of the data in the db for later execution. |
---|
| 57 | @syntax set_timer($times,$id,$method,$data,$account_id=False) |
---|
| 58 | @param $times unix timestamp or array('min','hour','dow','day','month','year') with execution time. |
---|
| 59 | Repeated events are possible to shedule by setting the array only partly, eg. |
---|
| 60 | array('day' => 1) for first day in each month 0am or array('min' => '* /5', 'hour' => '9-17') |
---|
| 61 | for every 5mins in the time from 9am to 5pm. |
---|
| 62 | @param $id unique id to cancel the request later, if necessary. Should be in a form like |
---|
| 63 | eg. '<app><id>X' where id is the internal id of app and X might indicate the action. |
---|
| 64 | @param $method Method to be called via ExecMethod($method,$data). $method has the form |
---|
| 65 | '<app>.<class>.<public function>'. |
---|
| 66 | @param $data This data is passed back when the method is called. It might simply be an |
---|
| 67 | integer id, but it can also be a complete array. |
---|
| 68 | @param $account_id account_id, under which the methode should be called or False for the actual user |
---|
| 69 | @result False if $id already exists, else True |
---|
| 70 | */ |
---|
| 71 | function set_timer($times,$id,$method,$data,$account_id=False) |
---|
| 72 | { |
---|
| 73 | if (empty($id) || empty($method) || $this->read($id) || |
---|
| 74 | !($next = $this->next_run($times))) |
---|
| 75 | { |
---|
| 76 | return False; |
---|
| 77 | } |
---|
| 78 | if ($account_id === False) |
---|
| 79 | { |
---|
| 80 | $account_id = $GLOBALS['phpgw_info']['user']['account_id']; |
---|
| 81 | } |
---|
| 82 | $job = array( |
---|
| 83 | 'id' => $id, |
---|
| 84 | 'next' => $next, |
---|
| 85 | 'times' => $times, |
---|
| 86 | 'method' => $method, |
---|
| 87 | 'data' => $data, |
---|
| 88 | 'account_id' => $account_id |
---|
| 89 | ); |
---|
| 90 | $this->write($job); |
---|
| 91 | |
---|
| 92 | return True; |
---|
| 93 | } |
---|
| 94 | |
---|
| 95 | /*! |
---|
| 96 | @function next_run |
---|
| 97 | @abstract calculates the next execution time for $times |
---|
| 98 | @syntax next_run($times) |
---|
| 99 | @param $times unix timestamp or array('year'=>$year,'month'=>$month,'dow'=>$dow,'day'=>$day,'hour'=>$hour,'min'=>$min) |
---|
| 100 | with execution time. Repeated execution is possible to shedule by setting the array only partly, |
---|
| 101 | eg. array('day' => 1) for first day in each month 0am or array('min' => '/5', 'hour' => '9-17') |
---|
| 102 | for every 5mins in the time from 9am to 5pm. All not set units before the smallest one set, |
---|
| 103 | are taken into account as every possible value, all after as the smallest possible value. |
---|
| 104 | @param $debug if True some debug-messages about syntax-errors in $times are echoed |
---|
| 105 | @result a unix timestamp of the next execution time or False if no more executions |
---|
| 106 | */ |
---|
| 107 | function next_run($times,$debug=False) |
---|
| 108 | { |
---|
| 109 | if ($this->debug) |
---|
| 110 | { |
---|
| 111 | echo "<p>next_run("; print_r($times); ",'$debug')</p>\n"; |
---|
| 112 | $debug = True; // enable syntax-error messages too |
---|
| 113 | } |
---|
| 114 | $now = time(); |
---|
| 115 | |
---|
| 116 | // $times is unix timestamp => if it's not expired return it, else False |
---|
| 117 | // |
---|
| 118 | if (!is_array($times)) |
---|
| 119 | { |
---|
| 120 | $next = (int)$times; |
---|
| 121 | |
---|
| 122 | return $next > $now ? $next : False; |
---|
| 123 | } |
---|
| 124 | // If an array is given, we have to enumerate the possible times first |
---|
| 125 | // |
---|
| 126 | $units = array( |
---|
| 127 | 'year' => 'Y', |
---|
| 128 | 'month' => 'm', |
---|
| 129 | 'day' => 'd', |
---|
| 130 | 'dow' => 'w', |
---|
| 131 | 'hour' => 'H', |
---|
| 132 | 'min' => 'i' |
---|
| 133 | ); |
---|
| 134 | $max_unit = array( |
---|
| 135 | 'min' => 59, |
---|
| 136 | 'hour' => 23, |
---|
| 137 | 'dow' => 6, |
---|
| 138 | 'day' => 31, |
---|
| 139 | 'month' => 12, |
---|
| 140 | 'year' => date('Y')+10 // else */[0-9] would never stop returning numbers |
---|
| 141 | ); |
---|
| 142 | $min_unit = array( |
---|
| 143 | 'min' => 0, |
---|
| 144 | 'hour' => 0, |
---|
| 145 | 'dow' => 0, |
---|
| 146 | 'day' => 1, |
---|
| 147 | 'month' => 1, |
---|
| 148 | 'year' => date('Y') |
---|
| 149 | ); |
---|
| 150 | |
---|
| 151 | // get the number of the first and last pattern set in $times, |
---|
| 152 | // as empty patterns get enumerated before the the last pattern and |
---|
| 153 | // get set to the minimum after |
---|
| 154 | // |
---|
| 155 | $n = $first_set = $last_set = 0; |
---|
| 156 | foreach($units as $u => $date_pattern) |
---|
| 157 | { |
---|
| 158 | ++$n; |
---|
| 159 | if (isset($times[$u])) |
---|
| 160 | { |
---|
| 161 | $last_set = $n; |
---|
| 162 | |
---|
| 163 | if (!$first_set) |
---|
| 164 | { |
---|
| 165 | $first_set = $n; |
---|
| 166 | } |
---|
| 167 | } |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | // now we go through all units and enumerate all patterns and not set patterns |
---|
| 171 | // (as descript above), enumerations are arrays with unit-values as keys |
---|
| 172 | // |
---|
| 173 | $n = 0; |
---|
| 174 | foreach($units as $u => $date_pattern) |
---|
| 175 | { |
---|
| 176 | ++$n; |
---|
| 177 | if ($this->debug) { echo "<p>n=$n, $u: isset(times[$u]="; print_r($times[$u]); echo ")=".(isset($times[$u])?'True':'False')."</p>\n"; } |
---|
| 178 | if (isset($times[$u])) |
---|
| 179 | { |
---|
| 180 | $time = explode(',',$times[$u]); |
---|
| 181 | |
---|
| 182 | $times[$u] = array(); |
---|
| 183 | |
---|
| 184 | foreach($time as $t) |
---|
| 185 | { |
---|
| 186 | if (strstr($t,'-') !== False && strstr($t,'/') === False) |
---|
| 187 | { |
---|
| 188 | list($min,$max) = $arr = explode('-',$t); |
---|
| 189 | |
---|
| 190 | if (count($arr) != 2 || !is_numeric($min) || !is_numeric($max) || $min > $max) |
---|
| 191 | { |
---|
| 192 | if ($debug) echo "<p>Syntax error in $u='$t', allowed is 'min-max', min <= max, min='$min', max='$max'</p>\n"; |
---|
| 193 | |
---|
| 194 | return False; |
---|
| 195 | } |
---|
| 196 | for ($i = (int)$min; $i <= $max; ++$i) |
---|
| 197 | { |
---|
| 198 | $times[$u][$i] = True; |
---|
| 199 | } |
---|
| 200 | } |
---|
| 201 | else |
---|
| 202 | { |
---|
| 203 | if ($t == '*') $t = '*/1'; |
---|
| 204 | |
---|
| 205 | list($one,$inc) = $arr = explode('/',$t); |
---|
| 206 | |
---|
| 207 | if (!(is_numeric($one) && count($arr) == 1 || |
---|
| 208 | count($arr) == 2 && is_numeric($inc))) |
---|
| 209 | { |
---|
| 210 | if ($debug) echo "<p>Syntax error in $u='$t', allowed is a number or '{*|range}/inc', inc='$inc'</p>\n"; |
---|
| 211 | |
---|
| 212 | return False; |
---|
| 213 | } |
---|
| 214 | if (count($arr) == 1) |
---|
| 215 | { |
---|
| 216 | $times[$u][(int)$one] = True; |
---|
| 217 | } |
---|
| 218 | else |
---|
| 219 | { |
---|
| 220 | list($min,$max) = $arr = explode('-',$one); |
---|
| 221 | if (empty($one) || $one == '*') |
---|
| 222 | { |
---|
| 223 | $min = $min_unit[$u]; |
---|
| 224 | $max = $max_unit[$u]; |
---|
| 225 | } |
---|
| 226 | elseif (count($arr) != 2 || $min > $max) |
---|
| 227 | { |
---|
| 228 | if ($debug) echo "<p>Syntax error in $u='$t', allowed is '{*|min-max}/inc', min='$min',max='$max', inc='$inc'</p>\n"; |
---|
| 229 | return False; |
---|
| 230 | } |
---|
| 231 | for ($i = $min; $i <= $max; $i += $inc) |
---|
| 232 | { |
---|
| 233 | $times[$u][$i] = True; |
---|
| 234 | } |
---|
| 235 | } |
---|
| 236 | } |
---|
| 237 | } |
---|
| 238 | } |
---|
| 239 | elseif ($n < $last_set || $u == 'dow') // before last value set (or dow) => empty gets enumerated |
---|
| 240 | { |
---|
| 241 | for ($i = $min_unit[$u]; $i <= $max_unit[$u]; ++$i) |
---|
| 242 | { |
---|
| 243 | $times[$u][$i] = True; |
---|
| 244 | } |
---|
| 245 | } |
---|
| 246 | else // => after last value set => empty is min-value |
---|
| 247 | { |
---|
| 248 | $times[$u][$min_unit[$u]] = True; |
---|
| 249 | } |
---|
| 250 | } |
---|
| 251 | if ($this->debug) { echo "enumerated times=<pre>"; print_r($times); echo "</pre>\n"; } |
---|
| 252 | |
---|
| 253 | // now we have the times enumerated, lets find the first not expired one |
---|
| 254 | // |
---|
| 255 | $found = array(); |
---|
| 256 | while (!isset($found['min'])) |
---|
| 257 | { |
---|
| 258 | $future = False; |
---|
| 259 | |
---|
| 260 | foreach($units as $u => $date_pattern) |
---|
| 261 | { |
---|
| 262 | $unit_now = $u != 'dow' ? (int)date($date_pattern) : |
---|
| 263 | (int)date($date_pattern,mktime(12,0,0,$found['month'],$found['day'],$found['year'])); |
---|
| 264 | |
---|
| 265 | if (isset($found[$u])) |
---|
| 266 | { |
---|
| 267 | $future = $future || $found[$u] > $unit_now; |
---|
| 268 | if ($this->debug) echo "--> already have a $u = ".$found[$u].", future='$future'<br>\n"; |
---|
| 269 | continue; // already set |
---|
| 270 | } |
---|
| 271 | foreach($times[$u] as $unit_value => $nul) |
---|
| 272 | { |
---|
| 273 | switch($u) |
---|
| 274 | { |
---|
| 275 | case 'dow': |
---|
| 276 | $valid = $unit_value == $unit_now; |
---|
| 277 | break; |
---|
| 278 | case 'min': |
---|
| 279 | $valid = $future || $unit_value > $unit_now; |
---|
| 280 | break; |
---|
| 281 | default: |
---|
| 282 | $valid = $future || $unit_value >= $unit_now; |
---|
| 283 | break; |
---|
| 284 | |
---|
| 285 | } |
---|
| 286 | if ($valid && ($u != $next || $unit_value > $over)) // valid and not over |
---|
| 287 | { |
---|
| 288 | $found[$u] = $unit_value; |
---|
| 289 | $future = $future || $unit_value > $unit_now; |
---|
| 290 | break; |
---|
| 291 | } |
---|
| 292 | } |
---|
| 293 | if (!isset($found[$u])) // we have to try the next one, if it exists |
---|
| 294 | { |
---|
| 295 | $next = array_keys($units); |
---|
| 296 | if (!isset($next[count($found)-1])) |
---|
| 297 | { |
---|
| 298 | if ($this->debug) echo "<p>Nothing found, exiting !!!</p>\n"; |
---|
| 299 | return False; |
---|
| 300 | } |
---|
| 301 | $next = $next[count($found)-1]; |
---|
| 302 | $over = $found[$next]; |
---|
| 303 | unset($found[$next]); |
---|
| 304 | if ($this->debug) echo "<p>Have to try the next $next, $u's are over for $next=$over !!!</p>\n"; |
---|
| 305 | break; |
---|
| 306 | } |
---|
| 307 | } |
---|
| 308 | } |
---|
| 309 | if ($this->debug) { echo "<p>next="; print_r($found); echo "</p>\n"; } |
---|
| 310 | |
---|
| 311 | return mktime($found['hour'],$found['min'],0,$found['month'],$found['day'],$found['year']); |
---|
| 312 | } |
---|
| 313 | |
---|
| 314 | /*! |
---|
| 315 | @function cancel_timer |
---|
| 316 | @abstract cancels a timer |
---|
| 317 | @syntax cancel_timer($id) |
---|
| 318 | @param $id has to be the one used to set it. |
---|
| 319 | @result True if the timer exists and is not expired. |
---|
| 320 | */ |
---|
| 321 | function cancel_timer($id) |
---|
| 322 | { |
---|
| 323 | return $this->delete($id); |
---|
| 324 | } |
---|
| 325 | |
---|
| 326 | /*! |
---|
| 327 | @function last_check_run |
---|
| 328 | @abstract checks when the last check_run was run or set the run-semaphore if $semaphore == True |
---|
| 329 | @param $semaphore if False only check, if true try to set/release the semaphore |
---|
| 330 | @param $release if $semaphore == True, tells if we should set or release the semaphore |
---|
| 331 | @result if !$set array('start' => $start,'end' => $end) with timestamps of last check_run start and end, \ |
---|
| 332 | !$end means check_run is just running. If $set returns True if it was able to get the semaphore, else False |
---|
| 333 | */ |
---|
| 334 | function last_check_run($semaphore=False,$release=False,$run_by='') |
---|
| 335 | { |
---|
| 336 | //echo "<p>last_check_run(semaphore=".($semaphore?'True':'False').",release=".($release?'True':'False').")</p>\n"; |
---|
| 337 | if ($semaphore) |
---|
| 338 | { |
---|
| 339 | $this->db->lock($this->db_table,'write'); // this will block til we get exclusive access to the table |
---|
| 340 | |
---|
| 341 | @set_time_limit(0); // dont stop for an execution-time-limit |
---|
| 342 | ignore_user_abort(True); |
---|
| 343 | } |
---|
| 344 | if ($exists = $this->read('##last-check-run##')) |
---|
| 345 | { |
---|
| 346 | list(,$last_run) = each($exists); |
---|
| 347 | } |
---|
| 348 | //echo "last_run (from db)=<pre>"; print_r($last_run); echo "</pre>\n"; |
---|
| 349 | |
---|
| 350 | if (!$semaphore) |
---|
| 351 | { |
---|
| 352 | return $last_run['data']; |
---|
| 353 | } |
---|
| 354 | //elseif (!$release && !$last_run['data']['end'] && $last_run['data']['start'] > time()-600) |
---|
| 355 | elseif (!$release && !$last_run['data']['end']) |
---|
| 356 | { |
---|
| 357 | // already one instance running (started not more then 10min ago, else we ignore it) |
---|
| 358 | |
---|
| 359 | $this->db->unlock(); // unlock the table again |
---|
| 360 | |
---|
| 361 | //echo "<p>An other instance is running !!!</p>\n"; |
---|
| 362 | //return False; |
---|
| 363 | } |
---|
| 364 | // no other instance runs ==> we should run |
---|
| 365 | // |
---|
| 366 | if ($release) |
---|
| 367 | { |
---|
| 368 | $last_run['data']['end'] = time(); |
---|
| 369 | } |
---|
| 370 | else |
---|
| 371 | { |
---|
| 372 | $last_run = array( |
---|
| 373 | 'id' => '##last-check-run##', |
---|
| 374 | 'next' => 0, |
---|
| 375 | 'times' => array(), |
---|
| 376 | 'method' => 'none', |
---|
| 377 | 'data' => array( |
---|
| 378 | 'run_by'=> $run_by, |
---|
| 379 | 'start' => time(), |
---|
| 380 | 'end' => 0 |
---|
| 381 | ) |
---|
| 382 | ); |
---|
| 383 | } |
---|
| 384 | //echo "last_run=<pre>"; print_r($last_run); echo "</pre>\n"; |
---|
| 385 | $this->write($last_run,!!$exits); |
---|
| 386 | |
---|
| 387 | $this->db->unlock(); |
---|
| 388 | |
---|
| 389 | return True; |
---|
| 390 | } |
---|
| 391 | |
---|
| 392 | /*! |
---|
| 393 | @function check_run |
---|
| 394 | @abstract checks if there are any jobs ready to run (timer expired) and executes them |
---|
| 395 | */ |
---|
| 396 | function check_run($run_by='') |
---|
| 397 | { |
---|
| 398 | flush(); |
---|
| 399 | |
---|
| 400 | if (!$this->last_check_run(True,False,$run_by)) |
---|
| 401 | { |
---|
| 402 | return False; // cant obtain semaphore |
---|
| 403 | } |
---|
| 404 | if ($jobs = $this->read()) |
---|
| 405 | { |
---|
| 406 | foreach($jobs as $id => $job) |
---|
| 407 | { |
---|
| 408 | // checking / setting up phpgw_info/user |
---|
| 409 | // |
---|
| 410 | if ($GLOBALS['phpgw_info']['user']['account_id'] != $job['account_id']) |
---|
| 411 | { |
---|
| 412 | $domain = $GLOBALS['phpgw_info']['user']['domain']; |
---|
| 413 | $lang = $GLOBALS['phpgw_info']['user']['preferences']['common']['lang']; |
---|
| 414 | unset($GLOBALS['phpgw_info']['user']); |
---|
| 415 | |
---|
| 416 | if ($GLOBALS['phpgw']->session->account_id = $job['account_id']) |
---|
| 417 | { |
---|
| 418 | $GLOBALS['phpgw']->session->account_lid = $GLOBALS['phpgw']->accounts->id2name($job['account_id']); |
---|
| 419 | $GLOBALS['phpgw']->session->account_domain = $domain; |
---|
| 420 | $GLOBALS['phpgw']->session->read_repositories(False,False); |
---|
| 421 | $GLOBALS['phpgw_info']['user'] = $GLOBALS['phpgw']->session->user; |
---|
| 422 | |
---|
| 423 | if ($lang != $GLOBALS['phpgw_info']['user']['preferences']['common']['lang']) |
---|
| 424 | { |
---|
| 425 | unset($GLOBALS['lang']); |
---|
| 426 | $GLOBALS['phpgw']->translation->add_app('common'); |
---|
| 427 | } |
---|
| 428 | } |
---|
| 429 | else |
---|
| 430 | { |
---|
| 431 | $GLOBALS['phpgw_info']['user']['domain'] = $domain; |
---|
| 432 | } |
---|
| 433 | } |
---|
| 434 | list($app) = explode('.',$job['method']); |
---|
| 435 | $GLOBALS['phpgw']->translation->add_app($app); |
---|
| 436 | |
---|
| 437 | ExecMethod($job['method'],$job['data']); |
---|
| 438 | |
---|
| 439 | // re-read job, in case it had been updated or even deleted in the method |
---|
| 440 | $updated = $this->read($id); |
---|
| 441 | if ($updated && isset($updated[$id])) |
---|
| 442 | { |
---|
| 443 | $job = $updated[$id]; |
---|
| 444 | |
---|
| 445 | if ($job['next'] = $this->next_run($job['times'])) |
---|
| 446 | { |
---|
| 447 | $this->write($job,True); |
---|
| 448 | } |
---|
| 449 | else // no further runs |
---|
| 450 | { |
---|
| 451 | $this->delete($job['id']); |
---|
| 452 | } |
---|
| 453 | } |
---|
| 454 | } |
---|
| 455 | } |
---|
| 456 | $this->last_check_run(True,True,$run_by); // release semaphore |
---|
| 457 | |
---|
| 458 | return $jobs ? count($jobs) : False; |
---|
| 459 | } |
---|
| 460 | |
---|
| 461 | /*! |
---|
| 462 | @function read |
---|
| 463 | @abstract reads all matching db-rows / jobs |
---|
| 464 | @syntax reay($id=0) |
---|
| 465 | @param $id =0 reads all expired rows / jobs ready to run\ |
---|
| 466 | != 0 reads all rows/jobs matching $id (sql-wildcards '%' and '_' can be used) |
---|
| 467 | @result db-rows / jobs as array or False if no matches |
---|
| 468 | */ |
---|
| 469 | function read($id=0) |
---|
| 470 | { |
---|
| 471 | $id = $this->db->db_addslashes($id); |
---|
| 472 | if (strpos($id,'%') !== False || strpos($id,'_') !== False) |
---|
| 473 | { |
---|
| 474 | $where = "id LIKE '$id' AND id!='##last-check-run##'"; |
---|
| 475 | } |
---|
| 476 | elseif (!$id) |
---|
| 477 | { |
---|
| 478 | $where = 'next<='.time()." AND id!='##last-check-run##'"; |
---|
| 479 | } |
---|
| 480 | else |
---|
| 481 | { |
---|
| 482 | $where = "id='$id'"; |
---|
| 483 | } |
---|
| 484 | $this->db->query($sql="SELECT * FROM $this->db_table WHERE $where",__LINE__,__FILE__); |
---|
| 485 | |
---|
| 486 | $jobs = array(); |
---|
| 487 | while ($this->db->next_record()) |
---|
| 488 | { |
---|
| 489 | $id = $this->db->f('id'); |
---|
| 490 | |
---|
| 491 | $jobs[$id] = array( |
---|
| 492 | 'id' => $id, |
---|
| 493 | 'next' => $this->db->f('next'), |
---|
| 494 | 'times' => unserialize($this->db->f('times')), |
---|
| 495 | 'method' => $this->db->f('method'), |
---|
| 496 | 'data' => unserialize($this->db->f('data')), |
---|
| 497 | 'account_id' => $this->db->f('account_id') |
---|
| 498 | ); |
---|
| 499 | //echo "job id='$id'<pre>"; print_r($jobs[$id]); echo "</pre>\n"; |
---|
| 500 | } |
---|
| 501 | if (!count($jobs)) |
---|
| 502 | { |
---|
| 503 | return False; |
---|
| 504 | } |
---|
| 505 | return $jobs; |
---|
| 506 | } |
---|
| 507 | |
---|
| 508 | /*! |
---|
| 509 | @function write |
---|
| 510 | @abstract write a job / db-row to the db |
---|
| 511 | @syntax write($job,$exists = False) |
---|
| 512 | @param $job db-row as array |
---|
| 513 | @param $exits if True, we do an update, else we check if update or insert necesary |
---|
| 514 | */ |
---|
| 515 | function write($job,$exists = False) |
---|
| 516 | { |
---|
| 517 | $job['times'] = $this->db->db_addslashes(serialize($job['times'])); |
---|
| 518 | $job['data'] = $this->db->db_addslashes(serialize($job['data'])); |
---|
| 519 | $job['next'] = (int)$job['next']; |
---|
| 520 | $job['account_id'] = (int)$job['account_id']; |
---|
| 521 | |
---|
| 522 | if ($exists || $this->read($job['id'])) |
---|
| 523 | { |
---|
| 524 | $this->db->query("UPDATE $this->db_table SET next=$job[next],times='$job[times]',". |
---|
| 525 | "method='$job[method]',data='$job[data]',account_id=$job[account_id] WHERE id='$job[id]'",__LINE__,__FILE__); |
---|
| 526 | } |
---|
| 527 | else |
---|
| 528 | { |
---|
| 529 | $this->db->query("INSERT INTO $this->db_table (id,next,times,method,data,account_id) VALUES ". |
---|
| 530 | "('$job[id]',$job[next],'$job[times]','$job[method]','$job[data]',$job[account_id])",__LINE__,__FILE__); |
---|
| 531 | } |
---|
| 532 | } |
---|
| 533 | |
---|
| 534 | /*! |
---|
| 535 | @function delete |
---|
| 536 | @abstract delete db-row / job with $id |
---|
| 537 | @result False if $id not found else True |
---|
| 538 | */ |
---|
| 539 | function delete($id) |
---|
| 540 | { |
---|
| 541 | $this->db->query("DELETE FROM $this->db_table WHERE id='$id'",__LINE__,__FILE__); |
---|
| 542 | |
---|
| 543 | return $this->db->affected_rows(); |
---|
| 544 | } |
---|
| 545 | |
---|
| 546 | function find_binarys() |
---|
| 547 | { |
---|
| 548 | static $run = False; |
---|
| 549 | if ($run) |
---|
| 550 | { |
---|
| 551 | return; |
---|
| 552 | } |
---|
| 553 | $run = True; |
---|
| 554 | |
---|
| 555 | if (substr(php_uname(), 0, 7) == "Windows") |
---|
| 556 | { |
---|
| 557 | // ToDo: find php-cgi on windows |
---|
| 558 | } |
---|
| 559 | else |
---|
| 560 | { |
---|
| 561 | $binarys = array( |
---|
| 562 | 'php' => '/usr/bin/php', |
---|
| 563 | 'php4' => '/usr/bin/php4', // this is for debian |
---|
| 564 | 'crontab' => '/usr/bin/crontab' |
---|
| 565 | ); |
---|
| 566 | foreach ($binarys as $name => $path) |
---|
| 567 | { |
---|
| 568 | $this->$name = $path; // a reasonable default for *nix |
---|
| 569 | |
---|
| 570 | if (!($Ok = @is_executable($this->$name))) |
---|
| 571 | { |
---|
| 572 | if (file_exists($this->$name)) |
---|
| 573 | { |
---|
| 574 | echo '<p>'.lang('%1 is not executable by the webserver !!!',$this->$name)."</p>\n"; |
---|
| 575 | $perms = fileperms($this->$name); |
---|
| 576 | if (!($perms & 0x0001) && ($perms & 0x0008)) // only executable by group |
---|
| 577 | { |
---|
| 578 | $group = posix_getgrgid(filegroup($this->$name)); |
---|
| 579 | $webserver = posix_getpwuid(posix_getuid ()); |
---|
| 580 | echo '<p>'.lang("You need to add the webserver user '%1' to the group '%2'.",$webserver['name'],$group['name'])."</p>\n"; } |
---|
| 581 | } |
---|
| 582 | if ($fd = popen('/bin/sh -c "type -p '.$name.'"','r')) |
---|
| 583 | { |
---|
| 584 | $this->$name = fgets($fd,256); |
---|
| 585 | @pclose($fd); |
---|
| 586 | } |
---|
| 587 | if ($pos = strpos($this->$name,"\n")) |
---|
| 588 | { |
---|
| 589 | $this->$name = substr($this->$name,0,$pos); |
---|
| 590 | } |
---|
| 591 | } |
---|
| 592 | if (!$Ok && !@is_executable($this->$name)) |
---|
| 593 | { |
---|
| 594 | $this->$name = $name; // hopefully its in the path |
---|
| 595 | } |
---|
| 596 | //echo "<p>$name = '".$this->$name."'</p>\n"; |
---|
| 597 | } |
---|
| 598 | if ($this->php4[0] == '/') // we found a php4 binary |
---|
| 599 | { |
---|
| 600 | $this->php = $this->php4; |
---|
| 601 | } |
---|
| 602 | } |
---|
| 603 | |
---|
| 604 | } |
---|
| 605 | |
---|
| 606 | /*! |
---|
| 607 | @function installed |
---|
| 608 | @abstract checks if phpgwapi/cron/asyncservices.php is installed as cron-job |
---|
| 609 | @syntax installed() |
---|
| 610 | @result the times asyncservices are run (normaly 'min'=>'* /5') or False if not installed or 0 if crontab not found |
---|
| 611 | @note Not implemented for Windows at the moment, always returns 0 |
---|
| 612 | */ |
---|
| 613 | function installed() |
---|
| 614 | { |
---|
| 615 | if ($this->only_fallback) { |
---|
| 616 | return 0; |
---|
| 617 | } |
---|
| 618 | $this->find_binarys(); |
---|
| 619 | |
---|
| 620 | // Nao eh executavel porque esta fora do openbase_dir |
---|
| 621 | /* |
---|
| 622 | if (!is_executable($this->crontab)) |
---|
| 623 | { |
---|
| 624 | //echo "<p>Error: $this->crontab not found !!!</p>"; |
---|
| 625 | return 0; |
---|
| 626 | } |
---|
| 627 | */ |
---|
| 628 | |
---|
| 629 | $times = False; |
---|
| 630 | $this->other_cronlines = array(); |
---|
| 631 | if (($crontab = popen('/bin/sh -c "'.$this->crontab.' -l" 2>&1','r')) !== False) |
---|
| 632 | { |
---|
| 633 | while ($line = fgets($crontab,256)) |
---|
| 634 | { |
---|
| 635 | if ($this->debug) echo 'line '.++$n.": $line<br>\n"; |
---|
| 636 | $parts = split(' ',$line,6); |
---|
| 637 | |
---|
| 638 | // Foi customizado para a Celepar. |
---|
| 639 | //if ($line[0] == '#' || count($parts) < 6 || ($parts[5][0] != '/' && substr($parts[5],0,3) != 'php')) |
---|
| 640 | if ($line[0] == '#' || count($parts) < 6) |
---|
| 641 | { |
---|
| 642 | // ignore comments |
---|
| 643 | if ($line[0] != '#') |
---|
| 644 | { |
---|
| 645 | $times['error'] .= $line; |
---|
| 646 | } |
---|
| 647 | } |
---|
| 648 | elseif (strstr($line,$this->cronline) !== False) |
---|
| 649 | { |
---|
| 650 | $cron_units = array('min','hour','day','month','dow'); |
---|
| 651 | foreach($cron_units as $n => $u) |
---|
| 652 | { |
---|
| 653 | $times[$u] = $parts[$n]; |
---|
| 654 | } |
---|
| 655 | $times['cronline'] = $line; |
---|
| 656 | } |
---|
| 657 | else |
---|
| 658 | { |
---|
| 659 | $this->other_cronlines[] = $line; |
---|
| 660 | } |
---|
| 661 | } |
---|
| 662 | @pclose($crontab); |
---|
| 663 | } |
---|
| 664 | return $times; |
---|
| 665 | } |
---|
| 666 | |
---|
| 667 | /*! |
---|
| 668 | @function insall |
---|
| 669 | @abstract installs /phpgwapi/cron/asyncservices.php as cron-job |
---|
| 670 | @syntax install($times) |
---|
| 671 | @param $times array with keys 'min','hour','day','month','dow', not set is equal to '*'. |
---|
| 672 | False means de-install our own crontab line |
---|
| 673 | @result the times asyncservices are run, False if they are not installed, |
---|
| 674 | 0 if crontab not found and ' ' if crontab is deinstalled |
---|
| 675 | @note Not implemented for Windows at the moment, always returns 0 |
---|
| 676 | */ |
---|
| 677 | function install($times) |
---|
| 678 | { |
---|
| 679 | if ($this->only_fallback && $times !== False) { |
---|
| 680 | return 0; |
---|
| 681 | } |
---|
| 682 | $this->installed(); // find other installed cronlines |
---|
| 683 | |
---|
| 684 | if (($crontab = popen('/bin/sh -c "'.$this->crontab.' -" 2>&1','w')) !== False) |
---|
| 685 | { |
---|
| 686 | if (is_array($this->other_cronlines)) |
---|
| 687 | { |
---|
| 688 | foreach ($this->other_cronlines as $cronline) |
---|
| 689 | { |
---|
| 690 | fwrite($crontab,$cronline); // preserv the other lines on install |
---|
| 691 | } |
---|
| 692 | } |
---|
| 693 | if ($times !== False) |
---|
| 694 | { |
---|
| 695 | $cron_units = array('min','hour','day','month','dow'); |
---|
| 696 | $cronline = ''; |
---|
| 697 | foreach($cron_units as $cu) |
---|
| 698 | { |
---|
| 699 | $cronline .= (isset($times[$cu]) ? $times[$cu] : '*') . ' '; |
---|
| 700 | } |
---|
[129] | 701 | |
---|
[2] | 702 | //$cronline .= $this->php.' -q '.$this->cronline."\n"; |
---|
[129] | 703 | $php_version = preg_match("/5./",phpversion()) ? "php5" : "php4"; |
---|
| 704 | $cronline .= "cd /var/www/expresso/phpgwapi/cron/; $php_version -c /etc/$php_version/apache2/php.ini -q /var/www/expresso/phpgwapi/cron/asyncservices.php default\n"; |
---|
[2] | 705 | //echo "<p>Installing: '$cronline'</p>\n"; |
---|
| 706 | fwrite($crontab,$cronline); |
---|
| 707 | } |
---|
| 708 | @pclose($crontab); |
---|
| 709 | } |
---|
| 710 | return $times !== False ? $this->installed() : ' '; |
---|
| 711 | } |
---|
| 712 | } |
---|