【发布时间】:2010-11-17 23:15:05
【问题描述】:
我想在登录页面中为我的登录表单操作(作为查询)添加一个重定向 URL,以便登录后,可以访问他或她浏览的上一个页面。
首先我考虑使用 Zend Session 并将每个页面的 url 保存在一个变量中。但我在文档中读到它有开销。那么,有没有更好的方法呢?还是有其他没有开销的使用 zend 会话的方法?
【问题讨论】:
标签: zend-framework url session redirect
我想在登录页面中为我的登录表单操作(作为查询)添加一个重定向 URL,以便登录后,可以访问他或她浏览的上一个页面。
首先我考虑使用 Zend Session 并将每个页面的 url 保存在一个变量中。但我在文档中读到它有开销。那么,有没有更好的方法呢?还是有其他没有开销的使用 zend 会话的方法?
【问题讨论】:
标签: zend-framework url session redirect
$this->_redirect($this->getRequest()->getServer('HTTP_REFERER'));
【讨论】:
如果您不喜欢通过会话传递变量,您可以尝试以安全的方式获取 $_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 ('/')
【讨论】:
此 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>';
}
}
【讨论】:
您可以尝试像这样使用 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"));
【讨论】:
首先,您需要获取重定向的原始 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->redirect = serialize($this->getRequest())。实际上这是我现在使用的解决方案,一年后;)
除了 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));
【讨论】:
我看到这已经有了答案,但我也想把我的也扔进去,就像使用静态方法给猫剥皮一样的另一种方式。
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)
【讨论】:
与 Jesta 在他的回答中所做的基本相同,但我将以下函数添加到我的“MW_Form”类中 - 这是我所有表单的超类 - 很容易从控制器以任何形式 $form->trackReferrer($this->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 创建的 <dl> 中的任何行:
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'));
}
}
【讨论】:
My_Form 类中,它扩展了 Zend_Form 并且我所有的表单都从这个扩展...
我在插件中有一个用于授权的预调度挂钩。如果(且仅当)用户需要登录,我将请求 URI 保存到会话中,并在登录后重定向到那里。除了重定向到登录表单时,没有任何开销。但这是开销没有问题的情况。 :)
if(!$auth->hasIdentity()){
$this->_insertLastUrlToSession();
$this->redirect('/index/login');
} else {
//no overhead
}
【讨论】:
我发现的一个简单方法就是在您的登录表单中添加一个隐藏字段。
现在,我不确定您的登录表单是通用 HTML 元素还是实际上是 Zend_Form 的实例,但如果它是 Zend_Form 的实例,您可以简单地添加以下内容:
$this->addElement('hidden', 'return', array(
'value' => Zend_Controller_Front::getInstance()->getRequest()->getRequestUri(),
));
然后在我的身份验证脚本中,就像上面的评论一样,我有一个简单的重定向,它使用传入的值将它们返回到同一页面。
$this->_redirect($this->_request->getPost('return'));
显然,在这两个示例中,它们只是为了压缩代码而编写的,可能并不代表完成它的最佳方式。在我的代码中使用getRequest() 的两种方法实际上并没有嵌入到redirect 或addElement 中,但出于示例目的,我只是将它们滑入其中。
上面的答案显然也可以,除非您正在进行大规模的页面重定向。我现在以这种方式运行我的主要原因是因为并非我的所有表单都在Zend_Form 中运行,并且能够更改隐藏的return 输入文本框的值以进行测试也很好。
【讨论】:
我确信在 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('/');
【讨论】: