Как отладить фатальную ошибку «Максимальное время выполнения»? - PullRequest
4 голосов
/ 17 февраля 2012

Я пытаюсь использовать Zend_acl в моем приложении. Я следовал книге «Zend Framework в действии». Я добавил этот помощник:

<?php
/**
* Zend Framework
*
* LICENSE "removed for clarity"
*

/** Zend_Controller_Action_Helper_Abstract */
require_once 'Zend/Controller/Action/Helper/Abstract.php';



class Bravo_Controller_Action_Helper_Acl extends Zend_Controller_Action_Helper_Abstract
{

    protected $_action;

    protected $_auth;

    protected $_acl;

    protected $_controllerName;

    public function __construct(Zend_View_Interface $view = null, array $options = array())
    {
        $this->_auth = Zend_Auth::getInstance();
        $this->_acl = $options['acl'];
        //var_dump($this->_acl);die();
    }

    public function init()
    {
        $this->_action = $this->getActionController();

        // add resource for this controller
        $controller = $this->_action->getRequest()->getControllerName();
        if(!$this->_acl->has($controller)) {
            $this->_acl->add(new Zend_Acl_Resource($controller));
        }

    }

    public function preDispatch()
    {
        $role = 'guest';
        if ($this->_auth->hasIdentity()) {
            $user = $this->_auth->getIdentity();
            if(is_object($user)) {
                $role = $this->_auth->getIdentity()->getUral()->getUralAccessNbr();
            }
        }

        $request = $this->_action->getRequest();
        $controller = $request->getControllerName();
        $action = $request->getActionName();
        $module = $request->getModuleName();
        $this->_controllerName = $controller;

        $resource = $controller;
        $privilege = $action;

        if (!$this->_acl->has($resource)) {
            $resource = null;
        }

        //** EDIT: During my test, the user isn't allowed. I'm now suspecting the 4 requests setting to be wrong.
        if (!$this->_acl->isAllowed($role, $resource, $privilege)) {
            $request->setModuleName('default');
            $request->setControllerName('login');
            $request->setActionName('login');
            $request->setDispatched(false);            
        }

    }


    public function allow($roles = null, $actions = null)
    {
        $resource = $this->_controllerName;
        $this->_acl->allow($roles, $resource, $actions);
        return $this;
    }

    public function deny($roles = null, $actions = null)
    {
        $resource = $this->_controllerName;
        $this->_acl->deny($roles, $resource, $actions);
       return $this;
    }

}

И бутстрап:

<?php

class Agenda_Bootstrap extends Zend_Application_Module_Bootstrap
{

    protected function _initAcl()
    {

        // acl action helper
        $acl = new Bravo_Acl_Acl();
        $aclHelper = new Bravo_Controller_Action_Helper_Acl(null, array('acl' => $acl));
        Zend_Controller_Action_HelperBroker::addHelper($aclHelper);
    }
}

Помощник не используется в контроллере. Я попробовал мое приложение, чтобы увидеть, все ли было правильно, и я получил эту ошибку:

Неустранимая ошибка: превышено максимальное время выполнения 30 секунд в /usr/share/php/ZendFramework-1.11.11/Zend/Filter/PregReplace.php в строке 171

С этим стеком вызовов:

Call Stack
#   Time    Memory  Function                                                Location
1   0.0001  314556  {main}( )                                               ../index.php:0
2   0.3275  2039356 Zend_Application->run( )                                ../index.php:29
3   0.3275  2039356 Zend_Application_Bootstrap_Bootstrap->run( )                ../Application.php:366
4   0.3276  2039412 Zend_Controller_Front->dispatch( )                      ../Bootstrap.php:97
5   31.7462 4813252 Zend_Controller_Dispatcher_Standard->dispatch( )        ../Front.php:954
6   31.7470 4813944 Zend_Controller_Action->__construct( )                      ../Standard.php:268
7   31.7470 4814144 Zend_Controller_Action_HelperBroker->__construct( )     ../Action.php:132
8   31.7472 4814924 Zend_Controller_Action_Helper_ViewRenderer->init( )     ../HelperBroker.php:253
9   31.7472 4814924 Zend_Controller_Action_Helper_ViewRenderer->initView( )     ../ViewRenderer.php:516
10  31.7473 4815260 Zend_Controller_Action_Helper_ViewRenderer->_getBasePath( ) ../ViewRenderer.php:469
11  31.7478 4815628 Zend_Filter_Inflector->filter( )                        ../ViewRenderer.php:393
12  31.7489 4816768 Zend_Filter_Word_CamelCaseToSeparator->filter( )        ../Inflector.php:473
13  31.7489 4816768 Zend_Filter_PregReplace->filter( )               ../CamelCaseToSeparator.php:46

Я пытался увеличить max_execution_time, но он всегда один и тот же: первые четыре стека остаются неизменными, а пятый отражает max_execution_time (30 секунд => 31,7462, 40 секунд => 42,6546 и т. Д.)

Так что я подозреваю, что Zend_Controller_Front->dispatch( ) является моим источником проблем, но почему всегда требуется максимальное время? Я немного смущен. У кого-то есть представление о том, куда мне копать?

РЕДАКТИРОВАТЬ: я иду дальше в моем отладке. Теперь я подозреваю, что настройка 4 запросов неверна в моем помощнике, когда пользователю не разрешено. Я тоже отредактировал код помощника и добавил комментарий.

EDIT2: Патрик, ты так прав !!! Я перепроверил, и я попал в бесконечный цикл: not-have-acces-to-login-page => go-to-login-page :-D Какая трата времени сегодня ... в любом случае все заканчивается хорошо, спасибо все.

Ответы [ 2 ]

5 голосов
/ 17 февраля 2012
if (!$this->_acl->isAllowed($role, $resource, $privilege)) {
    $request->setModuleName('default');
    $request->setControllerName('login');
    $request->setActionName('login');
    $request->setDispatched(false);            
}

Вы уверены, что у вас всегда есть разрешение на доступ к контроллеру входа независимо от роли?

В любом случае, звучит так, что вы попали в бесконечный цикл, где диспетчерский цикл ZFникогда не завершается.

1 голос
/ 17 февраля 2012

Если отладчик недоступен, вы можете использовать чистый код PHP. Вот вариант, использующий небольшой вспомогательный класс CSysTracer.

На основе этого интерфейса:

abstract class CSTReportDelegate {

    abstract public function emitVariableChange( $variableName, $oldValue, $newValue );
    abstract public function emitVariableSetNew( $variableName, $newValue );

}

создал этот конкретный экземпляр

class CSTSimpleReportDelegate extends CSTReportDelegate {

    public function emitVariableChange( $variableName, $oldValue, $newValue ) {
        echo '<br />[global/change] '. $variableName . ' : ' . print_r( $oldValue, true ) . ' &rarr; ' . print_r( $newValue, true );
    }

    public function emitVariableSetNew( $variableName, $newValue ) {
        echo '<br />[global/init] '. $variableName . '   &rarr; ' . print_r( $newValue, TRUE );
    }

}

... передать его в CSysTracer:

CSysTracer::setReportDelegate( new CSTSimpleReportDelegate() );

... и включите трассировку операторов, используя это:

CSysTracer::start( 5 );

Хотя CSTSimpleReportDelegate печатает вывод, он может записывать данные в файл журнала и, например, делать выборочные записи по определенным утверждениям.

Обратите внимание, что эта версия CSysTracer отслеживает изменения глобальной переменной. Переписать его для записи каждого оператора довольно просто.

CSysTracer добивается цели, используя тиковую функцию PHP :

class CSysTracer {

    static protected 
        $reportDelegate;

    static private 
        $globalState = array();

    static private  
        $traceableGlobals = array();

    static private 
        $globalTraceEnabled = FALSE;

    const 
        DEFAULT_TICK_AMOUNT = 1;

    static public 
    function setReportDelegate( CSTReportDelegate $aDelegate ) {
        self::$reportDelegate = $aDelegate;
    }


    static public 
    function start( $tickAmount = self::DEFAULT_TICK_AMOUNT ) {

        register_tick_function ( array( 'CSysTracer', 'handleTick' ) );

    }


    static public 
    function stop() {

        unregister_tick_function( array( 'CSysTracer', 'handleTick' ) );

    }

    static public 
    function evalAndTrace( $someStatement ) {

        declare( ticks = 1 ); {
            self::start();
            eval( $someStatement );
            self::stop();
        }
    }

    static public 
    function addTraceableGlobal( $varName ) {

        if ( is_array( $varName )) {
            foreach( $varName as $singleName ) {
                self::addTraceableGlobal( $singleName ); 
            }
            return;
        }

        self::$traceableGlobals[ $varName ] = $varName;

    }

    static public 
    function removeTraceableGlobal( $varName ) {
        unset( self::$traceableGlobals[ $varName ] );   
    }

    /**
     * Main function called at each tick. Calls those functions, which
     * really perform the checks.
     * 
     */
    static public 
    function handleTick( ) {

        if ( TRUE === self::$globalTraceEnabled ) { 
            self::traceGlobalVariable();
        }

    }

    static public 
    function enableGlobalsTrace() {
        self::$globalTraceEnabled = TRUE;   
    }


    static public 
    function disableGlobalsTrace() {
        self::$globalTraceEnabled = FALSE;  
    }

    static public 
    function traceGlobalVariable( ) {

        foreach( self::$traceableGlobals as $aVarname ) {

            if ( ! isset( $GLOBALS[ $aVarname ] )) {
                continue;
            }

            if ( ! isset( self::$globalState[ $aVarname ] ) ) {

                self::$reportDelegate->emitVariableSetNew( $aVarname, $GLOBALS[ $aVarname ] );
                self::$globalState[ $aVarname ] = $GLOBALS[ $aVarname ];
                continue;
            }

           if ( self::$globalState[ $aVarname ] !== $GLOBALS[ $aVarname ]) {

             self::$reportDelegate->emitVariableChange( $aVarname, self::$globalState[ $aVarname ], $GLOBALS[ $aVarname ] );

           }

           self::$globalState[ $aVarname ] = $GLOBALS[ $aVarname ];

        }

    }

}
...