Jump to content

Possible to register and login simultaneously


onjegolders

Recommended Posts

Have set up a front-end registration form and it all seems fine but rather than giving them a link to "Click here to login!", I'd like to log them in automatically.

I was thinking that as the login takes place after the new user has been saved that it ought to work but it doesn"t seem to be working at the moment. Is this even achievable without a page reload?

Here is my code currently:

<?php

include("./header.inc"); 

$headings = "
<div id='register'>
	<div class='row'>
		<div class='twelve columns'>

			<h3>Register with us</h3>";
			

			$form="<form action='./' id='registration' method='post'>
										
			<div class='row'>

				<div class='four columns'>

					<label for='username'>Username</label>
					<p class='help'>Please ensure your username contains no spaces</p>
					<input type='text' name='username' value='{$input->post->username}'>
					
					<label for='first_name'>First name</label>
					<input type='text' name='first_name' value='{$input->post->first_name}'>
					
					<label for='last_name'>Last name</label>
					<input type='text' name='last_name' value='{$input->post->last_name}'>
					
					<label for='email'>Email address</label>
					<input type='text' name='email' value='{$input->post->email}'>

				</div> <!-- /.four columns -->

				<div class='four columns'>
				
					<label for='company_name'>Company name</label>
					<input type='text' name='company_name' value='{$input->post->company_name}'>

					<label for='company_url'>Company URL</label>
					<input type='text' name='company_url' value='{$input->post->company_url}'>
					
					<label for='company_phone'>Company phone</label>
					<input type='text' name='company_phone' value='{$input->post->company_phone}'>				  	

			  	</div> <!-- /.four columns -->

			  	<div class='four columns'>

			  		<label for='pass'>Password</label>
			  		<p class='help'>Please ensure your password is at least 6 characters long and contains at least one digit and one letter</p>
				  	<input type='password' name='pass' value='{$input->post->pass}'>
		
				  	<label for='pass_confirm'>Confirm password</label>
				  	<input type='password' name='pass_confirm' value='{$input->post->pass_confirm}'>

			  	</div> <!-- /.four columns -->
			</div> <!-- /.row -->

			<input class='button success small' type='submit' name='submit_registration' id='submit'>

			</form>";

			$message = "Please fill in the form below if you would like to register in order to receive exclusive access to our brochures and latest information.";

			$usernames = array();

			foreach ($users as $u) {
			    $usernames[] = $u->name;
			}

			if($input->post->submit_registration) {
				
				if (empty($input->post->username) || empty($input->post->email) || empty($input->post->pass)) {
					$message = "Please fill out all fields marked with a *";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				} 

				elseif (in_array($input->post->username, $usernames)) {
					$message = "Sorry, that username is already taken, please choose another.";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				}
				
				elseif (filter_var($input->post->email, FILTER_VALIDATE_EMAIL) === FALSE) {
					$message = "Please include a valid email address";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				}


				elseif (!preg_match("/[0-9]/", $input->post->pass) || strlen($input->post->pass) < 6) {
					$message = "Please ensure your password has at least one digit and is at least 6 characters long";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				}

				elseif($input->post->pass !== $input->post->pass_confirm) {
					$message = "Please ensure that your passwords match";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				} 

				else {
					echo $headings;
					$message = "Congratulations! You have successfully registered and have been logged in";
					echo "<h5 class='success'>$message</h5>";

					$u = new User();
					$u->of(false);
		            $u->name = $sanitizer->username($input->post->username);
		            $u->first_name = $sanitizer->text($input->post->first_name);
		            $u->last_name = $sanitizer->text($input->post->last_name);
		            $u->company_name = $sanitizer->text($input->post->company_name);
		            $u->company_url = $sanitizer->url($input->post->company_url);
		            $u->company_phone = $sanitizer->text($input->post->company_phone);
		            $u->email = $sanitizer->email($input->post->email);
		            $u->pass = $sanitizer->text($input->post->pass);
		            $u->addRole('registered');
		            $u->save();
		            $u->of(true);

		            require_once("./scripts/PHPMailer/class.phpmailer.php");

					$form_contents = array(
						'username' => $sanitizer->username($page->username),
						'First name' => $sanitizer->text($input->post->first_name),
						'Last name' => $sanitizer->text($input->post->last_name),
						'Company name' => $sanitizer->text($input->post->company_name),
						'Company URL' => $sanitizer->url($input->post->company_url),
						'email' => $sanitizer->email($input->post->email),
						'Phone Number' => $sanitizer->text($input->post->company_phone),
					);

					$to_name = "My company";
					$to = "me@me.com";
					$subject = "New registered user";
					$form_message = "";
					
					foreach ($form_contents as $key => $value) {
						$form_message .= "$key: $value\n";
					}
					$from = "$form_contents[email]";
					$from_name = "$form_contents[username]";

					$mail = new PHPMailer();
					$mail->CharSet = 'UTF-8';
					$mail->FromName = "$from_name";
					$mail->From = "$from";
					$mail->AddAddress ($to, $to_name);
					$mail->Subject = "$subject";
					$mail->Body = "$form_message";

					$mail->Send();

					$name = $u->name;
					$pass = $u->pass;

					
			        if ($session->login($name, $pass)) {
			             $session->redirect("../");
			        } 

				}
				
			} elseif ($user->isLoggedin()) {
				echo $headings;
				echo "<h5>No need to register " . $user->get('first_name|name') . ", you are already are!   <a href='{$config->urls->root}'>Click here</a> if you would like to return to the homepage.</h5>";
			}

			else {
				echo $headings;
				echo "<h5>$message</h5>";
				echo $form;
			} 

			?>

		</div> <!-- /.twelve columns -->
	</div> <!-- /.row -->
</div> <!-- /#register -->

<?php 

?>

<?php include("./footer.inc");




Thanks.

Link to comment
Share on other sites

Hi onjegolders,

Can you tell us what exactly doesn't work? I'm not sure but I think it should be possible :)

Have you tried $session->redirect('./') instead of ->redirect('../');

A few suggestions to the code:

<input type='text' name='first_name' value='{$input->post->first_name}'>

If the user submitted a value with quotes or other html signs, this will brake your form. You should escape the post vars:

$v = $sanitizer->entities($input->post->first_name);
<input type='text' name='first_name' value='{$v}'>

To check if a user name already exists, this might be a better way than query all the users:

$username = $sanitizer->pageName($input->post->username);
$u = $users->get($username);
if ($u->id) $message = "Sorry, that username is already taken...";

Cheers

Edited by ryan
Corrected last code example (Ryan)
  • Like 2
Link to comment
Share on other sites

Hi onjegolders,

Can you tell us what exactly doesn't work? I'm not sure but I think it should be possible :)

Have you tried $session->redirect('./') instead of ->redirect('../');

A few suggestions to the code:

<input type='text' name='first_name' value='{$input->post->first_name}'>

If the user submitted a value with quotes or other html signs, this will brake your form. You should escape the post vars:

$v = $sanitizer->entities($input->post->first_name);
<input type='text' name='first_name' value='{$v}'>

To check if a user name already exists, this might be a better way than query all the users:

$username = $sanitizer->username($input->post->username);
$u = $users->find("name={$username}");
if ($u->id) $message = "Sorry, that username is already taken...";

Cheers

Thanks for the tips Wanze, will have a look at them!

Quite simply, the user is not getting logged in. The user is getting created fine but the logging them in part and the redirecting is not taking place. I'm not sure whether I have the login code in the wrong place or whether something else is preventing it from working?

Link to comment
Share on other sites

Hmmmmmm,

i just deleted exactly what u wanna achieve 2hours ago because i needed an email verification before first login.

Its definitve possbile to Login a User after registraton.

My Script was something like this:

Registry Page.

Vailidate Input.

Create User Dashboard as Page.

Create User.

Redirect to Dashboard and Login.

Im back in my office in 20minutes.

I'll take a look if i could restore the Script.

  • Like 1
Link to comment
Share on other sites

Ah I found the error:

$name = $u->name;
$pass = $u->pass;

if ($session->login($name, $pass)) {
  $session->redirect("../");
} 

This cannot work because $u->pass is already encrypted by Pw. You need the Password in plain-text for the login:

$pass = $input->post->pass;

$message = "Congratulations! You have successfully registered and have been logged in";
					echo "<h5 class='success'>$message</h5>";

This message will never appear because you do a redirect after creating the user.

  • Like 2
Link to comment
Share on other sites

Ah I found the error:

$name = $u->name;
$pass = $u->pass;

if ($session->login($name, $pass)) {
  $session->redirect("../");
} 

This cannot work because $u->pass is already encrypted by Pw. You need the Password in plain-text for the login:

$pass = $input->post->pass;

$message = "Congratulations! You have successfully registered and have been logged in";
					echo "<h5 class='success'>$message</h5>";

This message will never appear because you do a redirect after creating the user.

Brilliant, thanks so much for that Wanze! Works great now, thanks also Luis!

Link to comment
Share on other sites

Hmm just moved to live server and the emails aren't getting sent :(

Anything glaringly obvious in the code?

Don't know if the fact I'm using Gmail alters anything? I'm happy to just use mail() but never seems to work for me.

OK, I seem to have it, it was a slightly different bit of code and now I have it working under SMTP.

Link to comment
Share on other sites

Just wanted to reiterate what Wanze said about this:

<input type='text' name='first_name' value='{$input->post->first_name}'>

This is a major security hole. For example, try submitting this in the first_name field:

'><script>alert('Gotcha!');</script>

...and if you can do that, you can do some pretty bad stuff.

Definitely entity encode user submitted input that gets output again. Wanze's example:

$v = $sanitizer->entities($input->post->first_name);
echo "<input type='text' name='first_name' value='$v'>";

If you are running an older version of PW that doesn't have the $sanitizer->entities() method (a fairly recent addition) then do this:

$v = htmlentities($input->post->first_name, ENT_QUOTES, 'UTF-8'); 
  • Like 2
Link to comment
Share on other sites

Just wanted to reiterate what Wanze said about this:

<input type='text' name='first_name' value='{$input->post->first_name}'>

This is a major security hole. For example, try submitting this in the first_name field:

'><script>alert('Gotcha!');</script>

...and if you can do that, you can do some pretty bad stuff.

Definitely entity encode user submitted input that gets output again. Wanze's example:

$v = $sanitizer->entities($input->post->first_name);
echo "<input type='text' name='first_name' value='$v'>";

If you are running an older version of PW that doesn't have the $sanitizer->entities() method (a fairly recent addition) then do this:

$v = htmlentities($input->post->first_name, ENT_QUOTES, 'UTF-8'); 

Thanks Ryan, it can be quite hard at my level to keep all this code organized and remember everything!

Which fields should/can you run entities on?

Edit: Is it OK to run it as $sanitizer->text($input->post->first_name) ?

Link to comment
Share on other sites

Which fields should/can you run entities on?

A simple rule to remember is: Any data input from the user needs to be entity encoded before outputting it back to a browser. 

What is entity encoding? It means taking some special characters and converting them to a format that isn't interpreted by the browser as anything but text. We care primarily about characters used for tags, like "<" and ">", characters used for single or double quotes (especially when values might end up in HTML tag attributes), and ampersands "&". These are the characters that can mean something more than just text to a web browser. But you don't even have to think about this if you just remember to entity encode any output. 

There are cases where you don't have to entity encode, like if you've already typecast something as an integer, or already run it through one of PW's filtering functions that removes special characters... $sanitizer->pageName() is a good example. But if you want to play it safe, just entity encode everything you are outputting back to the user... there's no harm in it. 

One way to tell if entity encoding is working is to enter a value like "<b>test</b>" in your form field. When you get it back, if it reads as test rather than <b>test</b>, then you've got a problem. 

Edit: Is it OK to run it as $sanitizer->text($input->post->first_name) ?

No. $sanitizer->text() filters input for storage, not for output. It limits length and prevents linebreaks, among other things. While it strips tags (unless you tell it not to) it doesn't entity-encode any characters. The reason is that you don't usually want to store entity encoded text, unless it's meant to be stored as markup, like TinyMCE (in which case, none of this applies). So ideally, your sanitization would go something like this:

// these values are for API use or storage
$firstName = $sanitizer->text($input->post->first_name); 
$lastName = $sanitizer->text($input->post->last_name); 

// these values are for output back to the user
$outFirstName = $sanitizer->entities($firstName);
$outLastName = $sanitizer->entities($lastName);
// you might prefer to bundle these into an array 

When it comes to outputting values that came from the user, the $sanitizer->text(); is certainly a good idea, but it's not required. It's not going to make the text any safer for output than $sanitizer->entities(); will on it's own. 

  • Like 4
Link to comment
Share on other sites

A simple rule to remember is: Any data input from the user needs to be entity encoded before outputting it back to a browser. 

What is entity encoding? It means taking some special characters and converting them to a format that isn't interpreted by the browser as anything but text. We care primarily about characters used for tags, like "<" and ">", characters used for single or double quotes (especially when values might end up in HTML tag attributes), and ampersands "&". These are the characters that can mean something more than just text to a web browser. But you don't even have to think about this if you just remember to entity encode any output. 

There are cases where you don't have to entity encode, like if you've already typecast something as an integer, or already run it through one of PW's filtering functions that removes special characters... $sanitizer->pageName() is a good example. But if you want to play it safe, just entity encode everything you are outputting back to the user... there's no harm in it. 

One way to tell if entity encoding is working is to enter a value like "<b>test</b>" in your form field. When you get it back, if it reads as test rather than <b>test</b>, then you've got a problem. 

No. $sanitizer->text() filters input for storage, not for output. It limits length and prevents linebreaks, among other things. While it strips tags (unless you tell it not to) it doesn't entity-encode any characters. The reason is that you don't usually want to store entity encoded text, unless it's meant to be stored as markup, like TinyMCE (in which case, none of this applies). So ideally, your sanitization would go something like this:

// these values are for API use or storage
$firstName = $sanitizer->text($input->post->first_name); 
$lastName = $sanitizer->text($input->post->last_name); 

// these values are for output back to the user
$outFirstName = $sanitizer->entities($firstName);
$outLastName = $sanitizer->entities($lastName);
// you might prefer to bundle these into an array 

When it comes to outputting values that came from the user, the $sanitizer->text(); is certainly a good idea, but it's not required. It's not going to make the text any safer for output than $sanitizer->entities(); will on it's own. 

Thanks Ryan, that's a great summary.

does ->entities cover all input field types?

Link to comment
Share on other sites

does ->entities cover all input field types?

Yes, anything that you are inserting into HTML. For instance:

<input type="anything" value="this needs to be entity encoded" />

<input type="anything" any-attribute="this needs to be entity encoded" />

<textarea>this needs to be entity encoded</textarea>

<h3>this needs to be entity encoded</h3>

(The text "this needs to be entity encoded" is the user input, not the tags)

Anything in HTML like this needs to be entity encoded, unless you want the browser to interpret it as markup. Usually you don't want user input to be treated as markup by the browser, because it gives them control over the page. :)

  • Like 2
Link to comment
Share on other sites

  • 1 year later...

Adding to Wanze's code...
 

$username = $sanitizer->pageName($input->post->username);
$u = $users->get($username);
if ($u->id) {
     $message = "Sorry, that username is already taken...";
}
else {
      $u->addRole('frontend-editor');
      $u->save();
}

Assumes you already have that role available

  • Like 2
Link to comment
Share on other sites

And just because I am procrastinating, if the role doesn't already exit:

$newrole = new Role();
$newrole->name= 'frontend-editor';
$newrole->addPermission('guest');
$newrole->addPermission('editor'); //or whatever permissions you need it to have
$newrole->save();
$u->addRole('frontend-editor');
$u->save();
  • Like 2
Link to comment
Share on other sites

Awesome!!! I have it working!!! One step closer to my goal. 

Now, do you recommend sending the user an automatic email with their details?  Or any way to avoid multiple user registrations aka spammers?

Isn't that the normal practice globally? Also, define details? Some choose to send passwords and user names. Others just send user names and ask user to confirm their email address, blah blah...

Spammers can be people or bots. If the former, you decide whether you check uniqueness by email or other method...As for the latter, search forums (or the internet) for "honeypot" in relation to forms :-)....there's other stuff out there too to help with spammers, some less effective (and/or more annoying!) than others..:-)

Another question? If a user types in a user name with a space, it goes through, example johnny p  it will go through with success.  

Any suggestions to restrict this? 

Take your pick from these...http://processwire.com/api/variables/sanitizer/ . If nothing suits you there, you can roll your own Regex. You could should also start with client-side validation with some jQuery magic; no need allowing a user to submit a form with an invalid user name (or any other invalid input). BUT THIS IS no replacement for server-side validation! You must do that, e.g using your PHP and/or PW API stuff - e.g. $sanitizer....

  • Like 1
Link to comment
Share on other sites

@kongondo , 

So I basically did what onjegolders did accept, I removed the system email to the admin.  

How would I go about taking the users username, possibly his password too and emailing him a welcome to blah blah blah here is your user name and password, to login go to www.example.com. 

Any guidance on this?  

Thanks.

Here is the code:

<?php

include("./head.inc"); 
?>

<?php

$headings = "
<div id='register'>
	<div class='row'>
		<div class='medium-12 columns supersize'>
		<div class='medium-4 columns'>
		<p> </p>
		</div>
<div class='medium-4 columns'>

		<h3>Register with us</h3>";
			

			$form="<form action='./' id='registration' method='post'>
										
		

				

					<label for='username'>Username</label>
					<p class='help'>Please ensure your username contains no spaces</p>
					<input type='text' name='username' value='{$input->post->username}'>
					
					<label for='first_name'>First name</label>
					<input type='text' name='first_name' value='{$input->post->first_name}'>
					
					<label for='last_name'>Last name</label>
					<input type='text' name='last_name' value='{$input->post->last_name}'>
					
					<label for='email'>Email address</label>
					<input type='text' name='email' value='{$input->post->email}'>

				
				
					
			  		<label for='pass'>Password</label>
			  		<p class='help'>Please ensure your password is at least 6 characters long and contains at least one digit and one letter</p>
				  	<input type='password' name='pass' value='{$input->post->pass}'>
		
				  	<label for='pass_confirm'>Confirm password</label>
				  	<input type='password' name='pass_confirm' value='{$input->post->pass_confirm}'>

		

			<input class='button success small' type='submit' name='submit_registration' id='submit'>

			</form>";

			$message = "Please fill in the form below if you would like to register in order to receive exclusive access to our brochures and latest information.";

			$usernames = array();

			foreach ($users as $u) {
			    $usernames[] = $u->name;
			}

			if($input->post->submit_registration) {
				
				if (empty($input->post->username) || empty($input->post->email) || empty($input->post->pass)) {
					$message = "Please fill out all fields marked with a *";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				} 

				elseif (in_array($input->post->username, $usernames)) {
					$message = "Sorry, that username is already taken, please choose another.";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				}
				
				elseif (filter_var($input->post->email, FILTER_VALIDATE_EMAIL) === FALSE) {
					$message = "Please include a valid email address";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				}


				elseif (!preg_match("/[0-9]/", $input->post->pass) || strlen($input->post->pass) < 6) {
					$message = "Please ensure your password has at least one digit and is at least 6 characters long";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				}

				elseif($input->post->pass !== $input->post->pass_confirm) {
					$message = "Please ensure that your passwords match";
					echo $headings;
					echo "<h5 class='error'>$message</h5>";
					echo $form;
				} 

				else {
					echo $headings;
					$message = "Congratulations! You have successfully registered!";
					echo "<h5 class='success'>$message</h5>";
					echo "<h4><a href='/login' class='button'>LOGIN</a></h4>";

					$u = new User();
					$u->of(false);
		            $u->name = $sanitizer->username($input->post->username);
		            $u->first_name = $sanitizer->text($input->post->first_name);
		            $u->last_name = $sanitizer->text($input->post->last_name);
		        	$u->email = $sanitizer->email($input->post->email);
		            $u->pass = $sanitizer->text($input->post->pass);
		            $u->addRole('frontend-editor');
		            $u->save();
		            $u->of(true);

					
					

				}
				
			} elseif ($user->isLoggedin()) {
				echo $headings;
				echo "<h5>No need to register " . $user->get('first_name|name') . ", you are already are!   <a href='{$config->urls->root}'>Click here</a> if you would like to return to the homepage.</h5>";
			}

			else {
				echo $headings;
				echo "<h5>$message</h5>";
				echo $form;
			} 
			

			?>
	
			
			
			
			
						</div>
			<div class='medium-4 columns'>
		<p> </p>
		</div>
			</div>

		</div>

<?php 

?>

<?php include("./foot.inc");

Link to comment
Share on other sites

  • 1 month later...

This was a really nice example. I now have a working registration.

Checking is done by foundation abide.js with patterns - which means upon typing, wrong format gives a nice silent error at that field.

And if any not right, checking is also done by PW - I get a nice alert at the top of the form for that.

I made hover tool-tips for more info on the required fields.

Successful registration moves them to the 'member' role - which means they can still only view and need to apple for other special roles, after I confirm some things *.

They are automatically logged in and redirected to their profile page.

* There are 2 other roles: company and applicant. The reason for not moving them to these roles is that over here we can not auto confirm a chamber of commerce or tax number. So I think, a registered user 'member' is presented with a form on their profile page where they have to provide info that I can confirm in order to move them to other roles.

Link to comment
Share on other sites

  • 1 year later...

Just noticed you're sanitizing the password, too. When I remember right Ryan mentioned that it's better not to do so because you want to make sure the correct password gets saved, otherwise there is a little chance that somecharacters get sanitized so the user won't be able to login.

As far as I understand, because the password will be hashed you don't have to worry about what the users inputs.

Please correct me if I'm wrong!

@Onjegolders thanks for sharing your code, could grab some parts to improve my registration process. For example I forgot to implement password control like

if(!preg_match("/[0-9]/", $input->post->pass) || strlen($input->post->pass) < 6)

Saludos, Can

  • Like 1
Link to comment
Share on other sites

$v = $sanitizer->entities($input->post->first_name);
echo "<input type='text' name='first_name' value='$v'>";

Thanks for remembering me on this! Just forgot to do this  :excl::o:wacko:

Link to comment
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
×
×
  • Create New...