doucan957495
2013-10-07 11:02 阅读 41
已采纳

验证失败后Zend _forward不起作用(Zend Framework 1)

After a user fails authorisation I'd like to forward them back to the login page. Currently the _forward method causes Zend to hang and give a time out error (30 seconds exceeded).

The code for the login page handles both a login and signup form, and forwards to the authorisation controller:

public function indexAction() {

    if ($this->_request->isPost()) {
        $formData = $this->_request->getPost();

        if (array_key_exists('signUp', $formData)) {
            $authAction = 'signup';
            $form = 'signupForm';
        } elseif (array_key_exists('logIn', $formData)) {
            $authAction = 'login';
            $form = 'loginForm';
        }

        if ($this->$form->isValid($formData)) {
            $this->_forward($authAction, 'user-auth', null, $formData);
        } else {
            $this->$form->populate($formData);
        }
    }
}

This works fine and redirects to the auth controller successfully. The code inside the login action of the auth controller is as such:

public function loginAction() {
    $formData = $this->_request->getPost();

    $authAdapter = new My_Auth_Adapter();
    $authAdapter->setTableName('user')
                ->setIdentity($formData['username'])
                ->setCredential($formData['password'])
                ->setIdentityColumn('username')
                ->setCredentialColumn('password');
    $result = $authAdapter->authenticate();

    if ($result->isValid()) {
        // success, all good
    } else {
        $this->_forward('index', 'login', 'default', $formData);
    } 
}

We arrive here fine, and a successful authorisation works as expected. However in my else statement placing another forward back to the original login controller (I wish to populate the username as well as post back an error message) causes the program to hang, although a redirect works fine.

I thought it may be because the login controller is re-detecting the post data and I'm getting caught in an infinite loop, but removing the $formData as the last argument of the forward doesn't change anything.

I've also tried $formData['errMsg'] = 'whatever' above the forward and then checking if the key exists or if it is set in the login controller, but that doesn't change a thing either.

Interestingly, the time out error I receive references the Auth DbTable Adapter:

Fatal error: Maximum execution time of 30 seconds exceeded in /Applications/MAMP/MampServer/mysite/library/Zend/Auth/Adapter/DbTable.php on line 174

Any ideas as to what may be happening?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

2条回答 默认 最新

  • 已采纳
    douhao3562 douhao3562 2013-10-07 11:34

    I think you are infinity looping between loginAction() and indexAction().

    Check out the difference between the calls to forward() and redirect() action helpers. The former, forward() internally will change the $request->isDispatched() == false - This means that the front controller will execute the targeted controller action without a new HTTP request.

    The outcome of this is that $this->_request->isPost() will always be true and therefore $this->$form->isValid($formData) again will also be true, meaning your going around in circles.

    I know the below is a very different to your approach, however I believe it is a more conventional separation of concerns for Zend 1 controllers.

    // ... SomeController.php
    
      public function getLoginForm();
    
      public function getSignupForm();
    
      protected function authenticate($username, $password) 
      {
        $authAdapter = new My_Auth_Adapter();
        $authAdapter->setTableName('user')
                    ->setIdentity($username)
                    ->setCredential($password)
                    ->setIdentityColumn('username')
                    ->setCredentialColumn('password');
        $result = $authAdapter->authenticate();
    
        return ($result->isValid()) ? true : false;
      }
    
      public function indexAction()
      {
        $form = $this->getLoginForm();
        $request = $this->getRequest();
    
        if ($request->isPost()) {
          if ($form->isValid($request->getPost())) {
    
            if ($this->authenticate($form->getValue('username'), $form->getValue('username'))) {
              $this->redirect('/members'); // Successfully logged in
            }
          }
        }
        $this->view->form = $form;
      }
    
      public function signupAction()
      {
        // stuff only for signups! 
      }
    

    Edit To elaborate: forward() is a controller action helper. Its job is simply to modify the Zend_Controller_Request_Http instance. The Zend_Controller_Request_Http class is the one returned when you call $this->getRequest() within a controller.

    The Request instance encapsulates all access to $_POST, $_GET and stores then as values within the object. Calls such as $request->setParam('someparam', 123) set or get these values rather than the standard direct access to $_POST['someparam'] or $_GET['someparam'].

    The special case is with the values module,controller,action and dispatched. These are the key's used by the Zend_Controller_Front and the Dispatcher when trying to determine the correct controller to instantiate and action method to execute.

    A simplified example of how the dispatch loop works:

    while(! $request->isDispatched()) {
    
      $request->setDispatched(true);
    
      // If at any point here we change setDispatched(true)
      // perhaps in a controller action with a call to forward()
      // then the whole dispatch loop will be called again
      // perhaps creating a different controller
    
      $controllerName = $request->getControllerName();
      $actionName = $request->getActionName();
    
      $controller = new $controllerName();
      $controller->$actionName();
    
    }
    
    点赞 评论 复制链接分享
  • douxing5598 douxing5598 2013-10-07 11:31

    In the else block:

    $this->_redirect($this->url(array('login' => $formData['username'], 'nameOfYourRoute'));
    

    Added a new get variable 'login' to your route and populate your forms login with this variable.

    点赞 评论 复制链接分享

相关推荐