Log in field with a specific input - php

I'd like to make a registration input field that only accepts certain types of email addresses (e.g., one that only accepts email addresses that end with #yahoo.com) so that I can provide some security in terms of who can access my website (e.g., I want to only accept email addresses that are from students from my school, i.e., they must end in #school.edu).
Here's what i have so far, but this does not discriminate for a specific type of email:
<?php
// configuration
require("../includes/config.php");
// if form was submitted
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
// validate inputs
if (empty($_POST["username"]))
{
apologize("You must provide a username.");
}
else if (empty($_POST["password"]))
{
apologize("You must provide a password.");
}
else if (empty($_POST["confirmation"]) || $_POST["password"] != $_POST["confirmation"])
{
apologize("Those passwords did not match.");
}
// try to register user
$results = query("INSERT INTO users (username, hash, cash) VALUES(?, ?, 10000.0000)",
$_POST["username"], crypt($_POST["password"])
);
if ($results === false)
{
apologize("That username appears to be taken.");
}
// get new user's ID
$rows = query("SELECT LAST_INSERT_ID() AS id");
if ($rows === false)
{
apologize("Can't find your ID.");
}
$id = $rows[0]["id"];
// log user in
$_SESSION["id"] = $id;
// redirect to portfolio
redirect("/");
}
else
{
// else render form
render("register_form.php", ["title" => "Register"]);
}
?>

You can use the substr() function combined with the strrpos() to get the last part of the email:
if(substr($email, strrpos($email, "#")) == "#school.edu") {
//all good
}
Once you have done that, you can email them a confirmation link to the email provided to make sure it's not a bogus one.

You can also use simple regex to verify user's email
if(preg_match('#^(.*)\#school\.edu$#', $_POST['email'])) {
echo 'email is valid';
} else {
echo 'this is not valid email!';
}

Related

Incoherent return message after username check

I'm new here so I hope I do this right.
I am having some problems with sending the right message from my php to my
html.
Here you can see the php part that sould give a message back if the username isn't valid(if is uses #$%^& etc.)
$validUsername = $CurrentUser->ValidateUsername($username);
//if the input isn't filled send a message back
if(!$validUsername)
{
$messageError = "Please fill in a valid username";
header("location: ../public/index.php?messageError=$messageError");
}
and another one that should check if the username is unique
$uniqueUsername = $CurrentUser->CheckAvailableUsername($validUsername);
if (!$uniqueUsername)
{
$messageError = "Please fill in a unique username";
header("location: ../public/index.php?messageError=$messageError");
}
now the weird thing is if use #$%^&etc. as a username it will give me back a please fill in a unique username instead of please fill in a valid username and I can't find out why.
oh btw I made a class named User with these methods Ill show them below here.
public function ValidateUsername($username)
{
if (!empty($username))
{
if (isset($username))
{
if (!preg_match("/^[a-zA-Z ]*$/", $username))
{
return false;
}
return $this->username = $username;
}
return false;
}
return false;
}
And the other one.
public function CheckAvailableUsername($username)
{
$sql = "SELECT * FROM `tbl_todolist`
WHERE `username` = '$username';";
$result = $this->dataBase->query($sql)->rowCount();
if ($result == 1)
{
return false;
}
return $this->username = $username;
}
I really hope you guys can help me with this.
After header(...); you need to throw in a return; or exit; to exit right there, otherwise it continues beyond that header.
Additional Notes
You are open to SQL injection in CheckAvailableUsername, you need to sanitize the value before you get to that function and also escape/bind the value to your query instead. It looks like you are using PDO already.

What Can I Do Instead Of Multiple If Statements? PHP Register Script

As you can see in the script below, I use multiple if statements when checking registration inputs. Is there an easier, less spaghetti?
The script works as is, but i would like it to be neater.
<?php
if (isset($_POST['register'])) {
$uname = trim($_POST['uName']);
$email = trim($_POST['email']);
$pass = trim($_POST['pass']);
$passCon = trim($_POST['passCon']);
$uname = strip_tags($uname);
$email = strip_tags($email);
$pass = strip_tags($pass);
$passCon = strip_tags($passCon);
if (!empty($pass)) {
if (!empty($email)) {
if (!empty($uname)) {
if ($pass == $passCon) {
$query = "SELECT username FROM users WHERE username='$uname'";
$result = mysqli_query($conn, $query);
$checkUsername = mysqli_num_rows($result);
if ($checkUsername == 0) {
$query = "SELECT email FROM users WHERE email='$email'";
$result = mysqli_query($conn, $query);
$count = mysqli_num_rows($result);
if ($count == 0) {
$password = hash('sha256', $pass);
$queryInsert = "INSERT INTO users(id, username, email, password, date) VALUES('', '$uname', '$email', '$password', '" . time() . "')";
$res = mysqli_query($conn, $queryInsert);
if ($res) {
$errTyp = "success";
$errMsg = "successfully registered, you may login now";
}
} else {
$errTyp = "warning";
$errMsg = "Sorry Email already in use";
}
} else {
$errTyp = "warning";
$errMsg = "Sorry Username already in use";
}
} else {
$errTyp = "warning";
$errMsg = "Passwords didn't match";
}
} else {
$errTyp = "warning";
$errMsg = "You didn't enter a Username";
}
} else {
$errTyp = "warning";
$errMsg = "You didn't enter an email address";
}
} else {
$errTyp = "warning";
$errMsg = "You didn't enter a password";
}
}
Thank you,
Jay
The problem you are facing is not at all uncommon. Many programmers have faced this issue. Let me help you along the way restructuring your script.
First of all, let's get rid of the nested if-else statements. They confuse and obfuscate what is really going on.
Version 1:
if (!isset($_POST['register']))
redirect('register.php'); // Let's assume that redirect() redirects the user to a different web page and exit()s the script.
$uname = $_POST['uName'];
$email = $_POST['email'];
$pass = $_POST['pass'];
$passRepeat = $_POST['passRepeat'];
if (empty($pass)) {
$errorMessage = "You didn't enter a password";
}
if (empty($email)) {
$errorMessage = "You didn't enter an email address";
}
if (empty($uname)) {
$errorMessage = "You didn't enter a Username";
}
if ($pass !== $passRepeat) {
$errMsg = "Passwords didn't match";
}
$query = "SELECT username FROM users WHERE username='$uname'";
$result = mysqli_query($conn, $query);
$checkUsername = mysqli_num_rows($result);
if ($checkUsername !== 0) {
$errMsg = 'Sorry Username already in use';
}
$query = "SELECT email FROM users WHERE email='$email'";
$result = mysqli_query($conn, $query);
$count = mysqli_num_rows($result);
if ($count !== 0) {
$errMsg = 'Sorry Email already in use';
}
$password = hash('sha256', $pass);
$queryInsert = "INSERT INTO users(id, username, email, password, date) VALUES('', '$uname', '$email', '$password', '" . time() . "')";
$res = mysqli_query($conn, $queryInsert);
Note that although this avoids the nested if statements, this is not the same as the original code, because the errors will fall through. Let's fix that. While we are at it, why would we want to return after the first error occurs? Let's return all the errors at once!
Version 2:
$errors = array();
if (empty($pass)) {
$errors[] = "You didn't enter a password";
}
if (empty($email)) {
$errors[] = "You didn't enter an email address";
}
if (empty($uname)) {
$errors[] = "You didn't enter a username";
}
if ($pass !== $passRepeat) {
$errors[] = "Passwords didn't match";
}
$query = "SELECT username FROM users WHERE username='$uname'";
$result = mysqli_query($conn, $query);
$usernameExists = mysqli_num_rows($result) > 0;
if ($usernameExists) {
$errors[] = 'Sorry Username already in use';
}
$query = "SELECT email FROM users WHERE email='$email'";
$result = mysqli_query($conn, $query);
$emailExists = mysqli_num_rows($result) > 0;
if ($emailExists) {
$errors[] = 'Sorry Email already in use';
}
if (count($errors) === 0) {
$password = hash('sha256', $pass);
$queryInsert = "INSERT INTO users(id, username, email, password, date) VALUES('', '$uname', '$email', '$password', '" . time() . "')";
$res = mysqli_query($conn, $queryInsert);
redirect('register_success.php');
} else {
render_errors($errors);
}
Pretty clean so far! Note that we could replace the if (empty($var)) statements with a for-loop. However, I think that is overkill in this situation.
As a side note, please remember that this code is vulnerable to SQL injection. Fixing that issue is beyond the scope of the question.
Less spaghetti? Start with functional decomposition, then work towards separating the task of sanitation from that of validation. I will leave out many steps that I take (such as verifying the form / $_POST / filter_input_array() has the correct number of inputs, and the correct keys are in the $_POST superglobal / INPUT_POST, etc, you might want to think about that.). Alter some of my techniques for your exact needs. Your program should be less spaghetti afterwards. :-)
Sanitize then validate. You have to keep them separated, so to speak. ;-)
Sanitizing with Functional Decomposition
Make a single task its own block of code.
If all of your sanitization steps (trim(), strip_tags(), etc.) are the same for all of your form fields, then make a sanitizer function to do that work. Note, that the one-time way you are trimming and stripping tags can be improved upon simply by using a loop. Save the original value in a variable, then trim(), strip_tags(), etc within a while loop. Compare the results to the original. If they are the same, break. If they differ, save the current value of the form field in your variable again and let the loop run again.
function sanitize($formValue)
{
$oldValue = $formValue;
do
{
$formValue = trim($formValue);
$formValue = strip_tags($formValue);
//Anything else you want to do.
$formValue = trim($formValue);
if($formValue === $oldValue)
{
break;
}
$oldValue = $formValue;
}
while(1); //Infinite loop
return $formValue;
}
Then, simply run this function in a loop.
$sanitized = [];
foreach($_POST as $key => $value)
{
$sanitized[$key] = sanitize($value);
}
/* You can keep track your variable anyway you want.*/
Looking further down the road, it is times like this where devising an input source ($_POST, $_GET, $_SESSION, $_FILES, $_COOKIE, etc..) based sanitizing, class hierarcy really comes in handy. Moreover, basing that class hierarchy on the use of filter_input_array() really puts you a head of the game. What about validation?
Validating with Functional Decomposition
You could look at each form field as needing its own validating function. Then, only the logic required to check one form field will be contained within the block. The key, retain your Boolean logic by having the validator functions return the results of a test (true / false).
function uname($uname, &$error)
{
if(! /* Some test */)
{
$error = 'Totally wrong!'
}
elseif(! /* Another test */)
{
$error = 'Incredibly wrong!'
}
else
{
$error = NULL;
}
return !isset($error) //If error is set, then the test has failed.
}
function email($email, &$error)
{
if(! /* Some test */)
{
$error = 'Totally wrong!'
}
elseif(! /* Another test */)
{
$error = 'Incredibly wrong!'
}
else
{
$error = NULL;
}
return !isset($error) //If error is set, then the test has failed.
}
function pass($pass, &$error)
{
if(! /* Some test */)
{
$error = 'Totally wrong!'
}
elseif(! /* Another test */)
{
$error = 'Incredibly wrong!'
}
else
{
$error = NULL;
}
return !isset($error) //If error is set, then the test has failed.
}
function passCon($passCon, &$error)
{
if(! /* Some test */)
{
$error = 'Totally wrong!'
}
elseif(! /* Another test */)
{
$error = 'Incredibly wrong!'
}
else
{
$error = NULL;
}
return !isset($error) //If error is set, then the test has failed.
}
In PHP, you can use variable functions to name your function the same as the fields they are checking. So, to execute these validators, simply do this.
$errorMsgs = [];
foreach($sanitized as $key => $value)
{
$key($value, $errorMsgs[$key])
}
Then, generally speaking, you just need to see if there are any errors in the $errorMsgs array. Do this by processing the $errorMsgs array
$error = false;
foreach($errorMsgs as $key => $value)
{
if(isset($value))
{
//There is an error in the $key field
$error = true;
}
}
..and then.
if($error === true)
{
//Prompt user in some way and terminate processing.
}
// Send email, login, etc ....
Taken further, you could create a generic, Validator, super class.
All this being said. I do all of my sanitization and validation in an object oriented way to reduce code duplication. The Sanitizer super class has children (PostSanitizer, GetSanitizer, ....). The Validator super class has all the test one might perform on a string, integer, or float. Children of the Validator superclass are page/form specific. But, when something like a form token is needed, it's validating method is found in the Validator super-class because it can be used on any form.
A good validation routine keeps track of:
1) Input values in an associative array..
2) Test results (Booleans) in an associative array. Test results (true/false) can be converted to CSS classes or a JSON string of '1's and '0's.
3) Error messages in an associative array.
..then makes final decisions about what to do with the input values and/or error messages based on the test results (by key). If there are errors (false values in the a hypothetical test results array), use the error messages that have the corresponding key.
My previous example condenses the final error checking and error message data structures with one array, but using separate data structures allows more flexibility (decouples error messages from the detected errors). Simply store the results of each validating variable function into a $testResults array like this.
function sanitize($formValue)
{
$oldValue = $formValue;
do
{
$formValue = trim($formValue);
$formValue = strip_tags($formValue);
//Anything else you want to do.
$formValue = trim($formValue);
if($formValue === $oldValue)
{
break;
}
$oldValue = $formValue;
}
while(1); //Infinite loop
return $formValue;
}
$sanitized = [];
foreach($_POST as $key => $value)
{
$sanitized[$key] = sanitize($value);
}
$testResults = [];
$errorMsgs = [];
foreach($sanitized as $key => $value)
{
$testResults[$key] = $key($value, $errorMsgs[$key])
}
if(!in_array(false, $testResults, true))
{
return true //Assuming that, ultimately, you need to know if everything worked or not, and will take action on this elsewhere. It's up to you to make the correct functions/methods, but this general foundation can get you going.
}
return false; //Obviously. Do not submit the form. Show the errors (CSS and error messages).
Then, simply check for the existence of false in the $testResults array. Get the corresponding error message from $errorMsgs using the appropriate $key. Using this generic, final stub, you can create a powerful santization and validation routine, especially if you go object oriented.
Eventually, you will begin to see that the same kinds of test are being repeated among the various validation variable functions: data type, length, regular expression, exact matches, must be a value within a set, etc. Thus, the primary difference between the validating variable functions will be the minimum and maximum string lengths, regex patterns, etc... If you are savvy, you can create an associative array that is used to "program" each variable function with its set of validation parameters. That's getting a bit beyond the scope, but that is what I do.
Thus, all my variable functions perform the same basic tests via factored out logic using a method of class Validator called validateInput(). This method receives the following arguments
1) The value to be tested.
2) An associative array of the test parameters (which can specify datatype)
3) An array element, passed in as a variable (by reference), that corresponds the field being tested that will hold the error message, if any.
What's funny, is that I use a two step sanitization and a two step validation. I use a custom filter algorithm using PHP functions, then I use the PECL filter functions (filter_input_array()). If anything fails during these steps, I throw a SecurityException (because I extend RuntimeException).
Only after these filters pass do I attempt to use the PHP/PECL filter valiation functions. Then, I run my own validation routine using validating, variable functions. Yes, these only run if the previous test passed as true (to avoid overwriting previous failures and corresponding error message).
This is entirely object oriented.
Hope I helped.

Password_hash Incorrect after updating table

My login system md5 hashes the username and I password_hash the password. Therefore I cannot fetch the row based on the username? My client then enters an email address which I base64encode. I then offer a lost password change option. However, when I UPDATE the field using the same type of hash but, using the email field as an identifier, the new password is incorrect?
Below is a sample of my UPDATE, but hard coded for illustration(PS this does not work either?).
$em = 'example#example.com';
$em1 = base64_encode($em);
$ps = 'some password';
$password_hash = password_hash($ps, PASSWORD_BCRYPT);
$qu = "UPADTE table SET field = '$password_hash' WHERE email = '$em1'";
$res = mysqli_query($link, $qu);
Edited question to include my code after verifying that the user exists and sending out an email for them to positively identify themselves as the owner of the account. Here is the final processor page.
if(EMPTY($_POST[psw1]) ) {
echo "New password must be supplied"; }
elseif(EMPTY($_POST[psw2]) ) {
echo "Repeat password must be entered"; }
elseif($_POST[psw1] != $_POST[psw2]) {
echo "Passwords entered do not match";
} elseif(EMPTY($_POST[eu])) {
echo "Essential data is missing in order to complete this process.";
}
elseif (strlen($_POST['psw1']) < 6) {
echo "Password must be at least six characters in length";
}
elseif (preg_replace("/[^a-zA-Z0-9]/", "", $_POST['psw1']) != $_POST['psw1']) {
echo "Password may only contain letters and numbers";
}
elseif(!EMPTY($_POST[psw1]) && !EMPTY($_POST[psw2]) && !EMPTY($_POST[eu]) && $_POST[pw1] == $_POST[pw2] ) {
include "conn.php";
echo "$_POST[eu]<br />";
$eu = $_POST[eu];
$pdw = password_hash($_POST[pw1], PASSWORD_BCRYPT);
$sq = mysqli_query($link, "UPDATE str1 SET pf = '$pdw', cu_pw_status = '2' WHERE cu_type = '$eu'");
echo "Your password has been changed, you may now login <a href='login2.php'>Login</a>";
} else {
echo "An error occured. Contact Site Admin"; }
Check if you have column 'field' in your users table. Seems suspicios.
Check your update string, now it misses table name.
Check if you have user before updating:
$exists = mysqli_query("SELECT id FROM users WHERE email='$em1');
if (!is_empty($exists)) {
mysqli_query("UPDATE TABLE users SET password = '$ps' WHERE id='$exists');
echo 'updated' . "\n";
} else {
echo 'no user with such email hash' . "\n";
}

Recurring Error Display error function php

I have an output_errors function on my website which outputs all the "set" errors in a variable.
It pretty much works exactly how it should except for one thing; for one error in particular, it will output that error more than once (which it shouldn't).
How it is supposed to work is: if the user that is registering does not input any information into a certain part of the form, it needs to output (once) the error Fields marked with an asterisk(*) must be filled in., along with any other errors that the user has come across. All of this is displayed in an unordered list.
This is the function that I have created:
function output_errors($errors){
return '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
}
This is the code in which I specify when an error should be output:
$required = array('fname', 'username', 'password', 'password_again', 'email');
$reqCCNo = array('ccno');
// validation
foreach($_POST as $key=>$value){
if(empty($value) && in_array($key, $required) === true){
$errors[] = 'Fields marked with an asterisk(*) must be filled in.';
}
if(empty($value) && in_array($key, $reqCCNo) === true){
$errors[] = 'Please select a country.';
}
}
if(empty($errors)){
// credentials
if(preg_match('/[^a-z_\-0-9]/i', $fnp) || preg_match('/[^a-z_\-0-9]/i', $lnp)){
$errors[] = 'Credentials must only contain letters and numbers.';
}
// username
$result = mysqli_query($conn, "SELECT username FROM users WHERE username = '$user'");
$count = mysqli_num_rows($result);
if($count !== 0) {
$errors[] = 'That username is already taken.';
}
if(strlen($user) < 4){
$errors[] = 'Your username must be more than 4 characters long.';
}
if(strlen($user) > 16){
$errors[] = 'Your username must not be more than 16 characters long.';
}
if(preg_match('/[^a-z_\-0-9]/i', $user)){
$errors[] = 'Your username can only contain Alphanumeric characters.';
}
// email
if(filter_var($emailNex, FILTER_VALIDATE_EMAIL) === false){
$errors[] = 'That is not a valid email type.';
}
$email_result = mysqli_query($conn, "SELECT email FROM users WHERE email = '$emailNex'");
$email_count = mysqli_num_rows($email_result);
if($email_count !== 0) {
$errors[] = 'That email is already in use.';
}
// password
if(strlen($pass) < 6){
$errors[] = 'Your password must be more than 6 characters long.';
}
if($pass !== $_POST['password_again']){
$errors[] = 'Those passwords do not match!';
}
}
and, this is the code that I use to output all of those errors:
if(!empty($errors)){
echo output_errors($errors);
}
Say that I leave all the fields blank and input a username less than 4 characters long, this is how it should be output:
Fields marked with an asterisk(*) must be filled in.
Your username must be more than 4 characters long.
this is how it is being output right now:
Fields marked with an asterisk(*) must be filled in.
Fields marked with an asterisk(*) must be filled in.
Fields marked with an asterisk(*) must be filled in.
Please select a country.
Your username must be more than 4 characters long.
All help is appreciated!
Thanks
Problem is with your foreach loop. it insert error message for every Required file.
You need to create a flag outside your foreach loop and set it to true when it comes inside your condition as
$flag=FALSE;// set it false
foreach($_POST as $key=>$value){
if(empty($value) && in_array($key, $required) === true){
$flag=TRUE;// set true if fulfill your condition
}
}
if($flag){// set your message
$errors[] = 'Fields marked with an asterisk(*) must be filled in.';
}
It will set your error message once instead of multiple

smarter php login form validation

I've started learning PHP and MySQL for a while but I still consider myself a beginner!
I created a simple register form and I also wrote PHP code to validate it...
I want to know if there is a better and smarter way to accomplish my goal.
My form is based on 5 inputs: username, password, repeat password, email, repeat email and it sends through POST, their content and a button's value. It must check these conditions when a submit is performed:
show error "All fields empty" if all inputs are empty
show error "Some fields empty" if one or more inputs, but not all, are empty
username length must be up to 20 chars
password and repeat password must be equal
passwords must be between 8 and 20 chars
email and repeat email must be valid emails and must be equal
show an error message of what went wrong
I wrote this function (it's inside a class) which does everything I said above but can I improve it to reduce repetitive code? Are there other PHP functions which can be used for this? And finally, how secure is my code?
Here is it!
public function processRegisterInfo($POSTArray = array())
{
if (count(array_filter($POSTArray)) > 1) // button don't have to be counted
{
if (count(array_filter($POSTArray)) < 6)
{
$this->errorMsg = "Some fields are empty";
return FALSE;
}
else
{
$username = $POSTArray["username"];
$password = $POSTArray["password"];
$repPassword = $POSTArray["repPassword"];
$email = $POSTArray["email"];
$repEmail = $POSTArray["repEmail"];
$isValid = TRUE;
// Checking username length
if (strlen($username) > 20)
{
$this->errorMsg .= " Username too long.";
$isValid = FALSE;
}
// Checking password length and equality
if (strcmp($password, $repPassword) == 0)
{
if (strlen($password) < 8)
{
$this->errorMsg .= " Password must be at least 8 characters.";
$isValid = FALSE;
}
else if (strlen($password) > 20)
{
$this->errorMsg .= " Password must be max 20 characters long.";
$isValid = FALSE;
}
}
else
{
$this->errorMsg .= " Passwords don't match.";
$isValid = FALSE;
}
// Checking email validation and equality
if (strcmp($email, $repEmail) == 0)
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
{
$this->errorMsg .= " Email provided is not valid.";
$isValid = FALSE;
}
}
else
{
$this->errorMsg .= " Emails don't match.";
$isValid = FALSE;
}
if (isset($this->errorMsg) && !empty($this->errorMsg))
$this->errorMsg = substr($this->errorMsg, 1);
return $isValid;
}
}
else
{
$this->errorMsg = "All fields are empty";
return FALSE;
}
}
Thank you so much for your help! :)
If you are only able to use php it's as good as it's going to get i think.
These check can be performed by Jquery(javasript) to.
The pros of using jquery are, you don't have to submit it first and you can easily mark which field has a wrong value.

Categories