使用Zend Framework创建cronjob

时间:2008-09-27 09:43:41

标签: php zend-framework cron command-line-interface

我正在尝试编写一个cronjob控制器,所以我可以调用一个网站并执行所有模块cronjob.php。现在我的问题是我该怎么做?

curl是一个选项,所以我也可以计算错误和成功吗?

[更新]

我想我还没有解释得够。

我想要做的是有一个文件,我可以从http://server/cronjob调用,然后让它执行每个/application/modules/*/controller/CronjobController.php或者有另一种方法这样做所有cronjobs不在一个地方,而是在模块所在的同一个地方。这将为我提供优势,如果模块不存在,它不会尝试运行其cronjob。

现在我的问题是你将如何执行CronjobController的所有模块,或者你会以完全不同的方式执行它,以便它仍然保持模块化?

我希望能够分辨出有多少cronjobs成功运行,有多少没有

14 个答案:

答案 0 :(得分:12)

经过一些研究和拖延之后,我得出了一个简单的结论:一个ZF化的cron脚本应该包含你所有的zend框架应用程序的功能 - 没有所有的查看内容。我通过在我的应用程序目录中创建一个新的cronjobfoo.php文件来完成此操作。然后我从最低限度开始: -my前端控制器(index.php) -my bootstrap.php

我拿出了所有视图内容并专注于保持环境设置,数据库设置,自动加载器和&注册表设置。我不得不花一点时间来纠正文档根变量并删除从我的bootstrap中复制的一些OO功能。

之后,我只是编码了..在我的情况下,它正在编译并通过电子邮件发送夜间报告。使用Zend_Mail非常棒。当我确信我的脚本按照我想要的方式工作时,我只是添加了我的crontab。

祝你好运!

答案 1 :(得分:9)

对于Zend Framework我目前正在使用下面概述的代码。该脚本仅包含门户文件index.php,其中所有路径,环境和其他Zendy代码都是自举的。通过在cron脚本中定义一个常量,我们取消了运行应用程序的最后一步。

这意味着应用程序只是设置,甚至没有自举。在这一点上,我们开始引导我们需要的资源,那就是

//public/index.php

if(!defined('DONT_RUN_APP') || DONT_RUN_APP == false) {  
    $application->bootstrap()->run();
}

// application/../cron/cronjob.php

define("DONT_RUN_APP",true);
require(realpath('/srv/www/project/public/index.php'));
$application->bootstrap('config');
$application->bootstrap('db');

//cron code follows

答案 2 :(得分:6)

我会提醒你的cronjobs是公众可以访问的,因为它们可能会在正常时间之外触发,并且根据它们的作用会导致问题(我知道这不是你想要的,而是把它们放到一个实际的控制器中它可以从浏览器访问)。例如,我有一个发送电子邮件的cron。如果有人找到了cron URL并且刚刚开始点击它,我会不断发送垃圾邮件。

我做的是创建一个cron文件夹,并在那里创建了一个heartbeat.php,它为我引导了Zend Framework(减去MVC)。它检查一个数据库,该数据库包含所有已安装的cron作业的列表,如果是时候运行它们,则生成一个cron作业类的实例并运行它。

cron作业只是来自抽象cron类的子类,它包含install(),run(),deactivate()等方法。

为了解雇我的工作,我只有一个简单的crontab条目,每隔5分钟运行一次,命中heartbeat.php。到目前为止,它在两个不同的网站上都很棒。

答案 3 :(得分:2)

有人在几天前就fw-general(this blog entry提到了mailinglist,我建议你在使用Zend框架时阅读。{/ p>

还有Zend_Controller_Request_Cli的提案,应该迟早要解决这个问题。

答案 4 :(得分:2)

我可以访问专用服务器,我最初为cron作业提供了不同的引导程序。我最终讨厌这个想法,只是希望我能在现有的MVC设置中做到这一点而不必费心去处理。

我创建了一个文件cron.sh,保存在我的站点root(不公开)中,并在其中我放了一系列我想要运行的命令。因为我想立即运行许多命令,我像往​​常一样在我的控制器中编写PHP,并在cron.sh中添加了对这些URL的curl调用。例如curl http://www.mysite.com/cron_controller/action然后在cron界面上我运行了bash /path/to/cron.sh

正如其他人所指出的那样,任何猜测网址的人都可以解雇你的crons,所以总会有警告。您可以通过多种方式找到解决方案。

答案 5 :(得分:1)

为什么不创建一个crontab.php,包括或需要index.php引导程序文件?

考虑到引导程序正在执行Zend_Loader::registerAutoload(),您可以直接开始使用模块,例如myModules_MyClass::doSomething();

这样你就可以跳过控制器了。 Controller作业是通过http控制访问。在这种情况下,您不需要控制器方法,因为您正在本地访问。

答案 6 :(得分:1)

看看zf-cli

这可以很好地处理所有cron工作。

答案 7 :(得分:0)

http://framework.zend.com/wiki/display/ZFPROP/Zend_Scheduler+-+Matthew+Ratzloff?rootCommentId=1819我通过googleing找到的这个链接似乎也非常令人兴奋。

我所寻找的并不安静,但如果我无法找到我想要的东西,我将不得不为自己。

答案 8 :(得分:0)

您是否有文件系统访问模块的目录?您可以迭代目录并确定CronjobController.php可用的位置。然后你可以使用Zend_Http_Client通过HTTP访问控制器或使用像Zend_Test_PHPUnit这样的方法:在本地模拟实际的调度过程。

答案 9 :(得分:0)

您可以设置一个数据库表来保存对cronjob脚本的引用(在您的模块中),然后在pass / fail上使用带有返回值的exec命令。

答案 10 :(得分:0)

我用this post扩展了格雷戈回答。这就是出现的结果:

//public/index.php 

// Run application, only if not started from command line (cli)
if (php_sapi_name() != 'cli' || !empty($_SERVER['REMOTE_ADDR'])) {
    $application->run();
}

谢谢格雷戈尔!

答案 11 :(得分:0)

我的解决方案:

  • curl / cron
  • 全局cron方法将include_once所有控制器
  • 检查每个控制器是否具有 - > cron方法
  • 如果有,请运行那些。

公共cron url(用于curl)不是问题,有很多方法可以避免滥用。如上所述,检查远程IP是最简单的。

答案 12 :(得分:0)

这是我用Zend Framework运行Cron Jobs的方法

Bootstrap 中,我将保持环境设置,因为它是负MVC:

public static function setupEnvironment()
{
     ...
     self::setupFrontController();
     self::setupDatabase();
     self::setupRoutes();
     ...
     if (PHP_SAPI !== 'cli') { 
          self::setupView();
          self::setupDbCaches();
     }
     ...
}

同样在Bootstrap中,我将修改setupRoutes并添加自定义路线:

public function setupRoutes()
{   
    ...
    if (PHP_SAPI == 'cli') { 
        self::$frontController->setRouter(new App_Router_Cli());
        self::$frontController->setRequest(new Zend_Controller_Request_Http());        
    }
}

App_Router_Cli 是一种新的路由器类型,它根据此类请求确定控制器,操作和可选参数:script.php controller=mail action=send。我在这里找到了这个新的路由器:Setting up Cron with Zend Framework 1.11

class App_Router_Cli extends Zend_Controller_Router_Abstract 
{
    public function route (Zend_Controller_Request_Abstract $dispatcher) 
    {
        $getopt = new Zend_Console_Getopt (array());
        $arguments = $getopt->getRemainingArgs();
        $controller = "";
        $action = "";
        $params = array();

        if ($arguments) {

            foreach($arguments as $index => $command) {

                $details = explode("=", $command);

                if($details[0] == "controller") {
                    $controller = $details[1];
                } else if($details[0] == "action") {
                    $action = $details[1];
                } else {
                    $params[$details[0]] = $details[1];
                }
            }

            if($action == "" || $controller == "") {
                die("Missing Controller and Action Arguments == You should have: 
                     php script.php controller=[controllername] action=[action]");
            }
            $dispatcher->setControllerName($controller);
            $dispatcher->setActionName($action);
            $dispatcher->setParams($params);

            return $dispatcher;
        }
        echo "Invalid command.\n", exit;
        echo "No command given.\n", exit;
    }

    public function assemble ($userParams, $name = null, $reset = false, $encode = true)
    {
        throw new Exception("Assemble isnt implemented ", print_r($userParams, true));
    }
}

CronController 中,我做了一个简单的检查:

public function sendEmailCliAction()
{   
    if (PHP_SAPI != 'cli' || !empty($_SERVER['REMOTE_ADDR'])) { 
        echo "Program cannot be run manually\n";
        exit(1);
    } 
    // Each email sent has its status set to 0;

Crontab运行此类命令:

    * * * * * php /var/www/projectname/public/index.php controller=name action=send-email-cli >> /var/www/projectname/application/data/logs/cron.log

答案 13 :(得分:0)

在同一目录或cron作业文件夹中运行引导程序没有任何意义。我创建了一种更好,更轻松的方法来实施cron作业。请遵循以下几点,使您的工作变得轻松而聪明:

  1. 创建一个cron作业文件夹,例如“ cron”或“ crobjob”等。

  2. 有时,我们需要cron作业以可以在服务器上设置的不同间隔(例如1小时间隔或1天间隔)在服务器上运行。

  3. 在cron作业文件夹中创建一个文件,就像我创建一个“ init.php”一样,现在假设您想每天一次向用户发送新闻通讯。您无需在init.php中执行zend代码。

  4. 因此,只需在init.php中设置curl函数,然后在该curl函数中添加控制器操作的URL。因为我们的主要目的是每天都应该采取行动。例如,URL应该是这样的:

https://www.example.com/cron/newsletters

因此,在curl函数中设置此URL,并在同一文件中的init.php中调用此函数。

在上面的链接中,您可以看到“ cron”是控制器,新闻稿是可以执行工作的操作,以相同的方式,不需要运行引导文件等。