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 = preg_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 | } |
---|
701 | |
---|
702 | //$cronline .= $this->php.' -q '.$this->cronline."\n"; |
---|
703 | $php_version = preg_match("/5./",phpversion()) ? "php" : "php4"; |
---|
704 | $cronline .= "cd " . PHPGW_SERVER_ROOT . "/phpgwapi/cron/; $php_version -c /etc/php.ini -q " . PHPGW_SERVER_ROOT . "/phpgwapi/cron/asyncservices.php default\n"; |
---|
705 | //echo "<p>Installing: '$cronline'</p>\n"; |
---|
706 | fwrite($crontab,$cronline); |
---|
707 | } |
---|
708 | @pclose($crontab); |
---|
709 | } |
---|
710 | return $times !== False ? $this->installed() : ' '; |
---|
711 | } |
---|
712 | } |
---|