source: branches/1.2/content/plugins/cron/cron.php @ 1358

Revision 1358, 18.1 KB checked in by shibuya246, 3 years ago (diff)

[branch 1.2] readme file and completed changes for v.0.1

Line 
1<?php
2/**
3 * name: Cron
4 * description: Enables setting of cron jobs
5 * version: 0.1
6 * folder: cron
7 * class: Cron
8 * type: cron
9 * hooks: install_plugin, admin_plugin_settings, admin_sidebar_plugin_settings, theme_index_top, admin_theme_index_top, cron_schedule_event, cron_update_job, cron_delete_job, cron_flush_hook, cron_hotaru_version, admin_theme_main_stats_post_version
10 * author: shibuya246
11 * authorurl: http://shibuya246.com
12 *
13 * PHP version 5
14 *
15 * cron view functions modelled on plugin: Cron GUI developed for wordpress by Simon Wheatley http://simonwheatley.co.uk/wordpress/cron-gui
16 * main cron functions ported from wordpress http://wordpress.org
17 *
18 * LICENSE: Hotaru CMS is free software: you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License as
20 * published by the Free Software Foundation, either version 3 of
21 * the License, or (at your option) any later version.
22 *
23 * Hotaru CMS is distributed in the hope that it will be useful, but WITHOUT
24 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 * FITNESS FOR A PARTICULAR PURPOSE.
26 *
27 * You should have received a copy of the GNU General Public License along
28 * with Hotaru CMS. If not, see http://www.gnu.org/licenses/.
29 *
30 * @category  Content Management System
31 * @package   HotaruCMS
32 * @author    shibuya246 <blog@shibuya246.com>
33 * @copyright Copyright (c) 2010
34 * @license   http://www.gnu.org/copyleft/gpl.html GNU General Public License
35 * @link      http://shibuya246.com
36 */
37class Cron
38{
39        /*
40         * Setup the default settings
41         * */
42    public function install_plugin($h)
43    {
44        $timestamp = time();
45        $recurrence = "daily";
46        $hook = "cron_hotaru_version";
47        $this->cron_schedule_event($h, $timestamp, $recurrence, $hook);
48
49        if (SYS_FEEDBACK == 'true') {
50            $hook = "cron_hotaru_feedback";
51            $this->cron_schedule_event($h, $timestamp, $recurrence, $hook);
52        }
53    } 
54
55   public function theme_index_top($h) {
56        $this->admin_theme_index_top($h);
57   }
58
59    public function admin_theme_index_top($h) {       
60        $h->vars['cron_settings'] = $h->getSerializedSettings();
61        $this->checkrunCron($h);       
62        //$this->run_cron($h);
63    }
64
65    public function admin_theme_main_stats_post_version($h) {
66        $hotaru_version_settings = $h->getSerializedSettings('cron', 'hotaru_latest_version');
67        $hotaru_latest_version = $hotaru_version_settings['version'];
68        if ($hotaru_latest_version == $h->version) {
69            echo "<li>Latest version installed</li>";
70        }
71        else {
72            echo "<li><a href='http://hotarucms.org/forumdisplay.php?23-Download-Hotaru-CMS'>Update to v." . $hotaru_latest_version . "</a></li>";
73        }
74    }
75
76
77/**
78 * @param int $timestamp Timestamp for when to run the event.
79 * @param string $hook Action hook to execute when cron is run.
80 * @param array $args Optional. Arguments to pass to the hook's callback function.
81 */
82public function cron_schedule_single_event( $timestamp, $hook, $args = array()) {
83        // don't schedule a duplicate if there's already an identical event due in the next 10 minutes
84        $next = cron_next_scheduled($hook, $args);
85        if ( $next && $next <= $timestamp + 600 )
86                return;
87
88        $crons = _get_cron_array();
89        $key = md5(serialize($args));
90        $crons[$timestamp][$hook][$key] = array( 'schedule' => false, 'args' => $args );
91        uksort( $crons, "strnatcasecmp" );
92        _set_cron_array( $crons );
93}
94
95
96public function cron_schedule_event($h, $timestamp, $recurrence, $hook, $args = array()) {   
97        $crons = $this->_get_cron_array($h);
98        $schedules = $this->cron_get_schedules($h);
99        $key = md5(serialize($args));       
100        if ( !isset( $schedules[$recurrence] ) )
101                return false;
102       
103        $crons[$timestamp][$hook][$key] = array( 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] );
104        uksort( $crons, "strnatcasecmp" );
105       
106        $this->_set_cron_array($h, $crons );
107}
108
109/**
110 * Reschedule a recurring event.
111 *
112 * @since 2.1.0
113 *
114 * @param int $timestamp Timestamp for when to run the event.
115 * @param string $recurrence How often the event should recur.
116 * @param string $hook Action hook to execute when cron is run.
117 * @param array $args Optional. Arguments to pass to the hook's callback function.
118 * @return bool|null False on failure. Null when event is rescheduled.
119 */
120public function cron_reschedule_event($h, $timestamp, $recurrence, $hook, $args = array()) {
121        $crons = $this->_get_cron_array($h);
122        $schedules =  $this->cron_get_schedules($h);
123        $key = md5(serialize($args));
124        $interval = 0;
125
126        // First we try to get it from the schedule
127        if ( 0 == $interval )
128                $interval = $schedules[$recurrence]['interval'];
129        // Now we try to get it from the saved interval in case the schedule disappears
130        if ( 0 == $interval )
131                $interval = $crons[$timestamp][$hook][$key]['interval'];
132        // Now we assume something is wrong and fail to schedule
133        if ( 0 == $interval )
134                return false;
135
136        $now = time();
137
138    if ( $timestamp >= $now )
139        $timestamp = $now + $interval;
140    else
141        $timestamp = $now + ($interval - (($now - $timestamp) % $interval));   
142        $this->cron_schedule_event($h, $timestamp, $recurrence, $hook, $args );
143}
144
145/**
146 * Unschedule a previously scheduled cron job.
147 *
148 * The $timestamp and $hook parameters are required, so that the event can be
149 * identified.
150 *
151 * @since 2.1.0
152 *
153 * @param int $timestamp Timestamp for when to run the event.
154 * @param string $hook Action hook, the execution of which will be unscheduled.
155 * @param array $args Arguments to pass to the hook's callback function.
156 * Although not passed to a callback function, these arguments are used
157 * to uniquely identify the scheduled event, so they should be the same
158 * as those used when originally scheduling the event.
159 */
160public function cron_unschedule_event($h, $timestamp, $hook, $args = array() ) {
161        $crons = $this->_get_cron_array($h);       
162
163        $key = md5(serialize($args));       
164        unset( $crons[$timestamp][$hook][$key] );
165        if ( empty($crons[$timestamp][$hook]) )
166                unset( $crons[$timestamp][$hook] );
167        if ( empty($crons[$timestamp]) )             
168                unset( $crons[$timestamp] );     
169        $this->_set_cron_array($h, $crons );
170}
171
172/**
173 * Unschedule all cron jobs attached to a specific hook.
174 *
175 * @since 2.1.0
176 *
177 * @param string $hook Action hook, the execution of which will be unscheduled.
178 * @param mixed $args,... Optional. Event arguments.
179 */
180function cron_clear_scheduled_hook($h, $hook ) {
181        $args = array_slice( func_get_args(), 1 );
182
183        while ( $timestamp = wp_next_scheduled( $hook, $args ) )
184                $this->cron_unschedule_event($h, $timestamp, $hook, $args );
185}
186
187/**
188 * Retrieve the next timestamp for a cron event.
189 *
190 * @since 2.1.0
191 *
192 * @param string $hook Action hook to execute when cron is run.
193 * @param array $args Optional. Arguments to pass to the hook's callback function.
194 * @return bool|int The UNIX timestamp of the next time the scheduled event will occur.
195 */
196public function cron_next_scheduled( $hook, $args = array() ) {
197        $crons = _get_cron_array();
198        $key = md5(serialize($args));
199        if ( empty($crons) )
200                return false;
201        foreach ( $crons as $timestamp => $cron ) {
202                if ( isset( $cron[$hook][$key] ) )
203                        return $timestamp;
204        }
205        return false;
206}
207
208/**
209 * Send request to run cron through HTTP request that doesn't halt page loading.
210 *
211 * @since 2.1.0
212 *
213 * @return null Cron could not be spawned, because it is not needed to run.
214 */
215public function spawn_cron($h, $local_time = 0 ) {
216
217        if ( !$local_time )
218                $local_time = time();
219
220        if ( defined('DOING_CRON') || isset($_GET['doing_cron']) )
221                return;
222
223        /*
224         * do not even start the cron if local server timer has drifted
225         * such as due to power failure, or misconfiguration
226         */
227        $timer_accurate = $this->check_server_timer( $local_time );
228        if ( !$timer_accurate )
229                return;
230
231        /*
232        * multiple processes on multiple web servers can run this code concurrently
233        * try to make this as atomic as possible by setting doing_cron switch
234        */
235        $flag = $h->getSetting('doing_cron');
236
237        if ( $flag > $local_time + 10*60 )
238                $flag = 0;
239
240        // don't run if another process is currently running it or more than once every 60 sec.
241        if ( $flag + 60 > $local_time )
242                return;
243
244        //sanity check
245        $crons = $this->_get_cron_array($h);
246        if ( !is_array($crons) )
247                return;
248
249        $keys = array_keys( $crons );
250        if ( isset($keys[0]) && $keys[0] > $local_time )
251                return;
252
253         $h->updateSetting('doing_cron',  $local_time);
254
255        //$cron_url = get_option( 'siteurl' ) . '/wp-cron.php?doing_wp_cron';
256        //wp_remote_post( $cron_url, array('timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters('https_local_ssl_verify', true)) );
257
258        $this->checkrunCron($h);
259}
260
261/**
262 * Run scheduled callbacks or spawn cron for all scheduled events.
263 *
264 * @since 2.1.0
265 *
266 * @return null When doesn't need to run Cron.
267 */
268public function run_cron($h) {
269        if ( false === $crons = $this->_get_cron_array($h) )
270                return;
271
272        $local_time = time();
273        $keys = array_keys( $crons );
274        if ( isset($keys[0]) && $keys[0] > $local_time )
275                return;
276       
277        $schedules = $this->cron_get_schedules($h);
278        foreach ( $crons as $timestamp => $cronhooks ) {
279                if ( $timestamp > $local_time ) break;
280                foreach ( (array) $cronhooks as $hook => $args ) {
281                        if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
282                                continue;
283                        $this->spawn_cron($h, $local_time );
284                        break 2;
285                }
286        }
287}
288
289/**
290 * Retrieve supported and filtered Cron recurrences.
291 *
292 * The supported recurrences are 'hourly' and 'daily'. A plugin may add more by
293 * hooking into the 'cron_schedules' filter. The filter accepts an array of
294 * arrays. The outer array has a key that is the name of the schedule or for
295 * example 'weekly'. The value is an array with two keys, one is 'interval' and
296 * the other is 'display'.
297 *
298 * The 'interval' is a number in seconds of when the cron job should run. So for
299 * 'hourly', the time is 3600 or 60*60. For weekly, the value would be
300 * 60*60*24*7 or 604800. The value of 'interval' would then be 604800.
301 *
302 * The 'display' is the description. For the 'weekly' key, the 'display' would
303 * be <code>__('Once Weekly')</code>.
304 *
305 * For your plugin, you will be passed an array. you can easily add your
306 * schedule by doing the following.
307 * <code>
308 * // filter parameter variable name is 'array'
309 *      $array['weekly'] = array(
310 *              'interval' => 604800,
311 *              'display' => __('Once Weekly')
312 *      );
313 * </code>
314 *
315 * @since 2.1.0
316 *
317 * @return array
318 */
319public function cron_get_schedules($h) {
320        $schedules = array(
321                'hourly' => array( 'interval' => 3600, 'display' => 'Once Hourly' ),
322                'twicedaily' => array( 'interval' => 43200, 'display' => 'Twice Daily' ),
323                'daily' => array( 'interval' => 86400, 'display' => 'Once Daily' ),
324                'weekly' => array( 'interval' => 604800, 'display' => 'Once Weekly' ),
325        );
326        //return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
327        return $schedules;
328}
329
330/**
331 * Retrieve Cron schedule for hook with arguments.
332 *
333 * @since 2.1.0
334 *
335 * @param string $hook Action hook to execute when cron is run.
336 * @param array $args Optional. Arguments to pass to the hook's callback function.
337 * @return string|bool False, if no schedule. Schedule on success.
338 */
339public function cron_get_schedule($hook, $args = array()) {
340        $crons = _get_cron_array();
341        $key = md5(serialize($args));
342        if ( empty($crons) )
343                return false;
344        foreach ( $crons as $timestamp => $cron ) {
345                if ( isset( $cron[$hook][$key] ) )
346                        return $cron[$hook][$key]['schedule'];
347        }
348        return false;
349}
350
351//
352// Private functions
353//
354
355/**
356 * Retrieve cron info array option.
357 *
358 */
359public function _get_cron_array($h)  {
360        if (isset($h->vars['cron_settings'])) {
361            $cron = $h->vars['cron_settings'];
362            if ( ! is_array($cron) )
363                return false;
364
365            return $cron;
366        }
367        else {
368            return false;
369        }
370}
371
372    /**
373     * Updates the CRON settings.
374     *
375     */
376    public function _set_cron_array($h,$cron) {
377            $h->updateSetting('cron_settings', serialize($cron));
378            $h->vars['cron_settings'] = $cron;
379    }
380
381    // stub for checking server timer accuracy, using outside standard time sources
382    public function check_server_timer( $local_time ) {
383            return true;
384    }
385
386    public function cron_hotaru_feedback($h) {
387        $query_vals = array(
388            'api_key' => '',
389            'format' => 'json',
390            'method' => 'hotaru.systemFeedback.add',
391            'version' => $h->version
392        );
393
394       $info = $this->sendApiRequest($h, $query_vals);
395       
396    }
397
398    public function cron_hotaru_version($h) {
399        $query_vals = array(
400            'api_key' => '',
401            'format' => 'json',
402            'method' => 'hotaru.version.get'
403        );
404
405         $info = $this->sendApiRequest($h, $query_vals);
406       
407        // save the updated version number to the local db so we can display it on the admin panel until it gets updated.       
408         if (isset($info['version']))
409             $h->updateSetting('hotaru_latest_version', serialize($info), 'cron');
410    }
411
412    public function sendApiRequest($h, $query_vals) {
413
414        // Generate the POST string
415        $ret = '';
416        foreach($query_vals as $key => $value) {
417            $ret .= $key.'='.urlencode($value).'&';
418        }
419
420        $ret = rtrim($ret, '&');
421
422        $ch = curl_init("http://api.hotarucms.org/index.php?page=api");
423        curl_setopt($ch, CURLOPT_HEADER, 0);
424        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
425        curl_setopt($ch, CURLOPT_POSTFIELDS, $ret);
426        $response = curl_exec($ch);
427        curl_close ($ch);
428
429       return json_decode($response, true);
430    }
431
432
433    public function checkrunCron($h) {
434        if ( !empty($_POST) || defined('DOING_AJAX') || defined('DOING_CRON') )
435            return;
436
437       define('DOING_CRON', true);
438
439       if ( false === $crons = $this->_get_cron_array($h) )
440            return;
441
442       $keys = array_keys( $crons );
443       $local_time = time();
444
445       if ( isset($keys[0]) && $keys[0] > $local_time )
446           return;
447
448       foreach ($crons as $timestamp => $cronhooks) {
449            if ( $timestamp > $local_time )
450                return;
451
452            foreach ($cronhooks as $hook => $keys) {               
453                foreach ($keys as $k => $v) {                   
454                    $schedule = $v['schedule'];
455                    if ($schedule != false) {
456                            //$new_args = array($timestamp, $schedule, $hook, $v['args']);
457                            $this->cron_reschedule_event($h, $timestamp, $schedule, $hook, $v['args']);
458                    }
459                    $this->cron_unschedule_event($h, $timestamp, $hook, $v['args']);
460                    //call function to do task required for cron
461                    //print "running hook..-> " . $hook. "     ";
462                    $h->pluginHook($hook, '', $v['args']);
463                }
464            }
465       }
466    }
467
468    public function cron_update_job($h, $cron_data)
469    {
470        $h->vars['cron_settings'] = $h->getSerializedSettings();
471       
472        $timestamp = (isset($cron_data['timestamp'])) ? $cron_data['timestamp'] : array();
473        $recurrence = (isset($cron_data['recurrence'])) ? $cron_data['recurrence'] : array();
474        $hook = (isset($cron_data['hook'])) ? $cron_data['hook'] : array();
475        $args = (isset($cron_data['args'])) ? $cron_data['args'] : array();
476        $cron_exists = false;
477
478        // check whether already have existing event for this job
479        //  match against hook and args. note args must match
480        $current_crons = $this->_get_cron_array($h);
481        foreach ($current_crons as $current_timestamp => $current_cronhooks) {
482          foreach ($current_cronhooks as $current_hook => $current_keys) {
483             if ($current_hook == $hook) {
484               foreach ($current_keys as $current_md5 => $current_job) {
485              //print_r( $current_job["args"]); print "   **    "; print_r($args);
486            if ($current_job["args"] == $args) {
487                $this->cron_schedule_event($h, $timestamp, $recurrence, $hook, $args);
488                $this->cron_unschedule_event($h, $current_timestamp, $current_hook, $args);
489                $cron_exists = true;
490            }}}
491          }
492        }
493
494        if (!$cron_exists) $this->cron_schedule_event($h, $timestamp, $recurrence, $hook, $args);
495    }
496
497    public function cron_delete_job($h, $cron_data)
498    {       
499        //load current cron jobs from memory space
500        $h->vars['cron_settings'] = $h->getSerializedSettings();       
501       
502        $hook = (isset($cron_data['hook'])) ? $cron_data['hook'] : array();
503        $args = (isset($cron_data['args'])) ? $cron_data['args'] : array();
504
505        $current_crons = $this->_get_cron_array($h);
506       
507        foreach ($current_crons as $current_timestamp => $current_cronhooks) {
508          foreach ($current_cronhooks as $current_hook => $current_keys) {
509            foreach ($current_keys as $current_md5 => $current_job) {
510                foreach ($current_job as $current_set => $current_args) {               
511                    if ($current_hook == $hook && $current_args == $args) {                       
512                        $this->cron_unschedule_event($h, $current_timestamp, $current_hook, $current_args);
513                    }
514                }
515            }
516          }
517        }
518    }
519
520     public function cron_flush_hook($h, $cron_data)
521    {
522        $h->vars['cron_settings'] = $h->getSerializedSettings();
523
524        $hook = (isset($cron_data['hook'])) ? $cron_data['hook'] : array();
525        $flush_count = 0;
526
527        $current_crons = $this->_get_cron_array($h);
528        foreach ($current_crons as $current_timestamp => $current_cronhooks) {
529          foreach ($current_cronhooks as $current_hook => $current_keys) {
530              if ($current_hook == $hook) {                           
531               foreach ($current_keys as $current_md5 => $current_job) {
532                    $flush_count ++;                 
533                    //while ( list ($param, $value) = each ( $current_job ))                                                         
534                    $this->cron_unschedule_event($h, $current_timestamp, $current_hook,  $current_job["args"]);
535                    }
536               }
537          }
538        }
539        $array = array('count' => $flush_count);
540        echo json_encode($array);
541    }
542   
543}
Note: See TracBrowser for help on using the repository browser.