我正在尝试在我的应用程序中使用Zend_acl。我遵循了《Zend框架在行动》一书。我添加了这个助手:
<?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);
}
}
控制器中未使用Helper。我试了试我的应用程序,看看是否一切正常,我得到了这个错误:
致命错误:第171行的/usr/share/php/ZendFramework-1.11.11/Zend/Filter/PregReplace.php中超过了30秒的最长执行时间
使用此调用堆栈:
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个请求设置是错误的。我也编辑了助手代码并添加了一条注释。
第二版:帕特里克,你说得太对了!!!我重新检查了一下,陷入了一个无限循环:不要访问登录页面=>转到登录页面:-D今天真是浪费时间。。。不管怎样,它的结局很好,谢谢大家。
if (!$this->_acl->isAllowed($role, $resource, $privilege)) {
$request->setModuleName('default');
$request->setControllerName('login');
$request->setActionName('login');
$request->setDispatched(false);
}
你确定无论角色如何,你都有权访问登录控制器吗?
不管怎样,听起来就像你最终进入了一个无限循环,ZF的调度循环永远不会完成。
如果调试器不可用,可以使用纯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 ) . ' → ' . print_r( $newValue, true );
}
public function emitVariableSetNew( $variableName, $newValue ) {
echo '<br />[global/init] '. $variableName . ' → ' . print_r( $newValue, TRUE );
}
}
将其传递给CSysTracer:
CSysTracer::setReportDelegate( new CSTSimpleReportDelegate() );
并使用以下选项启用语句跟踪:
CSysTracer::start( 5 );
当CSTSimpleReportDelegate打印输出时,它可以将内容写入日志文件,例如对某些语句进行选择性写入。
注意,这个版本的CSysTracer跟踪全局变量的变化。重写它以记录每条语句非常简单。
CSysTracer使用PHP的tick函数:
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 ];
}
}
}