Sevarf2

Custom Login

Recommended Posts

Absolutely! Here is a simple, but functional example for both login and logout templates. You would want to replace the markup with your own markup or includes. Likewise you'd want to change the redirects to redirect to whatever page you want them to go to after completing a login.

/site/templates/login.php:

<?php

if($user->isLoggedin()) {
    // user is already logged in, so they don't need to be here
    $session->redirect("/somewhere/"); 
}

// check for login before outputting markup
if($input->post->user && $input->post->pass) {

    $user = $sanitizer->username($input->post->user);
    $pass = $input->post->pass; 

    if($session->login($user, $pass)) {
        // login successful
        $session->redirect("/somewhere/"); 
    }
}

?>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <form action='./' method='post'>
        <?php if($input->post->user) echo "<h2 class='error'>Login failed</h2>"; ?>
        <p><label>User <input type='text' name='user' /></label></p>
        <p><label>Password <input type='password' name='pass' /></label></p>
        <p><input type='submit' name='submit' value='Login' /></p>
    </form>
</body>
</html>

/site/templates/logout.php:

<?php $session->logout(); ?>
<html>
<head>
    <title>Logout</title>
</head>
<body>
    <h1>You have logged out</h1>
</body>
</html>
  • Like 17

Share this post


Link to post
Share on other sites

Ryan,

Thanks this gave me a great place to start. I thought I'd share the version I created in case anyone finds it useful.

• Single template for the login/logout.

• Automatically redirects the user back to whatever page they originally requested after they login.

./includes/login.php

<?php

// Handle logouts
if($input->get->logout == 1) {
$session->logout();
$session->redirect($page->path);
}

// If they aren't logged in, then show the login form
if(!$user->isLoggedin()){

// check for login before outputting markup
if($input->post->user && $input->post->pass) {

$user = $sanitizer->username($input->post->user);
$pass = $input->post->pass;

if($session->login($user, $pass)) {
	// login successful
	$session->redirect($page->path);
}  else {
	$session->login_error = 'Login Failed. Please try again, or use the forgot password link below.';
}
} ?>

<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Custom PW Login</title>
</head>

<body>
<form action='./' method='post'>
<div class="login">
<? if($input->post->user && $input->post->pass) {
echo "<p class='error'>" . $session->login_error . "</p>";
}?>
<p><input type='text' id="user" name='user' placeholder='Username'/></p>
<p><input type='password' id="pass" name='pass' placeholder="Password" /></p>
<p><input type='submit' class="btn" name='submit' value='Login' /></p>
</div>
</form>
</body>
</html>

<?
die(); // don't go any further if not logged in
} // end !logged in
?>

In any template you wish to protect:

<? require("./includes/login.php");?>

To trigger a logout:

<a href="?logout=1">Logout</a>

Note:

I'm using the HTML5 placeholder attribute. Browser support is not 100%.

You may want to use labels instead, or use some jQuery (like I did) to add the placeholder text for browser that don't support it.

SideNote:

How do you get code indents to stick when posting? I'm having to go back and add spaces to each line. I use tabs when coding.

  • Like 16

Share this post


Link to post
Share on other sites

Thanks for posting Renobird. I'm confused on this section:

if($session->login($user, $pass)) {
   // login successful
   $session->redirect($page->path);
   $error ="";
   $session->set($error, "");
} else {
   $error ="";
   $session->set($error, "Login Failed. Please try again, or use the forgot password link below.");
}

// ... further down

echo "<p class='error'>".$session->get($error)."</p>";

It seems like that is just setting a blank session variable? Are you sure you didn't mean for it to be like this?

if($session->login($user, $pass)) {
   // login successful
   $session->set("error", ""); // note: moved this above the redirect
   $session->redirect($page->path);
}else {
   $session->set("error", "Login Failed. Please try again, or use the forgot password link below.");
}

// ... further down

echo "<p class='error'>".$session->get('error')."</p>";
How do you get code indents to stick when posting? I'm having to go back and add spaces to each line. I use tabs when coding.

Good question--I have no idea. I've been trying to figure this one out for awhile. I have to paste any code in my plain text editor, then manually indent everything with 4 spaces. This editor appears to ignore tabs. Pete's been doing a great job of installing updates for us here, so we'll very likely see improvements here as the IP.Board developers make them.

  • Like 1

Share this post


Link to post
Share on other sites

Hi Ryan,

Nice catch. Yeah, no sense setting a session variable after the redirect. ;)

That entire if/else had a bunch of stuff I was commenting in/out while I was testing, I did a poor job of cleanup.

I updated my code above, so it's correct for anyone that uses it.

  • Like 2

Share this post


Link to post
Share on other sites

Thanks for updating your code. Just one more thing there that I don't understand are these lines:

$session->set($error, "");
$session->set($error, "Login Failed. Please try again, or use the forgot password link below.");
echo "<p class='error'>".$session->get($error)."</p>";

As far as I can tell, $error is an undefined/empty variable. Unless I'm misunderstanding something, shouldn't all of the $error instances instead be 'error' ? like this:

$session->set('error', "");
$session->set('error', "Login Failed. Please try again, or use the forgot password link below.");
echo "<p class='error'>".$session->get('error')."</p>";

Share this post


Link to post
Share on other sites

Hi Ryan,

Session variables and error handling aren't things I'm all that good at, so any guidance is appreciated. I'm just working off the cheatsheet and hacking my way around. :) I realize now that I initially had $error =""; in there because I thought that was the proper way to avoid the undefined variable.

When I tried setting it up like you suggested:

if($session->login($user, $pass)) {
// login successful
$session->redirect($page->path);
}else {
$session->set('error', "");
$session->set('error', "Login Failed. Please try again, or use the forgot password link below.");
}

echo "<p class='error'>".$session->get('error')."</p>";

I get this error if I enter an incorrect password more than once.

Warning: Invalid argument supplied for foreach() in /x/xxxx/xxxxxxxx.edu/htdocs/wire/core/Session.php on line 60

However, when I do it this way it seems to work properly.

if($session->login($user, $pass)) {
// login successful
$session->redirect($page->path);
}else {
$error ="";
$session->set($error, "Login Failed. Please try again, or use the forgot password link below.");
}

echo "<p class='error'>".$session->get($error)."</p>";

I'm sure there is a best practice for this, I just don't know what it is, so I fiddled around until I got it to work.

:)

Share this post


Link to post
Share on other sites

I think the problem might be that $session already keeps it's own 'error' function and variable, which is an array. So it might just be a matter of naming and using something like 'login_error' rather than 'error'. Your current solution works because it's likely resolving to a session variable named blank or "0". But if you tried to do something similar anywhere else, then you'd have unpredictable behavior. As a result, I think it's best to give $session an actual variable name that you want to use, like this:

$session->login_error = 'your message here';

and retrieve it like this:

echo '<p>' . $session->login_error . '</p>';

using set() and get() is also fine, but not necessary.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks Ryan,

Much appreciated. I'll test on my site and then update the code example accordingly.

  • Like 1

Share this post


Link to post
Share on other sites

Yep, works great!

In case anyone is following along, my original example is updated and working correctly.

Thanks Ryan!

  • Like 6

Share this post


Link to post
Share on other sites

Hey,

I am trying to use renobird's code above, but can't get the redirect to work properly.

I call e.g. /login/?id=1009 and after a successful login:

if ($session->login($user, $pass)) {
 // login successful
 $session->id = $input->get('id');
 $session->redirect($pages->get($session->id)->path);
   }

I discovered that the problem is that my $input->get('id') is empty ... but don't understand why and can't seem to fix it. Already tried using something else than id in case that was a system reserved name, but didn't make any difference.

Lars

Share this post


Link to post
Share on other sites

Make sure that you aren't outputting anything the call to $session->redirect(). In order for a redirect to work, it must happen before any output is sent.

Also, make sure to sanitize your 'id' variable by typecasting it to an integer:

$session->page_id = (int) $input->get('id'); 

Share this post


Link to post
Share on other sites

Thanks ryan, but still can't get it to work. My login file starts with this:

<?php
if ($user->isLoggedin()) {
 $out = 'You are already logged in.';
}
else {
 if ($input->post->user && $input->post->pass) {
  $user = $sanitizer->username($input->post->user);
  $pass = $input->post->pass;
  if ($session->login($user, $pass)) {
   // login successful
   $i = (int) $input->get->id;
   $t = $pages->get($i)->path;
   $session->redirect($t);
  }
  else {
   $out = 'Login Failed. Please try again.';
  }
 }
 $out = '<form action="./" method="post">';
 $out .= '<input type="text" name="user" value="Username" />';
 $out .= '<input type="password" name="pass" value="Password" />';
 $out .= '<input type="submit" name="submit" />';
 $out .= '</form>';
}
?>

But the redirect after successful login still doesn't work. Any ideas?

Thanks!

Share this post


Link to post
Share on other sites

What does not work? Can you please provide more infos? Any errors? Debug enabled?

As Ryan said, the session redirect doesn't work if anything is already rendered before your code.

I don't think this code is the only there is. If this code is included in some or has some header.inc that already has html code it will not work.

Share this post


Link to post
Share on other sites

This is the very beginning of the login page template, header etc only comes after it, but assumed that what comes after is irrelevant for the redirect?

After I login successfully, it only shows a blank page with no content on it, no errors.

Share this post


Link to post
Share on other sites

Ah ok , have you tried to debug anything yet? For example where does the id come from? Output the path you are redirecting, is it correct?

Share this post


Link to post
Share on other sites

I also don't understand where the id comes from. And where is it supposed to redirect to?

Share this post


Link to post
Share on other sites

Use something other than $user for this:

$user = $sanitizer->username($input->post->user);

That overwrites the $user API variable in your template file, so better to use something like $username or $name or the like. It's probably not the issue here, but still something to fix just for good measure.

After I login successfully, it only shows a blank page with no content on it, no errors.

What is the URL in your browser window? When you access that URL independently of a login, do you get something different?

Share this post


Link to post
Share on other sites

The url to login is something like /login/?id=1009. When a page requires a login, it redirects to this with the id being it's own id. After a login, this should redirect back to the previous page.

@ryan: what do you mean with independently of a login?

Share this post


Link to post
Share on other sites

Ryan was talking about the URL when you logged in, refering to your "blank" page.

Anyway, it looks to me as the id from the url isn't submited by the form. A simple debug "echo $input->get->id;" and commenting out the redirect would show that there's no id.

So I'd guess, the form action should contain the id so it gets submited by the url.

  • Like 1

Share this post


Link to post
Share on other sites

Try something like this:

<?php
if ($user->isLoggedin()) {
 $out = 'You are already logged in.';
}
else {
 // get id var from request
 $requested_id = (int) $input->get->id;
 if ($input->post->user && $input->post->pass) {
$user = $sanitizer->username($input->post->user);
$pass = $input->post->pass;
if ($session->login($user, $pass)) {
  // login successful
  $t = $pages->get($requested_id)->path;
  $session->redirect($t);
} else {
  $out = 'Login Failed. Please try again.';
}
 }
 $out = '<form action="./?id='.$requested_id.'" method="post">';
 $out .= '<input type="text" name="user" value="Username" />';
 $out .= '<input type="password" name="pass" value="Password" />';
 $out .= '<input type="submit" name="submit" />';
 $out .= '</form>';
}

Share this post


Link to post
Share on other sites

SideNote:

How do you get code indents to stick when posting? I'm having to go back and add spaces to each line. I use tabs when coding.

Just saw this note of yours. :D

When I have code I copy from editor I first switch tabs to spaces. In Sublime2 I can do this with one click in status bar.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.