zoukankan      html  css  js  c++  java
  • yii 计划任务

    Yii框架自动生成的Web应用骨架的目录里面有连个脚步文件,yiic和yiic.bat。

    yiic是Unix/Linux平台用的,yiic.bat是windows平台用的。如果要查看脚本的帮助可以进入到脚步所在的根目录,然后执行yiic help,他会列出所有可用的命令,里面包括Yii提供的系统命令和用户自定义的命令。

    如果要知道如何执行一个命令可以执行以下命令:

    1 yiic help <command-name>

    如果要执行一个命令,可以使用如下格式:

    1 yiic <command-name> [parameters...]

    1、创建命令

    控制台命令都是以类文件的方式存储在CConsoleApplication::commandPath指定的目录。默认是存储在protected/commands

    每个类必须继承自CConsoleCommand。类名的格式是XyzCommand,命令的名字首字母大写,xyz才是命令本身。

    可以通过配置CConsoleApplication::commandMap,命令类可以有不同的命名约定和不同的目录。

    创建一个新命令你可以覆盖CConsoleCommand::run()或者写一个或多个action.

    覆盖父类的run方法格式可以是:

    1 public function run($args) { ... }

    当执行一个命令的时候,run方法将会被调用,任何加在调用命令后面的参数将会赋给$args。

    在命令内部可以用Yii::app()调用这个控制台的实例。

    从1.1.1版本开始,可以创建一个全局的命令,被在同一台机器上的所有的Yii应用所共享。为了达到这样的目的,你需要定义一个名为

    YII_CONSOLE_COMMANDS的环境变量,指向一个已存在的目录,然后把这个全局的命令类放在这个目录里面。

    2、控制台命令Action

    一个控制台命令action就是一个控制台命令类的一个方法。

    方法名的格式:actionXyz,action名的首字母大写,xyz才是被调用的action本身。

    执行一个action的命令格式:

    1 yiic <command-name> <action-name> --option1=value1 --option2=value2 ...

    后面的option-value对将会赋给这个action方法的参数。如果你给出了option名而没有给出对应的值,那么这个option将会被认为是boolean值true。

    action的参数也可以声明一个数组类型,如:

    1 public function actionIndex(array $types) { ... }

    调用它的命令是:

    1 yiic sitemap index --types=News --types=Article

    最终命令调用是:actionIndex(array('News', 'Article'))。

    从1.1.6开始,还支持匿名参数和全局选项。

    匿名参数指的是不按正常选项参数格式(the format of options)的命令行参数,比如:yiic sitemap index --limit=5 News,News就是一个匿名参数。

    要使用匿名参数,action必须声明一个$args变量,比如:

    1 public function actionIndex($limit=10, $args=array()) {...}

    $args会接收到所有可用的匿名参数。

    全局选项(Global options)指的是一个命令行选项被这个命令的所有action所共享。

    比如:一个命令有好几个action,我们想在每个action里面都有一个名字叫verbose的选项,我们可以在每个action方法里面都声明一个叫$verbose的参数。

    一个更好的做法是把它声明成这个命令类的公共成员变量(public member variable),这样verbose就会成为一个全局的选项。

    1 class SitemapCommand extends CConsoleCommand
    2 {
    3     public $verbose=false;
    4     public function actionIndex($type) {...}
    5 }

    这样就可以执行一个带verbose选项的命令:

    1 yiic sitemap index --verbose=1 --type=News

    3、退出代码

    执行命令的宿主机器可能需要检测我们的命令执行成功与否,它可以通过检测命令最后退出是返回的退出码来识别。

    退出码是介于0到254之间的整型值,0表示这个命令执行成功,非0表示这个命令执行期间出现错误。

    你可以在action或者是run方法里面通过一个退出码来退出你的应用程序。

    比如:

    1 if (/* error */) {
    2     return 1; // exit with error code 1
    3 }
    4 // ... do something ...
    5 return 0; // exit successfully

    假如没有返回值,将会有一个默认的0被返回

    4、定制控制台应用

    默认的控制台应用配置位置:protected/config/console.php

    任何CConsoleApplication的公共属性都可以在这个文件里面配置。

    这个配置文件类似于普通的web应用的配置文件。

    Customizing Console Applications 

    By default, if an application is created using the yiic webapp tool, the configuration for the console application will be protected/config/console.php. Like a Web application configuration file, this file is a PHP script which returns an array representing the property initial values for a console application instance. As a result, any public property of CConsoleApplication can be configured in this file.

    Because console commands are often created to serve for the Web application, they need to access the resources (such as DB connections) that are used by the latter. We can do so in the console application configuration file like the following:

    return array(
        ......
        'components'=>array(
            'db'=>array(
                ......
            ),
        ),
    );

    As we can see, the format of the configuration is very similar to what we do in a Web application configuration. This is because both CConsoleApplication and CWebApplication share the same base class.

    文章参考:http://www.yiiframework.com/doc/guide/1.1/zh_cn/topics.console

    ----------------------------------------------------------------------------------------------------------------------

    一篇文章:

    使用YII框架进行PHP程序的计划任务教程

    1.当你通过yiic创建一个webapp应用后,
    会在webapp/protected/下生成yiic.php, 由于是命令行应用,所以这里的yiic.php其实就是与webapp下的index.php一样的,命令行入口文件。

    2.打开yiic文件,添加一行设置,将commands目录的路径添加到yiic中,这样,yiic就能够找到commands目录下的命令文件了,修改后的代码如下,红色为新加入代码:

    1
    2
    3
    4
    5
    6
    <?php
    // change the following paths if necessary
    $config=dirname(__FILE__).'/config/console.php';
    @putenv('YII_CONSOLE_COMMANDS='. dirname(__FILE__).'/commands' );
    require_once($yiic);

    或者是:(其实require_once($yiic)中的yiic.php文件内容跟crons.php类似)。

     配置好,要执行的页面。本文为 protected/commands/crons.php

    <?php
    defined('YII_DEBUG') or define('YII_DEBUG',true);
    // including Yii
    require_once(dirname(dirname(dirname(__FILE__))).'/framework/yii.php');
    // we'll use a separate config file
    $configFile=dirname(dirname(__FILE__)).'/config/console.php';
    // creating and running console application
    Yii::createConsoleApplication($configFile)->run();
    ?>

    3.配置好product/config/console.php里面需要用到的组件,像数据库连接。

    配置main/console.php,设置import路径,以及db连接,这部份与main.php类似。

    <?php
    // This is the configuration for yiic console application.
    // Any writable CConsoleApplication properties can be configured here.
    return array (
            'basePath' => dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . '..',
            'name' => 'My Console Application',
            'import' => array (
                    'application.models.*',
                    'application.components.*',
                    'application.components.base.*',
                    'application.components.imgthumb.*',
                    'application.models.form.*',
                    '等等,导入所要的类包'
            ),
            'components' => array (
                    // Main DB connection
                    'db' => array (
                            'connectionString' => 'mysql:host=localhost;dbname=数据库名称',
                            'emulatePrepare' => true,
                            'username' => '数据库名称',
                            'password' => '数据库密码',
                            'charset' => 'utf8',
                            'tablePrefix' => 'company_'、//表前缀
                    ),
                    'log' => array (
                            'class' => 'CLogRouter',
                            'routes' => array (
                                    array (
                                            'class' => 'CFileLogRoute',
                                            'levels' => 'error, warning'
                                    ) 
                            ) 
                    ) 
            ) 
    );

    4.继承CConsoleCommand写入自己的命令类,Yii提供了两种方式去执行,如果你执行单一的任务,直接在run方法里面写,另外一种 就是同写你的Controller(控制器),增加actionXXX即可。
    本实例采用第二种方式,即采用web程序开发的方式,在基础了CConsoleCommand的类中添加actionXXX方法来执行程序。
    我们在commands目录下创建一个文件,来执行我们要执行的任务,暂且命名为TestCommand.php 。

    <?php
    /**
     * 自动化执行 命令行模式
     */
    class TestCommand extends CConsoleCommand
    {
        public function run($args) {
            //所要执行的任务,如数据符合某条件更新,删除,修改
        }
    }

    4,打开你的linux命令窗口,创建自动任务。至于windows系统 ,是计划任务(win系统,可以谷歌如何操作),下面只讲linux系统。

    crontab -e
    ##然后输入
    1 * * * *  php /具体地址/protected/commands/crons.php Test >>/具体地址/protected/commands/test.log
    ##上面命令说明,每分钟执行Test任务一次,把日志保存在test.log下

    至此,自动化任务已完成。

    windows下面计划任务:

    schtasks /create /sc minute /mo 1 /tn "taskPhp" /tr  "php F:xampphtdocsphpyiiblog2protectedcommandscrons.php  CInsert insertData"

    删除计划任务 schtasks /delete /tn "taskPhp"

    每个1分钟就执行CInsert命令中的insertData方法。

    参考了:http://www.cnlvzi.com/index.php/Index/article/id/124

    http://www.yiiframework.com/wiki/221/cronjobsyii/

    http://986866294.blog.163.com/blog/static/1651222522013571578115/

    http://www.yiiframework.com/wiki/91/implementing-cron-jobs-with-yii/

    http://www.yiiframework.com/wiki/221/cronjobsyii/

    yii模拟消息队列发邮件:http://netyum.blog.163.com/blog/static/14175022011223287932/

    一篇文章:

    PHP使用1个crontab管理多个crontab任务

    http://www.binarytides.com/php-manage-multiple-cronjobs-with-a-single-crontab-entry/

    In many php applications there are multiple tasks that need to be run via cron at different times. In a typical application you may be doing the following tasks via cronjobs : 

    1. Backup database.
    2. Send out email to subscribers.
    3. Clear temporary files.
    4. Fetch xml feeds from some source and store them in database.

    So if you had separate php files doing these tasks , and had a cronjob entry for each , your cronjob could look like this :

    MAILTO="happy@birthday.com"
    0 0 * * * /var/www/my_app/backup_database.php
    12 2 * * * /var/www/my_app/email_to_subscribers.php
    10 5 * * * /var/www/my_app/clear_temp_files.php
    10 7 * * * /var/www/my_app/fetch_xml_feeds.php

    The above is the simplest approach to manage multiple cronjobs for your php application. However this approach has many drawbacks :

    1. Multiple entries in crontabs means more time and effort needed to edit the crontab and maintain it.

    - Since this approach involves writing each task separately in the cron list , it becomes difficult to maintain.

    2. The crontab command has to be used everytime a change is to be made.

    - You need to either manually do a `crontab -t` in the shell prompt or make your php application do it , everytime there is a change in either the tasks or their timing.

    3. If the script name changes then have to edit the crontab file again.
    4. A log email would be generated for every cron run, creating multiple log emails.

    - Every task that is running would generate a cronlog and email itself to the email specified

    5. Inefficient when there are 10s or 100s of tasks to be run via cron.

    - Do you think it is a good idea if you had many many tasks to do.

    An alternative solution

    How about having only 1 entry in the cronjobs, and that 1 cronjob manages the rest of the cronjobs.

    1. Add only 1 task to the crontab rule say :

    1
    * * * * * php /path/to/cronjob.php

    The cronjob.php file would run all the tasks that need to be run via cron. Its important to note that this cronjob.php will run every minute and forever. Do not be worried about it eating too much of system resources. It is a faily light thing and does not load your CPU or RAM with anything heavy.(注意这个cronjob.php会每分钟执行一次,而且一直会一直这样。不必担心这会消耗太多系统资源,这是一个非常轻量级的东西,它不会额外占用你的CPU和内存)

    Now the next thing would be to make sure cronjob.php can run all the tasks at the right time.

    2. Now we need to have different tasks have a different cron schedule. Lets say there are 3 different tasks to run at 3 different times :

    0 5 * * * database_backup
    0 5 1,15 * * monthly_sales_report
    0 10 15 02 * purchase_report
    
    
    

    The cronjob.php that runs every minute should have an array like this :

    1
    2
    3
    4
    5
    $cronjobs = array();
     
    $cronjobs['database_backup'] = '0 5 * * *';
    $cronjobs['monthly_sales_report'] = '0 5 1,15 * *';
    $cronjobs['purchase_report'] = '0 10 15 02 *';

    Now we test each job/task for the timestamp and run it like this :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    foreach($cronjobs as $method => $cron)
    {
        $time = time();
            if( is_time_cron($time , $cron) )
        {
            $result = $method();
            echo $result;
        }
    }

    is_time_cron checks if the current timestamp matches the cron schedule or not. If it matches , then the task is executed. Theis_time_cron method can be found in the previous post here.

    In this approach the benefits are :

    1. Only 1 crontab entry.

    The crontab list is clean and your application does not overload it.

    2. Easy to maintain , does not need any modification unless the script path/name changes.

    The crontab once created does not need any change unless the name or path of 'cronjob.php' changes. Meanwhile the jobs inside cronjob.php can change their names , schedules and anything very easily.

    3. To add/edit/remove tasks or change their time schedules only the cronjob.php needs to be changed.

    This means easier modification , maintenance and the application can provide simple user interface to make changes anytime without the need to use crontab commands or anything as such.

    The above mentioned approach can be applied to any language , not just php.

    附加:判断当前时间蹉是否符合某个cronjob

    http://www.binarytides.com/php-check-if-a-timestamp-matches-a-given-cron-schedule/

    PHP check if a timestamp matches a given cron schedule

    desktop:~$ php -a
    Interactive shell
     
    php > echo time();
    1319362432
    php >
    
    
    

    Above is an example of a given timestamp.

    And a cron schedule can look like this 0 5 * * * - which means run everyday at 5 hours and 0 minutes.

    Now in a php application you may need to test if a given timestamp , say 1319362432 matches a given cron schedule like 0 5 * * *.

    Here is a quick php function that can do this task.

    /**
        Test if a timestamp matches a cron format or not
        //$cron = '5 0 * * *';
    */
    function is_time_cron($time , $cron) 
    {
        $cron_parts = explode(' ' , $cron);
        if(count($cron_parts) != 5)
        {
            return false;
        }
         
        list($min , $hour , $day , $mon , $week) = explode(' ' , $cron);
         
        $to_check = array('min' => 'i' , 'hour' => 'G' , 'day' => 'j' , 'mon' => 'n' , 'week' => 'w');
         
        $ranges = array(
            'min' => '0-59' ,
            'hour' => '0-23' ,
            'day' => '1-31' ,
            'mon' => '1-12' ,
            'week' => '0-6' ,
        );
         
        foreach($to_check as $part => $c)
        {
            $val = $$part;
            $values = array();
             
            /*
                For patters like 0-23/2
            */
            if(strpos($val , '/') !== false)
            {
                //Get the range and step
                list($range , $steps) = explode('/' , $val);
                 
                //Now get the start and stop
                if($range == '*')
                {
                    $range = $ranges[$part];
                }
                list($start , $stop) = explode('-' , $range);
                     
                for($i = $start ; $i <= $stop ; $i = $i + $steps)
                {
                    $values[] = $i;
                }
            }
            /*
                For patters like :
                2
                2,5,8
                2-23
            */
            else
            {
                $k = explode(',' , $val);
                 
                foreach($k as $v)
                {
                    if(strpos($v , '-') !== false)
                    {
                        list($start , $stop) = explode('-' , $v);
                     
                        for($i = $start ; $i <= $stop ; $i++)
                        {
                            $values[] = $i;
                        }
                    }
                    else
                    {
                        $values[] = $v;
                    }
                }
            }
             
            if ( !in_array( date($c , $time) , $values ) and (strval($val) != '*') ) 
            {
                return false;
            }
        }
         
        return true;
    }
     
    var_dump(time() , '0 5 * * *');  //true or false

    How does it work

    The above code uses the date format specifiers as follows :
    'min' => 'i' ,
    'hour' => 'G' ,
    'day' => 'j' ,
    'mon' => 'n' ,
    'week' => 'w'

    over the timestamp to extract the minute , hour , day , month and week of a timestamp

    Then it checks the cron format by splitting it into parts like 0 , 5 , * , * , * and then tests each part for the corresponding value from timestamp.

     
     
    yii2 的commands
     
    <?php
    /**
     * @link http://www.yiiframework.com/
     * @copyright Copyright (c) 2008 Yii Software LLC
     * @license http://www.yiiframework.com/license/
     */
    
    namespace appcommands;
    
    use yiiconsoleController;
    
    /**
     * This command echoes the first argument that you have entered.
     *
     * This command is provided as an example for you to learn how to create console commands.
     *
     * @author Qiang Xue <qiang.xue@gmail.com>
     * @since 2.0
     */
    class HelloController extends Controller
    {
        /**
         * This command echoes what you have entered as the message.
         * @param string $message the message to be echoed.
         */
        public function actionIndex($message = 'hello world')
        {
            echo $message . "
    ";
        }
    }

    根目录运行yii hello you 即可。

    或形式如yii test/mail 

    yii <route> [--option1=value1 --option2=value2 ... argument1 argument2 ...]

  • 相关阅读:
    深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame
    深入理解定时器系列第一篇——理解setTimeout和setInterval
    idea自动生成方法注释(含参数及返回值)
    敲最少的键,编最多的码
    「HAOI2016」食物链
    「SCOI2015」小凸玩矩阵
    后缀自动机详解
    「TJOI2019」大中锋的游乐场
    「TJOI2019」唱、跳、rap 和篮球
    「TJOI2019」甲苯先生的滚榜
  • 原文地址:https://www.cnblogs.com/youxin/p/3584300.html
Copyright © 2011-2022 走看看