php 从命令行运行 Zend Framework 操作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2325338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 06:03:05  来源:igfitidea点击:

Running a Zend Framework action from command line

phpzend-frameworkcommand-line

提问by Ariod

I would like to run a Zend Framework action to generate some files, from command line. Is this possible and how much change would I need to make to my existing Web project that is using ZF?

我想从命令行运行 Zend Framework 操作来生成一些文件。这可能吗?我需要对使用 ZF 的现有 Web 项目进行多少更改?

Thanks!

谢谢!

回答by akond

UPDATE

更新

You can have all this code adapted for ZF 1.12 from https://github.com/akond/zf-cliif you like.

如果您愿意,可以从https://github.com/akond/zf-cli为 ZF 1.12 调整所有这些代码。

While the solution #1 is ok, sometimes you want something more elaborate. Especially if you are expecting to have more than just one CLI script. If you allow me, I would propose another solution.

虽然解决方案 #1 没问题,但有时您想要更复杂的东西。特别是如果您希望拥有多个 CLI 脚本。如果您允许,我会提出另一种解决方案。

First of all, have in your Bootstrap.php

首先,在你的 Bootstrap.php 中有

protected function _initRouter ()
{
    if (PHP_SAPI == 'cli')
    {
        $this->bootstrap ('frontcontroller');
        $front = $this->getResource('frontcontroller');
        $front->setRouter (new Application_Router_Cli ());
        $front->setRequest (new Zend_Controller_Request_Simple ());
    }
}

This method will deprive dispatching control from default router in favour of our own router Application_Router_Cli.

此方法将剥夺默认路由器的调度控制权,转而使用我们自己的路由器 Application_Router_Cli。

Incidentally, if you have defined your own routes in _initRoutes for your web interface, you would probably want to neutralize them when in command-line mode.

顺便说一句,如果您在 _initRoutes 中为您的 Web 界面定义了自己的路由,您可能希望在命令行模式下中和它们。

protected function _initRoutes ()
{
    $router = Zend_Controller_Front::getInstance ()->getRouter ();
    if ($router instanceof Zend_Controller_Router_Rewrite)
    {
        // put your web-interface routes here, so they do not interfere
    }
}

Class Application_Router_Cli (I assume you have autoload switched on for Application prefix) may look like:

Application_Router_Cli 类(我假设您为应用程序前缀打开了自动加载)可能如下所示:

class Application_Router_Cli extends Zend_Controller_Router_Abstract
{
    public function route (Zend_Controller_Request_Abstract $dispatcher)
    {
        $getopt = new Zend_Console_Getopt (array ());
        $arguments = $getopt->getRemainingArgs ();
        if ($arguments)
        {
            $command = array_shift ($arguments);
            if (! preg_match ('~\W~', $command))
            {
                $dispatcher->setControllerName ($command);
                $dispatcher->setActionName ('cli');
                unset ($_SERVER ['argv'] [1]);

                return $dispatcher;
            }

            echo "Invalid command.\n", exit;

        }

        echo "No command given.\n", exit;
    }


    public function assemble ($userParams, $name = null, $reset = false, $encode = true)
    {
        echo "Not implemented\n", exit;
    }
}

Now you can simply run your application by executing

现在您可以通过执行简单地运行您的应用程序

php index.php backup

In this case cliAction method in BackupController controller will be called.

在这种情况下,将调用 BackupController 控制器中的 cliAction 方法。

class BackupController extends Zend_Controller_Action
{
    function cliAction ()
    {
        print "I'm here.\n";
    }
}

You can even go ahead and modify Application_Router_Cli class so that not "cli" action is taken every time, but something that user have chosen through an additional parameter.

您甚至可以继续修改 Application_Router_Cli 类,这样每次都不会执行“cli”操作,而是用户通过附加参数选择的操作。

And one last thing. Define custom error handler for command-line interface so you won't be seeing any html code on your screen

还有最后一件事。为命令行界面定义自定义错误处理程序,这样您就不会在屏幕上看到任何 html 代码

In Bootstrap.php

在 Bootstrap.php 中

protected function _initError ()
{
    $error = $frontcontroller->getPlugin ('Zend_Controller_Plugin_ErrorHandler');
    $error->setErrorHandlerController ('index');

    if (PHP_SAPI == 'cli')
    {
        $error->setErrorHandlerController ('error');
        $error->setErrorHandlerAction ('cli');
    }
}

In ErrorController.php

在 ErrorController.php 中

function cliAction ()
{
    $this->_helper->viewRenderer->setNoRender (true);

    foreach ($this->_getParam ('error_handler') as $error)
    {
        if ($error instanceof Exception)
        {
            print $error->getMessage () . "\n";
        }
    }
}

回答by David Snabel-Caunt

It's actually much easier than you might think. The bootstrap/application components and your existing configs can be reused with CLI scripts, while avoiding the MVC stack and unnecessary weight that is invoked in a HTTP request. This is one advantage to not using wget.

这实际上比您想象的要容易得多。引导程序/应用程序组件和您现有的配置可以与 CLI 脚本重用,同时避免在 HTTP 请求中调用的 MVC 堆栈和不必要的权重。这是不使用 wget 的优势之一。

Start your script as your would your public index.php:

像您的公共 index.php 一样启动您的脚本:

<?php

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH',
              realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV',
              (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
                                         : 'production'));

require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/config.php'
);

//only load resources we need for script, in this case db and mail
$application->getBootstrap()->bootstrap(array('db', 'mail'));

You can then proceed to use ZF resources just as you would in an MVC application:

然后,您可以像在 MVC 应用程序中一样继续使用 ZF 资源:

$db = $application->getBootstrap()->getResource('db');

$row = $db->fetchRow('SELECT * FROM something');

If you wish to add configurable arguments to your CLI script, take a look at Zend_Console_Getopt

如果您希望向 CLI 脚本添加可配置参数,请查看Zend_Console_Getopt

If you find that you have common code that you also call in MVC applications, look at wrapping it up in an object and calling that object's methods from both the MVC and the command line applications. This is general good practice.

如果您发现您也有在 MVC 应用程序中调用的公共代码,请考虑将其包装在一个对象中并从 MVC 和命令行应用程序调用该对象的方法。这是一般的良好做法。

回答by Saeven

Just saw this one get tagged in my CP. If you stumbled onto this post and are using ZF2, it's gotten MUCH easier. Just edit your module.config.php's routes like so:

刚刚看到这个被标记在我的 CP 中。如果您偶然发现了这篇文章并且正在使用 ZF2,那么它会变得容易得多。只需像这样编辑你的 module.config.php 的路由:

/**
 * Router
 */

'router' => array(
    'routes' => array(

        // .. these are your normal web routes, look further down
    ),
),

/**
 * Console Routes
 */
'console' => array(
    'router' => array(
        'routes' => array(

            /* Sample Route */
            'do-cli' => array(
                'options' => array(
                    'route'    => 'do cli',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'do-cli',
                    ),
                ),
            ),
        ),    
    ),
),

Using the config above, you would define doCliAction in your IndexController.php under your Application module. Running it is cake, from the command line:

使用上面的配置,您将在您的 Application 模块下的 IndexController.php 中定义 doCliAction。从命令行运行它是蛋糕:

php index.php do cli

php index.php 做 cli

Done! Way smoother.

完毕!顺畅多了。

回答by Saeven

akond's solution above is on the best track, but there are some subtleties that may may his script not work in your environment. Consider these tweaks to his answer:

上面 akond 的解决方案处于最佳轨道上,但有一些细微之处可能会使他的脚本在您的环境中无法正常工作。考虑对他的回答进行这些调整:

Bootstrap.php

引导程序

protected function _initRouter()
{
    if( PHP_SAPI == 'cli' )
    {
        $this->bootstrap( 'FrontController' );
        $front = $this->getResource( 'FrontController' );
        $front->setParam('disableOutputBuffering', true);
        $front->setRouter( new Application_Router_Cli() );
        $front->setRequest( new Zend_Controller_Request_Simple() );
    }
}

Init error would probably barf as written above, the error handler is probably not yet instantiated unless you've changed the default config.

初始化错误可能会如上文所述,错误处理程序可能尚未实例化,除非您更改了默认配置。

protected function _initError ()
{
    $this->bootstrap( 'FrontController' );
    $front = $this->getResource( 'FrontController' );
    $front->registerPlugin( new Zend_Controller_Plugin_ErrorHandler() );
    $error = $front->getPlugin ('Zend_Controller_Plugin_ErrorHandler');
    $error->setErrorHandlerController('index');

    if (PHP_SAPI == 'cli')
    {
        $error->setErrorHandlerController ('error');
        $error->setErrorHandlerAction ('cli');
    }
}

You probably, also, want to munge more than one parameter from the command line, here's a basic example:

您可能还想从命令行中处理多个参数,这是一个基本示例:

class Application_Router_Cli extends Zend_Controller_Router_Abstract
{
    public function route (Zend_Controller_Request_Abstract $dispatcher)
    {
        $getopt     = new Zend_Console_Getopt (array ());
        $arguments  = $getopt->getRemainingArgs();

        if ($arguments)
        {
            $command = array_shift( $arguments );
            $action  = array_shift( $arguments );
            if(!preg_match ('~\W~', $command) )
            {
                $dispatcher->setControllerName( $command );
                $dispatcher->setActionName( $action );
                $dispatcher->setParams( $arguments );
                return $dispatcher;
            }

            echo "Invalid command.\n", exit;

        }

        echo "No command given.\n", exit;
    }


    public function assemble ($userParams, $name = null, $reset = false, $encode = true)
    {
        echo "Not implemented\n", exit;
    }
}

Lastly, in your controller, the action that you invoke make use of the params that were orphaned by the removal of the controller and action by the CLI router:

最后,在您的控制器中,您调用的操作使用了因移除控制器和 CLI 路由器操作而孤立的参数:

public function echoAction()
{
    // disable rendering as required
    $database_name     = $this->getRequest()->getParam(0);        
    $udata             = array();

    if( ($udata = $this->getRequest()->getParam( 1 )) )
        $udata         = explode( ",", $udata );

    echo $database_name;
    var_dump( $udata );
}

You could then invoke your CLI command with:

然后,您可以使用以下命令调用您的 CLI 命令:

php index.php Controller Action ....

For example, as above:

例如,如上:

php index.php Controller echo database123 this,becomes,an,array

You'll want to implement a more robust filtering/escaping, but, it's a quick building block. Hope this helps!

您会想要实现更强大的过滤/转义,但是,这是一个快速构建块。希望这可以帮助!

回答by james tan

akond idea works great, except the error exception isnt rendered by the error controller.

akond 的想法很好用,除了错误控制器没有呈现错误异常。

public function cliAction() {
  $this->_helper->layout->disableLayout();
  $this->_helper->viewRenderer->setNoRender(true);

  foreach ($this->_getParam('error_handler') as $error) {
    if ($error instanceof Exception) {
      print "cli-error: " . $error->getMessage() . "\n";
    }
  }
}

and In Application_Router_Cli, comment off the echo and die statement

并在 Application_Router_Cli 中,注释掉 echo 和 die 语句

public function assemble($userParams, $name = null, $reset = false, $encode = true) {
//echo "Not implemented\n";
}

回答by antoineg

You cant use -O option of wget to save the output. But wget is clearly NOT the solution. Prefer using CLI instead.

您不能使用 wget 的 -O 选项来保存输出。但是 wget 显然不是解决方案。更喜欢使用 CLI。

回答by marsbomber

One option is that you could fudge it by doing a wget on the URL that you use to invoke the desirable action

一种选择是,您可以通过对用于调用所需操作的 URL 执行 wget 来捏造它

回答by Layke

You can just use PHP as you would normally from the command line. If you call a script from PHP and either set the action in your script you can then run whatever you want.

您可以像往常一样从命令行使用 PHP。如果您从 PHP 调用脚本并在脚本中设置操作,您就可以运行任何您想要的。

It would be quite simple really. Its not really the intended usage, however this is how it could work if you wanted to.

真的会很简单。它并不是真正的预期用途,但是如果您愿意,这就是它的工作方式。

For example

例如

 php script.php 

Read here: http://php.net/manual/en/features.commandline.php

在这里阅读:http: //php.net/manual/en/features.commandline.php

回答by Richard Knop

You can use wget command if your OS is Linux. For example:

如果您的操作系统是 Linux,则可以使用 wget 命令。例如:

wget http://example.com/controller/action

See http://linux.about.com/od/commands/l/blcmdl1_wget.htm

http://linux.about.com/od/commands/l/blcmdl1_wget.htm

UPDATE:

更新:

You could write a simple bash script like this:

您可以编写一个简单的 bash 脚本,如下所示:

if wget http://example.com/controller/action
    echo "Hello World!" > /home/wasdownloaded.txt
else
    "crap, wget timed out, let's remove the file."
    rm /home/wasdownloaded.txt
fi

Then you can do in PHP:

然后你可以在PHP中做:

if (true === file_exists('/home/wasdownloaded.txt') {
    // to check that the 
}

Hope this helps.

希望这可以帮助。

回答by hhs

I have used wget command

我用过 wget 命令

wget http://example.com/module/controller/action -O /dev/null

wget http://example.com/module/controller/action -O /dev/null

-O /dev/nullif you dont want to save the output

-O /dev/null如果你不想保存输出