Skip to content

Instantly share code, notes, and snippets.

@kongondo
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kongondo/9711668aba8ea243c3a0 to your computer and use it in GitHub Desktop.
Save kongondo/9711668aba8ea243c3a0 to your computer and use it in GitHub Desktop.
ProcessWire: Code example - front-end system to handle logins, password resets and changing passwords
<?php
/*
Code by Ryan Cramer
Integrating a member visitor login form
https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919
*/
/*
I recently had to setup front-end system to handle logins, password resets and changing passwords, so here's about how it was done. This should be functional code, but consider it pseudocode as you may need to make minor adjustments here and there. Please let me know if anything that doesn't compile and I'll correct it here.
The template approach used here is the one I most often use, which is that the templates may generate output, but not echo it. Instead, they stuff any generated output into a variable ($page->body in this case). Then the main.php template is included at the end, and it handles sending the output. This 'main' template approach is preferable to separate head/foot includes when dealing with login stuff, because we can start sessions and do redirects before any output is actually sent. For a simple example of a main template, see the end of this post.
1. In Admin > Setup > Fields, create a new text field called 'tmp_pass' and add it to the 'user' template. This will enable us to keep track of a temporary, randomly generated password for the user, when they request a password reset.
2a. Create a new template file called reset-pass.php that has the following:
/site/templates/reset-pass.php
*/
$showForm = true;
$email = $sanitizer->email($input->post->email);
if($email) {
$u = $users->get("email=$email");
if($u->id) {
// generate a random, temporary password
$pass = '';
$chars = 'abcdefghjkmnopqrstuvwxyz23456789'; // add more as you see fit
$length = mt_rand(9,12); // password between 9 and 12 characters
for($n = 0; $n < $length; $n++) $pass .= $chars[mt_rand(0, strlen($chars)-1)];
$u->of(false);
$u->tmp_pass = $pass; // populate a temporary pass to their profile
$u->save();
$u->of(true);
$message = "Your temporary password on our web site is: $pass\n";
$message .= "Please change it after you login.";
mail($u->email, "Password reset", $message, "From: noreply@{$config->httpHost}");
$page->body = "<p>An email has been dispatched to you with further instructions.</p>";
$showForm = false;
} else {
$page->body = "<p>Sorry, account doesn't exist or doesn't have an email.</p>";
}
}
if($showForm) $page->body .= "
<h2>Reset your password</h2>
<form action='./' method='post'>
<label>E-Mail <input type='email' name='email'></label>
<input type='submit'>
</form>
";
// include the main HTML/markup template that outputs at least $page->body in an HTML document
include('./main.php');
/*
2b. Create a page called /reset-pass/ that uses the above template.
3a. Create a login.php template. This is identical to other examples you may have seen, but with one major difference: it supports our password reset capability, where the user may login with a temporary password, when present. When successfully logging in with tmp_pass, the real password is changed to tmp_pass. Upon any successful authentication tmp_pass is cleared out for security.
/site/templates/login.php
*/
if($user->isLoggedin()) $session->redirect('/profile/');
if($input->post->username && $input->post->pass) {
$username = $sanitizer->username($input->post->username);
$pass = $input->post->pass;
$u = $users->get($username);
if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) {
// user logging in with tmp_pass, so change it to be their real pass
$u->of(false);
$u->pass = $u->tmp_pass;
$u->save();
$u->of(true);
}
$u = $session->login($username, $pass);
if($u) {
// user is logged in, get rid of tmp_pass
$u->of(false);
$u->tmp_pass = '';
$u->save();
// now redirect to the profile edit page
$session->redirect('/profile/');
}
}
// present the login form
$headline = $input->post->username ? "Login failed" : "Please login";
$page->body = "
<h2>$headline</h2>
<form action='./' method='post'>
<p>
<label>Username <input type='text' name='username'></label>
<label>Password <input type='password' name='pass'></label>
</p>
<input type='submit'>
</form>
<p><a href='/reset-pass/'>Forgot your password?</a></p>
";
include("./main.php"); // main markup template
/*
3b. Create a /login/ page that uses the above template.
4a. Build a profile editing template that at least lets them change their password (but take it further if you want):
/site/templates/profile.php
*/
// if user isn't logged in, then we pretend this page doesn't exist
if(!$user->isLoggedin()) throw new Wire404Exception();
// check if they submitted a password change
$pass = $input->post->pass;
if($pass) {
if(strlen($pass) < 6) {
$page->body .= "<p>New password must be 6+ characters</p>";
} else if($pass !== $input->post->pass_confirm) {
$page->body .= "<p>Passwords do not match</p>";
} else {
$user->of(false);
$user->pass = $pass;
$user->save();
$user->of(true);
$page->body .= "<p>Your password has been changed.</p>";
}
}
// display a password change form
$page->body .= "
<h2>Change password</h2>
<form action='./' method='post'>
<p>
<label>New Password <input type='password' name='pass'></label><br>
<label>New Password (confirm) <input type='password' name='pass_confirm'></label>
</p>
<input type='submit'>
</form>
<p><a href='/logout/'>Logout</a></p>
";
include("./main.php");
/*
4b. Create a page called /profile/ that uses the template above.
5. Just to be complete, make a logout.php template and create a page called /logout/ that uses it.
/site/templates/logout.php
*/
if($user->isLoggedin()) $session->logout();
$session->redirect('/');
/*
6. The above templates include main.php at the end. This should just be an HTML document that outputs your site's markup, like a separate head.inc or foot.inc would do, except that it's all in one file and called after the output is generated, and we leave the job of sending the output to main.php. An example of the simplest possible main.php would be:
/site/templates/main.php
*/
?>
<html>
<head>
<title><?=$page->title?></title>
</head>
<body>
<?=$page->body?>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment