可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to add a redirection URL to my login forms action (as a query) in login page, so after loging-in, one can visit the previous page he or she was surfing.
First I thought about using Zend Session and save the url of each page in a variable. but I read in the documentation that it has overhead. So, is there a better way to do so? or is there an other way to use zend session with no overhead?
回答1:
First, you need to grab the original url for the redirection.
You can do that by the Zend_Controller_Request class via:
$url = Zend_Controller_Front::getInstance()->getRequest()->getRequestUri();
or simply by:
$url = $_SERVER['REQUEST_URI'];
Then, the tricky part is to pass it through the user request.
I recommend to use the library Zend_Session, despite using a POST parameter is also legitimate:
$session = new Zend_Session_Namespace('Your-Namespace');
$session->redirect = $_SERVER['REQUEST_URI'];
Please note that the address we kept includes the base path.
To redirect the client in the controller class, disable the option 'prependBase' to lose the base path insertion:
$this->_redirect($url, array('prependBase' => false));
回答2:
What I have found as a simple method to accomplish this is just to have a hidden field in your login form.
Now, im not sure if your login form is a generic HTML element or is actually an instance of Zend_Form
, but if its an instance of Zend_Form
, you could simple add the following:
$this->addElement('hidden', 'return', array(
'value' => Zend_Controller_Front::getInstance()->getRequest()->getRequestUri(),
));
Then in my authentication script, like the comment above, I have a simple redirect that uses the value passed in to return them to the same page.
$this->_redirect($this->_request->getPost('return'));
Obviously in these two examples, they are just written to compact the code and probably do not represent the best way to accomplish it. The two methods using the getRequest()
in my code are actually not embedded in the redirect
or the addElement
, but for example purposes I just slid them in there.
The answer above will obviously work as well, unless you have some massive page redirection going on. The main reason I am running mine this way right now is because not all of my forms are running in Zend_Form
and its also nice being able to change the value of the hidden return
input text box for testing purposes.
回答3:
Basically the same thing that Jesta is doing in his answer, but I added the following functions to my "MW_Form" class - which is a superclass of all my forms - easy enough to $form->trackReferrer($this->getRequest());
from the controller with any form. The getReferrer() function takes a "default" argument (which if the user has REFERER headers disabled, or there is no referrer - your going to want a default place to redirect back to)
/**
* 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;
}
The Decorator Used - gives you the added benifit of not using up any rows in the <dl>
created by zend_form:
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;
}
}
Example Usage (from a controller):
$form = $description->getEditForm();
$form->trackReferrer($this->_request);
if ($this->_request->isPost())
{
if ($form->process($this->_request->getPost()))
{
return $this->_redirect($form->getReferrer('/page'));
}
}
回答4:
I have a predispatch hook in plugin for authorization. In it if (and only if) user needs to be logged I save the request URI to session and after logging in I redirect there. There is no overhead except when redirecting to login form. But that's a case where overhead is no problem. :)
if(!$auth->hasIdentity()){
$this->_insertLastUrlToSession();
$this->redirect('/index/login');
} else {
//no overhead
}
回答5:
I see this already has an answer, but i'd like to throw mine in too, just as a different way to skin the cat sort of deal, using static methods.
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;
}
}
This doesn't run all the time, only on a need to basis.
That's the whole code, part of my blog post here (http://hewmc.blogspot.com/2010/08/simple-way-to-store-last-visited-url-in.html)
回答6:
This Zend framework plugin allows you to save current and last qualified url and filter out unwanted urls. feel free to use and comment:
<?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>';
}
}
回答7:
In addition to gnarfs answer, i modified it to making it validate - for those of you that get a kick of it.
$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));
回答8:
You can try using HTTP_REFERRER header like this:
// 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"));
回答9:
If you are not a fan of passing variables via session you could try to get $_SERVER['HTTP_REFERER'] variable in a safe way. Basically it checks if your referrer url and matches with your server local name, and scheme (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'];
}
}
And then just
$referrerUrl = My_Tools::safelyGetReferrerUrl('/');
As default you can set local uri ('/')
回答10:
$this->_redirect($this->getRequest()->getServer('HTTP_REFERER'));
回答11:
I'm sure there is some built in method for doing this somewhere in ZF, but I'm lazy, so I did it this way:
Create your own App_Controller_Action class (create /library/App/Controller/Action.php). Extend all of your controllers off of this class
In each of my controllers, I call $this->_initAuth(), function pasted below:
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();
}
In my AuthController, I do the following to make sure my form points to the full 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 the login validates, then I do the following:
if (strlen($uri) > 0)
$this->_redirect($uri);
else
$this->_redirect('/');