• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1968
  • Last Modified:

Zend Framework - redirect after login from restricted page

I am working on a site that registered users can input comments which are then emailed to other registered users - the email includes a link to the comment - but users must be logged in to read the comment.

What I want is for the user to click the link (from the email) - if they are not logged in they will go to a fail page that allows them to log in - when they log in, they will be redirected to the page from the email link.

Can someone give me some direction on how I would do this redirection?
0
blorriman
Asked:
blorriman
  • 7
  • 5
  • 3
  • +1
1 Solution
 
Ray PaseurCommented:
Yes, I can show you some of the basics, but you'll need to consider the best way to integrate these with the ZF.

Here is how to log out...
<?php // RAY_logout_example.php
error_reporting(E_ALL);

// MAN PAGE HERE: http://us.php.net/manual/en/book.session.php
// ALWAYS START THE SESSION ON EVERY PAGE
session_start();

// SEE IF THE CLIENT IS ALREADY LOGGED OUT
if (empty($_SESSION["uid"]))
{

// CLIENT IS NOT LOGGED IN
    echo "<br/>YOU ARE NOT LOGGED IN \n";
    echo "<br/>CLICK HERE TO <a href=\"RAY_login_example.php\">LOG IN</a>\n";
    die();
}

// SET THE EXPIRATION FOR COOKIES
define('COOKIE_LIFE', 60*60*24); // A 24-HOUR DAY IN SECONDS ( = 86,400 )
$cookie_expires	= time() - date('Z') - COOKIE_LIFE;

// CLEAR THE INFORMATION FROM THE $_SESSION ARRAY
$_SESSION = array();

// IF THE SESSION IS KEPT IN COOKIE, FORCE SESSION COOKIE TO EXPIRE
if (isset($_COOKIE[session_name()]))
{
   setcookie(session_name(), '', $cookie_expires, '/');
}

// TELL PHP TO ELIMINATE THE SESSION
session_destroy();


// OPTIONAL - CLEAR ALL COOKIES
// foreach ($_COOKIE as $key => $value)
// {
//    setcookie($key, '', $cookie_expires, '/');
// }

// OPTIONAL - REDIRECT TO THE HOME PAGE
// header("Location: /");
// exit;


// GIVE THE CLIENT A LINK TO THE LOGIN
echo "<br/>YOU ARE LOGGED OUT\n";
echo "<br/>CLICK HERE TO <a href=\"RAY_login_example.php\">LOG IN</a>\n";

Open in new window

0
 
Ali KayahanFull Stack DeveloperCommented:
from zend framework while u are in related action ;

 $this->_forward("your_errorController/your_errorAction");

from php directly ;

header("Location:your_errorController/your_errorAction");
0
 
Ray PaseurCommented:
Here is the access control function.  You put this after session_start() on any pages you want to protect
// QUICK AND EASY PASSWORD PROTECTION
function access_control($test=FALSE)
{
    // IF TEST ONLY
    if ($test !== FALSE)
    {
        if  (isset($_SESSION["U"])) return TRUE;
        if (!isset($_SESSION["U"])) return FALSE;
    }
    // IF NOT TEST CAUSE NEED FOR LOGIN
    if (!isset($_SESSION["U"]))
    {
        $_SESSION["entry_request_uri"] = $_SERVER["REQUEST_URI"];
        header("Location: login.php");
        exit;
    }
}

Open in new window

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
Ali KayahanFull Stack DeveloperCommented:
You should add a session check from related controller/action (that link goes to) and by the help of the code above i wrote if they logged in just forward them to related page , if they dont you can add a link property to Zend_Session_Namespace which stores the link , so if they login correctly you can forward them from login page
0
 
Ray PaseurCommented:
here is how to login - some local functions since I ripped this out of production code, but hopefully you can follow the logic.

Best regards, ~Ray
<?php // login.php

session_start();
error_reporting(E_ALL); // FOR DEBUGGING



// THE LOCATION FOR OUR DEPARTURE UPON SUCCESSFUL LOGIN
if (!isset($_SESSION["entry_request_uri"])) $_SESSION["entry_request_uri"] = "/";

// SET THIS IN CASE WE HAVE A BAD LOGIN
if (!empty($_POST)) $_SESSION["login_error"] = TRUE;

// UID + PWD PROCESSING
if ( (!empty($_POST["uid"])) &&
     (!empty($_POST["pwd"])) )
{

    $now = date('c');
    $uid = mysql_real_escape_string($_POST["uid"]);
    $pwd = mysql_real_escape_string($_POST["pwd"]);
    $sql = "UPDATE users SET lastlogin = '$now' WHERE uid = '$uid' AND pwd = '$pwd' ";
    if (!$res = mysql_query($sql)) { fatal_query_error($sql); }

    $sql = "SELECT * FROM users WHERE uid = '$uid' AND pwd = '$pwd' LIMIT 1";
    if (!$res = mysql_query($sql)) { fatal_query_error($sql); }
    $num = mysql_num_rows($res);
    if ($num)
    {
        $_SESSION["login_error"] = FALSE;
        $_SESSION["U"] = mysql_fetch_assoc($res);
        $_SESSION["U"]["pwd"] = '';
        header("Location: {$_SESSION["entry_request_uri"]}");
        exit;
    }
}






if (isset($_SESSION["login_error"]))
{
    if ($_SESSION["login_error"] !== FALSE);
    {
        $_SESSION["login_error"] = FALSE;
        echo "<h2><span style=\"color:firebrick;\">Login Error</span></h2>\n";
    }
}
echo "<h2>Please Log In</h2>\n";


?>
<form method="post" action="<?php echo $_SERVER["REQUEST_URI"]; ?>">
Please enter your Uid and Pwd for login
<table>
<tr><td>Uid </td><td><input name="uid" value="" /></td></tr>
<tr><td>Pwd </td><td><input name="pwd" value="" type="password" /></td></tr>
</table>
<input type="submit"  value="Login" />
</form>

Open in new window

0
 
AlexanderRCommented:
Do you use Zend_Auth and/or Zend_Acl.  Its much easier with it.

Without knowing your full structure i can only provide generalized code.

In your comment controller's init() method have something similar to.
if(Zend_Auth::getInstance()->hasIdentity()){
            $this->_redirect('loginController/loginAction'); //controller action combination for login
}

If you use Zend_Acl you can use isAllowed method too in if statement.
0
 
blorrimanAuthor Commented:
Thanks for your responses.  To clarify what I am doing, I am using Zend_Auth:

class MemberController extends Zend_Controller_Action
{
public function init()
    {
        $auth = Zend_Auth::getInstance();
        if ($auth->hasIdentity()) {
            $this->view->identity = $auth->getIdentity();
        } else {
            $this->_redirect('/user/fail');
        }
    }
}
The above init() is in the MemberController and the redirect on fail sends them to the UserController.  

As an example if the email link sent to a registered member (who is not logged in) is "http://localhost/member/index" they will be redirected to '/user/fail' where they will be able to log in.  

What I need help with is the best way to get them back to "http://localhost/member/index" after they have successfully logged in.  

So I'm thinking that I need to somehow attach the URL ("http://localhost/member/index") to the _redirect() and then somehow add it to the $userForm->setAction().

Hopefully that helps - Thanks

class MemberController extends Zend_Controller_Action
{
public function init()
    {
        $auth = Zend_Auth::getInstance();
        if ($auth->hasIdentity()) {
            $this->view->identity = $auth->getIdentity();
        } else {
            $this->_redirect('/user/fail');
        }
    }
}

Open in new window

0
 
AlexanderRCommented:
It does help, thanks. Just want to clarify last thing.
From what i understand, after a user logs in himself (NOT following an email link) does he or does he not go to member/index  or does redirection to member/index needs to happen ONLY when following email link.

Thanks.
0
 
AlexanderRCommented:
In case its the latter (going to member/index ONLY when following email links).

There is no need to attach member/index to _redirect(). Remember that _redirect is only INTERNAL redirect.  so actual request does not change. Therefore you can easily pick up where the user is expecting to be anywhere using
$this->_request->getControllerName();
$this->_request->getActionName();
, even in /user/fail
So user goes to member/index and ZF finds that user needs to log in.  It does internal _redirect to /user/fail while _request remains in tact (with /member/index still in it).  So you can then use _request in your form (put it in a hidden field maybe) to let login controller know that once form is sucessfuly submitted AND authenticated, they go to member/index.

Hope this makes sense.
0
 
blorrimanAuthor Commented:
Thanks AlexanderR,
When a member logs in himself (NOT following an email link) that is when they are directed to '/member/index'.  

The link in the email will be always be dynamic as it will point to the comment made by another member, so the controller, action and params will all be different each time.
0
 
AlexanderRCommented:
Ignore my last comment which makes no sense. Whatever made me think $this->_request is for internal only.

So you can do something similar to what ali_kayahan suggested.


class MemberController extends Zend_Controller_Action
{
public function init()
    {
        $userSession = new Zend_Session_Namespace('userSession');
        $userSession->commentId = $this->_getParam('commentId') //include whatever variables in session from comment url in email
// we have to use session because form submission at login is not one continuous request, as the sequence "breaks" while user fills out the form
        $auth = Zend_Auth::getInstance();
        if ($auth->hasIdentity()) {
            $this->view->identity = $auth->getIdentity();
        } else {
            $this->_redirect('/user/fail');
        }
    }
}


Then /user/fail does its login thing which redirects to /member/index.  You can reuse your existing login mechanism.  If right now you are redirecting to /member/index then now you can check whether session variable is defined and if it is redirect to it:

login class:
if(login is succussfull){
   $userSession = new Zend_Session_Namespace('userSession');
   if(defined($userSession->commentId)){
         //build rout based on variables in session:
         $commentId = $userSession->commentId;
         $this->_redirect('member/comments/commentId/'.$commentId); //adjust as necessery
    } else {
$this->_redirect('member/index');
    }
}

Open in new window

0
 
AlexanderRCommented:
sorry,
if(isset($userSession->commentId)){
defined is for constants XD
0
 
blorrimanAuthor Commented:
Thanks AlexanderR,
It's starting to make sense - what I'm still unsure of is picking up the $userSession:
$userSession->commentId = $this->_getParam('commentId')
I want to be able to get the entire url (example: http://mysite.com/member/comment/id?=25) because the controller, action, param, etc. may change and I want to insure I have that flexibility, so I'm not sure what you mean by "include whatever variables in session from comment url in email" - can you be more specific?

Thanks
0
 
AlexanderRCommented:
Your URLs are not formed properly.  You should not be using id?=25 (and i am assuming from that, $_GET and/or $_POST) which is why my solution did not make full sense.

That aside, you should be able to get url through
$userSession->url = 'http://'.$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
0
 
blorrimanAuthor Commented:
AlexanderR,
Thank you, Thank you, Thank you.

With a few modifications from your input it's working like a charm !

Happy New Year !
0
 
AlexanderRCommented:
You have to say "accept as solution" next to the comment that answered your question.  If you say "delete" then we don't get anything ;)

Can you do that please? Thank you.
Glad it worked for you !!
0
 
blorrimanAuthor Commented:
Sorry . . .
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 7
  • 5
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now