【问题标题】:Redirect to previous page in zend framework重定向到zend框架中的上一页
【发布时间】:2010-11-17 23:15:05
【问题描述】:

我想在登录页面中为我的登录表单操作(作为查询)添加一个重定向 URL,以便登录后,可以访问他或她浏览的上一个页面。

首先我考虑使用 Zend Session 并将每个页面的 url 保存在一个变量中。但我在文档中读到它有开销。那么,有没有更好的方法呢?还是有其他没有开销的使用 zend 会话的方法?

【问题讨论】:

    标签: zend-framework url session redirect


    【解决方案1】:

    $this->_redirect($this->getRequest()->getServer('HTTP_REFERER'));

    【讨论】:

    • 它不保存状态。而且 HTTP_REFERER 并不总是可用。
    【解决方案2】:

    如果您不喜欢通过会话传递变量,您可以尝试以安全的方式获取 $_SERVER['HTTP_REFERER'] 变量。基本上,它会检查您的引荐来源网址是否与您的服务器本地名称和方案(http/https)匹配。

    class My_Tools
    {   
        public static function doesUrlMatchServerHttpHost($url)
        {       
            $scheme = Zend_Controller_Front::getInstance()->getRequest()->getScheme();
            $httpHost = Zend_Controller_Front::getInstance()->getRequest()->getHttpHost();
            $needleUrl = $scheme.'://'.$httpHost.'/';
            if (strpos($url, $needleUrl) !== 0)
            {
                return false;
            }
            return true;
        }
    
        public static function safelyGetReferrerUrl($default)
        {
            if ( isset($_SERVER['HTTP_REFERER']) == false){
                return $default;
            }
            if (self::doesUrlMatchServerHttpHost($_SERVER['HTTP_REFERER']) == false){
                return $default;
            }
            return $_SERVER['HTTP_REFERER'];
        }
    }
    

    然后就是

    $referrerUrl = My_Tools::safelyGetReferrerUrl('/');
    

    默认你可以设置本地 uri ('/')

    【讨论】:

      【解决方案3】:

      此 Zend 框架插件允许您保存当前和最后一个合格的 url 并过滤掉不需要的 url。随意使用和评论:

      <?php
      
      class Plugins_PageLog extends Zend_Controller_Plugin_Abstract
      {
          public function preDispatch(Zend_Controller_Request_Abstract $request){
              $module = $request->getModuleName();
              $controller = $request->getControllerName();
              $action = $request->getActionName();
              $params=$request->getParams();
      
              // to grap urls that are in default module, not in auth controller, and not an error url 
              $controller2= Zend_Controller_Front::getInstance();
              if ($controller2->getDispatcher()->isDispatchable($request) 
                  && ( $module == 'default' || $module == NULL )
                  && $controller != 'auth'
                  && ( !isset($params['error_handler']))
              ) {
      
                  // init 2 session variables: the current and last qualified url
                  if (!isset($_SESSION['redirect'])) $_SESSION['redirect'] = '';
                  if (!isset($_SESSION['last_visited_url'])) $_SESSION['last_visited_url'] = '';
      
                  // tempurl is to save current qualified url temporarily to ensure current and last qualified url will not be same
                  if (!isset($tempUrl)) $tempUrl = '';
                  if ($_SESSION['last_visited_url'] != $_SESSION['redirect']) {
                      $tempUrl = $_SESSION['redirect'];
                      $tempParams = $_SESSION['redirect_params'];
                  }
      
                  // save current qualified url
                  $_SESSION['redirect']=$request->getRequestUri();
                  $_SESSION['redirect_params'] = $params;
      
                  // to ensure there are no duplicated urls due to browser refresh 
                  if ($tempUrl != $_SESSION['redirect']){
                      $_SESSION['last_visited_url'] = $tempUrl;
                      $_SESSION['last_visited_url_params'] = $tempParams;
                  }
              }
      
              //echo '<pre>';var_dump($_SESSION['last_visited_url']);echo '</pre>';
              //echo '<pre>';var_dump($_SESSION['redirect']);echo '</pre>';
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以尝试像这样使用 HTTP_REFERRER 标头:

        // str_replace is the easiest way to get rid of domain - u can also preg_replace it   
        return str_replace("http://".Zend_Controller_Front::getInstance()->getRequest()->getServer("HTTP_HOST"),"",Zend_Controller_Front::getInstance()->getRequest()->getServer("HTTP_REFERER"));  
        

        【讨论】:

        • 它并不总是可用的。
        【解决方案5】:

        首先,您需要获取重定向的原始 url。 你可以通过 Zend_Controller_Request 类来做到这一点:

        $url = Zend_Controller_Front::getInstance()->getRequest()->getRequestUri();
        

        或者简单地说:

        $url = $_SERVER['REQUEST_URI'];
        

        然后,棘手的部分是通过用户请求传递它。 我推荐使用 Zend_Session 库,尽管使用 POST 参数也是合法的:

        $session = new Zend_Session_Namespace('Your-Namespace');
        $session->redirect = $_SERVER['REQUEST_URI'];
        

        请注意,我们保留的地址包括基本路径。 要在控制器类中重定向客户端,请禁用选项“prependBase”以丢失基本路径插入:

        $this->_redirect($url, array('prependBase' => false));
        

        【讨论】:

        • 也可以序列化请求对象:$session-&gt;redirect = serialize($this-&gt;getRequest())。实际上这是我现在使用的解决方案,一年后;)
        • 序列化请求对象保留所有接收到的数据,如 POST 数据。
        • @Morteza M. 您在哪里(或何时)使用您的方法重建请求?插件?
        • @Julian 只要你喜欢!例如,当用户发布需要特权的数据时,我序列化请求。将用户重定向到登录页面并成功登录后,我将他保存的请求反序列化并进行处理。是的,你可以在插件中做到这一点。
        • @Morteza M. 谢谢。效果很好!
        【解决方案6】:

        除了 gnarfs 答案之外,我还对其进行了修改以使其验证 - 对于那些喜欢它的人。

        $this->addDecorator(array('WrapClose' => 'HtmlTag'), array('tag' => 'div', 'placement' => 'PREPEND', 'closeOnly' => true));
        $this->addDecorator('Referrer'); 
        $this->addDecorator(array('WrapOpen' => 'HtmlTag'), array('tag' => 'div', 'placement' => 'PREPEND', 'openOnly' => true));
        

        【讨论】:

          【解决方案7】:

          我看到这已经有了答案,但我也想把我的也扔进去,就像使用静态方法给猫剥皮一样的另一种方式。

          class App_Helpers_LastVisited {
              /**
               * Example use:
               * App_Helpers_LastVisited::saveThis($this->_request->getRequestUri());
               */
              public static function saveThis($url) {
                  $lastPg = new Zend_Session_Namespace('history');
                  $lastPg->last = $url;
                  //echo $lastPg->last;// results in /controller/action/param/foo
              }
          
              /**
               * I typically use redirect:
               * $this->_redirect(App_Helpers_LastVisited::getLastVisited());
               */
              public static function getLastVisited() {
                  $lastPg = new Zend_Session_Namespace('history');
                  if(!empty($lastPg->last)) {
                      $path = $lastPg->last;
                      $lastPg->unsetAll();
                      return $path;
                  }
          
                  return ''; // Go back to index/index by default;
               }
          }
          

          这不会一直运行,仅在需要时运行。

          这就是全部代码,这里是我博客文章的一部分 (http://hewmc.blogspot.com/2010/08/simple-way-to-store-last-visited-url-in.html)

          【讨论】:

          • 谢谢。我读了你的博文和这个答案。您知道,当在案例应用程序中使用表单时,这个问题的公认答案非常简单,根本不使用会话。但是 Web 应用程序通常使用会话,因此添加另一个键/值对来存储以前的 url 没有意义,您的回答很有帮助。
          • 感谢您的回复,非常感谢您。并感谢您访问我的博客,我通常有咳咳,没有访客 :) 。实际上我已经更新了那篇博文,但只是我的态度更包容了其他用例,代码没有改变。祝你有美好的一天!
          【解决方案8】:

          与 Jesta 在他的回答中所做的基本相同,但我将以下函数添加到我的“MW_Form”类中 - 这是我所有表单的超类 - 很容易从控制器以任何形式 $form-&gt;trackReferrer($this-&gt;getRequest());。 getReferrer() 函数采用“默认”参数(如果用户禁用了 REFERER 标头,或者没有引荐来源 - 你会想要一个默认位置重定向回)

            /**
             * Adds a form element named "referrer" and sets its default value to either
             * the 'referrer' param from the request, or the HTTP_REFERER header.
             *
             * @param Zend_Controller_Request_Abstract $request 
             * @return MW_Form
             * @author Corey Frang
             */
            public function trackReferrer(Zend_Controller_Request_Abstract $request)
            {
              $this->addElement('hidden', 'referrer');
              $this->setDefault('referrer', 
                $request->getParam('referrer', 
                  $request->getServer('HTTP_REFERER')));
                  // HTTP_REFERER not HTTP_REFERRER - grrr HTTP spec misspellings
          
              // use no decorator for the actual form element
              $this->referrer->setDecorators(array()); 
          
              // use our custom "referrer" decorator to stick the hidden before the <dl>
              $decorators = $this->getDecorators();
              $this->clearDecorators();
              foreach ($decorators as $class=>$decorator)
              {
                if (substr($class,-5) == '_Form') {
                  $this->addDecorator('Referrer');
                  $added = true;
                }
                $this->addDecorator($decorator);
              }
              if (!$added) $this->addDecorator('Referrer');
          
              return $this;
            }
          
            /**
             * Returns the referrer field if it exists.
             *
             * @return string | false
             * @param mixed $default The value to return if referrer isn't set
             * @author Corey Frang
             **/
            public function getReferrer($default = false)
            {
              if (!isset($this->referrer)) return $default;
              $val = $this->referrer->getValue();
              if ($val) return $val;
              return $default;
            }
          

          使用的装饰器 - 为您提供了额外的好处,即不会用完由 zend_form 创建的 &lt;dl&gt; 中的任何行:

          class MW_Form_Decorator_Referrer extends Zend_Form_Decorator_Abstract  {
            /**
             * Attaches the standard "ViewHelper" decorator for the 'referrer' element
             * prepended on the content
             *
             * @return void
             * @author Corey Frang
             **/
            public function render($content)
            {
              $form = $this->getElement();
              if ($form instanceOf MW_Form)
              {
                $referrer = $form->referrer;
                if ($referrer)
                {
                  $decorator = new Zend_Form_Decorator_ViewHelper(array('placement'=>self::PREPEND));
                  $decorator->setElement($referrer);
                  return $decorator->render($content);
                }
              }
              return "Error - No Referrer Found".$content;
            }
          }
          

          示例用法(来自控制器):

          $form = $description->getEditForm();
          $form->trackReferrer($this->_request);
          if ($this->_request->isPost())
          {
            if ($form->process($this->_request->getPost()))
            {
              return $this->_redirect($form->getReferrer('/page'));
            }
          }
          

          【讨论】:

          • Gnarf 看起来不错。但是“trackReferrer”函数在哪个文件中?它是什么类型的课程?是帮手还是什么?
          • 它在我的 My_Form 类中,它扩展了 Zend_Form 并且我所有的表单都从这个扩展...
          【解决方案9】:

          我在插件中有一个用于授权的预调度挂钩。如果(且仅当)用户需要登录,我将请求 URI 保存到会话中,并在登录后重定向到那里。除了重定向到登录表单时,没有任何开销。但这是开销没有问题的情况。 :)

          if(!$auth->hasIdentity()){
            $this->_insertLastUrlToSession();
            $this->redirect('/index/login');
          } else {
            //no overhead
          }
          

          【讨论】:

          • 谢谢大家,所以,我将在 _insertLastUrlToSession 助手中使用新的 Zend_Session_Namespace 代替 Zend_Session::start(),哈?谢谢。
          【解决方案10】:

          我发现的一个简单方法就是在您的登录表单中添加一个隐藏字段。

          现在,我不确定您的登录表单是通用 HTML 元素还是实际上是 Zend_Form 的实例,但如果它是 Zend_Form 的实例,您可以简单地添加以下内容:

          $this->addElement('hidden', 'return', array(
                  'value' => Zend_Controller_Front::getInstance()->getRequest()->getRequestUri(),             
                      ));
          

          然后在我的身份验证脚本中,就像上面的评论一样,我有一个简单的重定向,它使用传入的值将它们返回到同一页面。

          $this->_redirect($this->_request->getPost('return'));
          

          显然,在这两个示例中,它们只是为了压缩代码而编写的,可能并不代表完成它的最佳方式。在我的代码中使用getRequest() 的两种方法实际上并没有嵌入到redirectaddElement 中,但出于示例目的,我只是将它们滑入其中。

          上面的答案显然也可以,除非您正在进行大规模的页面重定向。我现在以这种方式运行我的主要原因是因为并非我的所有表单都在Zend_Form 中运行,并且能够更改隐藏的return 输入文本框的值以进行测试也很好。

          【讨论】:

          • 谢谢 Mark 和 Jesta,我更喜欢 Jesta Answer。因为我做了很多路由、转发、preDispatch 功能等等!!!不管怎样,谢谢你。我等待更多答案。
          • 这个解决方案的问题是数据丢失。场景:用户登录到应用程序并加载表单。他开始填写表格。同时,会话到期,他需要重新登录。当他使用此解决方案提交表单时,他发布的数据会丢失。
          【解决方案11】:

          我确信在 ZF 的某个地方有一些内置的方法可以做到这一点,但我很懒,所以我这样做了:

          创建您自己的 App_Controller_Action 类(创建 /library/App/Controller/Action.php)。从这个类中扩展你所有的控制器

          在我的每个控制器中,我调用 $this->_initAuth(),函数粘贴在下面:

          protected function _initAuth()
          {
              $auth = Zend_Auth::getInstance();
              if (!$auth->hasIdentity() && strcmp($_SERVER['REQUEST_URI'], '/auth/login') <> 0)
                  $this->_redirect('/auth/login' . $_SERVER['REQUEST_URI']);
              else
                  $this->_identity = $auth->getIdentity();
          }
          

          在我的 AuthController 中,我执行以下操作以确保我的表单指向完整的 url:

          $uri = str_replace('/auth/login','',$_SERVER['REQUEST_URI']);
          if (strlen($uri) > 0)
              $form->setAction($this->_helper->url('login') . $uri);
          else
              $form->setAction($this->_helper->url('login'));
          

          如果登录验证通过,则执行以下操作:

          if (strlen($uri) > 0)
              $this->_redirect($uri);
          else
              $this->_redirect('/');
          

          【讨论】:

          • 显然,在您的应用程序上线之前,一旦您知道所有可能接受的输入,您需要清理 $uri,我还没有这样做
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-25
          • 1970-01-01
          • 2013-02-16
          • 2011-08-26
          • 1970-01-01
          相关资源
          最近更新 更多