请选择 进入手机版 | 继续访问电脑版
seo_网站建设_网站模板_网页源码_网站源码-千欧中软
查看: 725|回复: 0

Discuz!中的计划任务代码分析

[复制链接]

202

主题

224

帖子

259

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
259
发表于 2017-10-10 11:04:48 | 显示全部楼层 |阅读模式
discuz_cron.php



    <?php

    /**
    *      [Discuz!] (C)2001-2099 Comsenz Inc.
    *      This is NOT a freeware, use is subject to license terms
    *
    *      $Id: discuz_cron.php 25833 2011-11-24 01:12:09Z monkey $
    */

    if(!defined('IN_DISCUZ')) {
            exit('Access Denied');
    }

    class discuz_cron
    {

            public static function run($cronid = 0) {
                    global $_G;
                    //取出这个时间点或这个时间点之前的计划任务
                    $cron = $cronid ? C::t('common_cron')->fetch($cronid) : C::t('common_cron')->fetch_nextrun(TIMESTAMP);

                    //进程名称
                    $processname ='DZ_CRON_'.(empty($cron) ? 'CHECKER' : $cron['cronid']);

                    if($cronid && !empty($cron)) {
                            //此计划任务有效,解锁
                            discuz_process::unlock($processname);
                    }

                    if(discuz_process::islocked($processname, 600)) {
                            //没有加锁,加锁,返回false,若已加锁,返回true,终止程序进行
                            return false;
                    }

                    if($cron) {

                            $cron['filename'] = str_replace(array('..', '/', '\\'), '', $cron['filename']);
                            $cronfile = DISCUZ_ROOT.'./source/include/cron/'.$cron['filename'];

                            $cron['minute'] = explode("\t", $cron['minute']);
                            self::setnextime($cron); //更新此计划任务的上次执行时间和下次执行时间

                            @set_time_limit(1000); //设置允许脚本运行的时间,单位为秒
                            @ignore_user_abort(TRUE);//函数设置与客户机断开是否会终止脚本的执行

                            if(!@include $cronfile) {
                                    return false;
                            }
                    }

                    self::nextcron();//设置下次计划任务执行的时间,存入缓存
                    discuz_process::unlock($processname);
                    return true;
            }

            private static function nextcron() {
                    $cron = C::t('common_cron')->fetch_nextcron();
                    if($cron && isset($cron['nextrun'])) {
                            savecache('cronnextrun', $cron['nextrun']);
                    } else {
                            savecache('cronnextrun', TIMESTAMP + 86400 * 365);
                    }
                    return true;
            }

            /*
             * 获取计划任务下次执行时间,更新此计划任务的上次执行时间,是否可用
             *
             */
            private static function setnextime($cron) {

                    if(empty($cron)) return FALSE;

                    list($yearnow, $monthnow, $daynow, $weekdaynow, $hournow, $minutenow) = explode('-', gmdate('Y-m-d-w-H-i', TIMESTAMP + getglobal('setting/timeoffset') * 3600));
                    //获取现在的年、月、日,周几,小时,分钟

                    if($cron['weekday'] == -1) {//为不限制
                            if($cron['day'] == -1) { //为不限制
                                    $firstday = $daynow;//第一个日为今天, 第二个日为明天
                                    $secondday = $daynow + 1;
                            } else {
                                    $firstday = $cron['day']; //第一个日为计划任务指定的日,第二个日为计划任务指定的下一个月的日
                                    $secondday = $cron['day'] + gmdate('t', TIMESTAMP + getglobal('setting/timeoffset') * 3600);
                            }
                    } else {
                            $firstday = $daynow + ($cron['weekday'] - $weekdaynow);//通过今天的日,计划任务的周几,现在的周几计划得出第一个日
                            $secondday = $firstday + 7; //第二个日
                    }

                    if($firstday < $daynow) {//如果超过了计划任务指定的,则为第二个日
                            $firstday = $secondday;
                    }

                    if($firstday == $daynow) { //计划任务的日为今天
                            $todaytime = self::todaynextrun($cron); //获取下次计划任务的小时,分钟
                            if($todaytime['hour'] == -1 && $todaytime['minute'] == -1) { //小时,分钟都无效
                                    $cron['day'] = $secondday; //日为第二个日
                                    $nexttime = self::todaynextrun($cron, 0, -1);
                                    $cron['hour'] = $nexttime['hour'];
                                    $cron['minute'] = $nexttime['minute'];
                            } else {
                                    $cron['day'] = $firstday;
                                    $cron['hour'] = $todaytime['hour'];
                                    $cron['minute'] = $todaytime['minute'];
                            }
                    } else {
                            $cron['day'] = $firstday;
                            $nexttime = self::todaynextrun($cron, 0, -1);
                            $cron['hour'] = $nexttime['hour'];
                            $cron['minute'] = $nexttime['minute'];
                    }

                    //获取执行计划任务的下次时间 取得GMT日期的UNIX时间戳
                    $nextrun = @gmmktime($cron['hour'], $cron['minute'] > 0 ? $cron['minute'] : 0, 0, $monthnow, $cron['day'], $yearnow) - getglobal('setting/timeoffset') * 3600;
                    //如果计划任务下次执行的时间小于当前时间戳,则此计划任务无效
                    $data = array('lastrun' => TIMESTAMP, 'nextrun' => $nextrun);
                    if(!($nextrun > TIMESTAMP)) {
                            $data['available'] = '0';
                    }
                    C::t('common_cron')->update($cron['cronid'], $data);

                    return true;
            }

            /*
             *
             * 获取计划任务执行的小时,分钟
             */
            private static function todaynextrun($cron, $hour = -2, $minute = -2) {

                    $hour = $hour == -2 ? gmdate('H', TIMESTAMP + getglobal('setting/timeoffset') * 3600) : $hour;
                    $minute = $minute == -2 ? gmdate('i', TIMESTAMP + getglobal('setting/timeoffset') * 3600) : $minute;
                    //没有设置小时,分钟值  是取当前的小时 ,分钟值

                    $nexttime = array();
                    if($cron['hour'] == -1 && !$cron['minute']) { //计划任务为任意小时,任意分钟
                            $nexttime['hour'] = $hour;
                            $nexttime['minute'] = $minute + 1;
                    } elseif($cron['hour'] == -1 && $cron['minute'] != '') { //计划任务为任意小时,指定分钟
                            $nexttime['hour'] = $hour;
                            if(($nextminute = self::nextminute($cron['minute'], $minute)) === false) { //如果分钟无效,即现在的分钟超过了指定分钟,则到下一个小时,分钟 为指定分钟的第一个值
                                    ++$nexttime['hour'];
                                    $nextminute = $cron['minute'][0];
                            }
                            $nexttime['minute'] = $nextminute;
                    } elseif($cron['hour'] != -1 && $cron['minute'] == '') { //如果为指定小时,任意分钟
                            if($cron['hour'] < $hour) { //计划任务的小时小于当前小时
                                    $nexttime['hour'] = $nexttime['minute'] = -1;
                            } elseif($cron['hour'] == $hour) { //计划任务的小时等于当前小时
                                    $nexttime['hour'] = $cron['hour'];
                                    $nexttime['minute'] = $minute + 1;
                            } else {
                                    $nexttime['hour'] = $cron['hour'];
                                    $nexttime['minute'] = 0;
                            }
                    } elseif($cron['hour'] != -1 && $cron['minute'] != '') { //如果为指定小时,指定分钟
                            $nextminute = self::nextminute($cron['minute'], $minute);
                            if($cron['hour'] < $hour || ($cron['hour'] == $hour && $nextminute === false)) {//计划任务小时小于当前小时,或者小时相等,但是分钟过了
                                    $nexttime['hour'] = -1;
                                    $nexttime['minute'] = -1;
                            } else {
                                    $nexttime['hour'] = $cron['hour'];
                                    $nexttime['minute'] = $nextminute;
                            }
                    }

                    return $nexttime;
            }

            private static function nextminute($nextminutes, $minutenow) {
                    foreach($nextminutes as $nextminute) {
                            if($nextminute > $minutenow) {
                                    return $nextminute;
                            }
                    }
                    return false;
            }
    }

    ?>



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

2010-2015 千欧中软 版权所有
快速回复 返回顶部 返回列表