I have this login and registration script from the net. Everything is working fine.
Objectives:
Usernames entered by the user will only be alphabets. If the username entered is not exist in the database, it will automatically add a number 1 on the username, example, user1.
Let's say the database have already had user1, user2, user3. Whenever a user entered user, it will then check what is the last incrementing number which in this case, it is 3, so it will then add into the database as user4.
Problems:
As I am trying to learn PDO as much as I could and it is still pretty difficult for me to understand. Also, I do not have any idea where should I start from.
Below are my current working code:
if (isset($_POST['submit'])) {
if(empty($_POST['username']) || empty($_POST['password'])){
$errors[] = 'All fields are required.';
}else if(!ctype_alpha($_POST['username'])){
$errors[] = 'Please enter only alphabet letters.';
}else{
if ($users->user_exists($_POST['username']) === true) {
$errors[] = 'That username already exists';
}
}
if(empty($errors) === true){
$username = htmlentities($_POST['username']);
$password = $_POST['password'];
$users->register($username, $password);
header('Location: register.php?success');
exit();
}
}
public function user_exists($username) {
$stmt = $this->db->prepare("SELECT COUNT(`id`) FROM `userinfo` WHERE `username`= ?");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
try{
$stmt->execute();
$rows = $stmt->fetchColumn();
if($rows == 1){
return true;
}else{
return false;
}
} catch (PDOException $e){
die($e->getMessage());
}
}
public function register($username, $password){
$password = sha1($password);
$stmt = $this->db->prepare("INSERT INTO `userinfo` (`username`, `password`) VALUES (?, ?) ");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
$stmt->bindValue(2, $password, PDO::PARAM_STR);
try{
$stmt->execute();
// mail($email, 'Please activate your account', "Hello " . $username. ",\r\nThank you for registering with us. Please visit the link below so we can activate your account:\r\n\r\nhttp://www.example.com/activate.php?email=" . $email . "&email_code=" . $email_code . "\r\n\r\n-- Example team");
}catch(PDOException $e){
die($e->getMessage());
}
}
Is there any kind souls out there can help me out on this? Letting me know where should I start and what should I do? Or the flow of the whole procedure in achieving my objectives.
Any help will be much appreciated! Thanks in advance.
Here is a example how to change your function to check if the user exist .. and which is the last index.
It is not pretty but will do the job and may be point you to the right ideas.
public function register($username, $password){
$password = sha1($password);
//check if the user exists and find first posible free index
$_username = $username;
if($this->db->query("SELECT * FROM `userinfo` WHERE `username` = 'user' ")){
$n = 1;
$max_index = 20;
while ($n < $max_index ) { //just to be safe
$_username = $username . $n;
if (!$this->db->query("SELECT * FROM `userinfo` WHERE `username` = '" . $_username . "' ")) {
break;
}
$n++;
}
if($n == $max_index){
die("Sorry ,there already (".$max_index.") entries of this username.");
}
}
//continue as normal just use $_username in the final query
$stmt = $this->db->prepare("INSERT INTO `userinfo` (`username`, `password`) VALUES (?, ?) ");
$stmt->bindValue(1, $_username, PDO::PARAM_STR);
$stmt->bindValue(2, $password, PDO::PARAM_STR);
try{
$stmt->execute();
// mail($email, 'Please activate your account', "Hello " . $username. ",\r\nThank you for registering with us. Please visit the link below so we can activate your account:\r\n\r\nhttp://www.example.com/activate.php?email=" . $email . "&email_code=" . $email_code . "\r\n\r\n-- Example team");
}catch(PDOException $e){
die($e->getMessage());
}
}
First of all you have to add a Sql-Wildcard like % _ * meaning see here to find all usernames they starts with "user" and have one or more charakter behind the "user"-string. Currently you only will get the username that excatly matchs the insert username.
But you could get some trouble by using the wrong wildcard, then
SELECT COUNT(id) FROM userinfo LIKE username = user%;
will always selct usernames like user1, user2, user3 but also something like userhorst..
To the pdo, the pdo help you to protect you system from sql injections. The prepare function sends only something like a query with wildcars for your parameter, thats means they send your statement without the parameters, to the Database. After this you send with the bindValue-function the single values to the Database. And finally you will excecute the statement. During this process the datapase can check each sended value for invalid signs.
Finally you have to check your if-statement. You will only get true when one user with the same name was in the database in all other cases (0,2,3,4,5,6,7) you get false.. But you want
if countUsers equal 0 then:
return false;
else
return true;
fi
Another part is you should thinking about using the sha1-hash, there are still better hashs to protect your passwords.
You can select all usernames like user* using:
SELECT username FROM `userinfo` WHERE username LIKE 'user%'
Next you should sort your results using asort:
asort($array_of_usernames);
then use substr or preg_match to get the number at the end of the username:
$number = substr($each_username, -1, 2) //within a foreach
Increment the number gotten then insert into database.
$new_username = "user" . $number++;
Thanks for the help guys!
Below are my current working code which I manage to tweak here and there based on the help given:
public function register($username, $password){
$stmt = $this->db->prepare("SELECT username FROM `userinfo` WHERE `username` LIKE :username");
$parse_username = "%".$username."%";
$stmt->bindValue(':username', $parse_username, PDO::PARAM_STR);
$stmt ->execute();
$user = $stmt->fetch();
$n = 1;
if($user){
$db_username = $user["username"];
$username_counter = preg_match("/".$username."(\d+)/", $db_username, $matches) ? (int)$matches[1] : NULL;
while ($n < $username_counter ) { //just to be safe
$new_username = $username . $n;
if (!$user) {
break;
}
$n++;
}
if($n == $username_counter){
$n++;
$new_username = $username.$n;
}
}else if(!$user){
$new_username = $username.$n;
}
$password = sha1($password);
$query = $this->db->prepare("INSERT INTO `userinfo` (`username`, `password`) VALUES (?, ?) ");
$query->bindValue(1, $new_username);
$query->bindValue(2, $password);
try{
$query->execute();
$_SESSION['new_username'] = $new_username;
// mail($email, 'Please activate your account', "Hello " . $username. ",\r\nThank you for registering with us. Please visit the link below so we can activate your account:\r\n\r\nhttp://www.example.com/activate.php?email=" . $email . "&email_code=" . $email_code . "\r\n\r\n-- Example team");
}catch(PDOException $e){
die($e->getMessage());
}
}
I am not sure that my way of coding is the best or professional, it is just based on my little logical knowledge of the flow. If there are any area where I can improve or rewrite, help me out if you wish to. =)
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
i have a query using PDO. password match was successful when I enter only strings or number. But when my password contains #& or anything like that it will tell that password is incorrect. Though in my database that was the right password.
session_start();
// Change this to your connection info.
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '';
$DATABASE_NAME = 'Data-Six';
// Try and connect using the info above.
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if ( mysqli_connect_errno() ) {
// If there is an error with the connection, stop the script and display the error.
die ('Failed to connect to MySQL: ' . mysqli_connect_error());
}
// Now we check if the data from the login form was submitted, isset() will check if the data exists.
if ( !isset($_POST['username'], $_POST['password']) ) {
// Could not get the data that should have been sent.
die ('Please fill both the username and password field!');
}
// Prepare our SQL, preparing the SQL statement will prevent SQL injection.
if ($stmt = $con->prepare('SELECT `used-id`, `username`, `password` FROM `user-list` WHERE `username` = ?')) {
// Bind parameters (s = string, i = int, b = blob, etc), in our case the username is a string so we use "s"
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
// Store the result so we can check if the account exists in the database.
$stmt->store_result();
}
if ($stmt->num_rows > 0) {
$stmt->bind_result($username, $password, $id);
$stmt->fetch();
// Account exists, now we verify the password.
// Note: remember to use password_hash in your registration file to store the hashed passwords.
if ($_POST['password'] === $password) {
// Verification success! User has loggedin!
// Create sessions so we know the user is logged in, they basically act like cookies but remember the data on the server.
session_regenerate_id();
$_SESSION['loggedin'] = TRUE;
$_SESSION['name'] = $_POST['username'];
$_SESSION['id'] = $id;
echo 'Welcome ' . $_SESSION['name'] . '!';
} else {
echo 'Incorrect password!';
}
} else {
echo 'Incorrect username!';
}
$stmt->close();
?>
The order of variables in bind_result doesn't follow the order of field names in the SQL query.
That said, store_result/bind_result is outdated and inconvenient method which was replaced by get_result that gets you a conventional PHP array.
Here is the code you need:
$sql = 'SELECT `used-id`, `username`, `password` FROM `user-list` WHERE `username` = ?';
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$user = $stmt->get_result()->fetch_assoc();
// if ($_POST['password'] === $password) { come onm you MUST use a hash
if ($user && password_verify($_POST['password'], $user['password']))
{
...
}
as you can see it is much more concise and convenient
I just figured out how to used the PDO statement XD! thanks team. what i did was just rearranged the query to match the Bind-result.
if ($stmt = $con->prepare('SELECT `username`, `password`, `used-id` FROM `user-list` WHERE `username` = ?')) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->store_result();
}
if ($stmt->num_rows > 0) {
$stmt->bind_result($username, $password, $id);
$stmt->fetch();
if ($_POST['password'] === $password) {
session_regenerate_id();
$_SESSION['loggedin'] = TRUE;
$_SESSION['name'] = $_POST['username'];
$_SESSION['id'] = $id;
echo 'Welcome ' . $_SESSION['name'] . '!';
echo 'Welcome ' . $_SESSION['id'] . '!';
} else {
echo 'Incorrect password!';
}
} else {
echo 'Incorrect username!';
}
This code simply registers the user but it's not working, I would like if someone could just double check this code to make sure, I think it has a problem with the SQL lines where it has to insert the user to the DB.
Users.php
public function register($email, $screenName, $password){
$stmt = $this->pdo->prepare("INSERT INTO users ('email', 'password',
'screenName', 'profileImage', 'profileCover') VALUES (:email, :password,
:screenName, 'assets/images/defaultProfileImage.png',
'assets/images/defaultCoverImage.png')");
$stmt->bindParam(":email", $email, PDO::PARAM_STR);
$stmt->bindParam(":password", md5($password), PDO::PARAM_STR);
$stmt->bindParam(":screenName", $screenName, PDO::PARAM_STR);
$stmt->execute();
$user_id = $this->pdo->lastInsertId();
$_SESSION['user_id'] = $user_id;
}
Login.php
if(!filter_var($email)){
$error = 'Invalid email format';
}else if(strlen($screenName) > 20){
$error = 'Name must be between 6-20 caracters long';
}else if(strlen($password) < 5){
$error = 'Password is too short';
}else{
if($getFromU->checkEmail($email) === true){
$error = 'Email already in use';
}else{
$getFromU->register($email, $screenName, $password);
header('Location: home.php')
}
}
}
}
You don't need to use " ' " single quote to specify the column list in Insert statement, unless you created these column in case-sensitive.
If you columns are not in Case-sensitive then you can use:
INSERT INTO users (email, password,screenName, profileImage, profileCover) VALUES (:email, :password,
:screenName, 'assets/images/defaultProfileImage.png',
'assets/images/defaultCoverImage.png')
SOLVED
Turns out I had a syntax error ";".
Mysql also doesn't like the be enclosed in quotes since it is closterfobic. Thanks to everyone who helped!
am currently working on a project and i have the script for insertion.my table is called survey and the fields are id,username,password,province. the username is set to unique key. the insertion process is working fine without any duplicate entry but when i try to insert a duplicate entry at always shows me this error
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'bluff' for key 'username'
I know what this error mean, my problem is that how can i can if username already exist or not i want an alert message to pop up..
here is my code
class.user.php
public function username($username){
$stmt = $this->db->prepare("SELECT count(*) FROM tish_images WHERE username = :username");
$stmt->execute(array($username));
$number_of_rows = $result->fetchColumn();
if($number_of_rows >= 1) {
echo 'username does exist'; // or return so you get the value
} else {
echo 'username does not exist'; //also return?
}
}
public function create($username,$password,$province)
{
try
{
$stmt = $this->db->prepare("INSERT INTO tish_images(username,password,province) VALUES(:username, :password, :province)");
$stmt->bindparam(":username",$username);
$stmt->bindparam(":password",$password);
$stmt->bindparam(":province",$province);
$stmt->execute();
return true;
}
catch(PDOException $e)
{
echo $e->getMessage();
return false;
}
}
index.php
<?php
include_once 'DB.php';
$username = isset($_GET['username']) ? $_GET['username'] : '';
$password = isset($_GET['password']) ? $_GET['password'] : '';
$province = isset($_GET['province']) ? $_GET['province'] : '';
if(isset($_FILES['files'])){
$id = $_GET['id'];
$username = $_POST['username'];
$password = $_POST['password'];
$province = $_POST['province'];
if($crud->upload($id,$FILE_NAME,$FILE_SIZE,$FILE_TYPE,$username,$password,$province))
{
echo "<script type='text/javascript'>alert('Successfully Updated!');</script>";
}
else
{
echo "<script type='text/javascript'>alert('Updating Failed!');</script>";
}
}
if(isset($_GET['id']))
{
$id = $_GET['id'];
extract($crud->getID($id));
}
You should run a SELECT before performing the query to see if the username exists.
// count how many rows with user name exists
$checkUserStmt = $this->db->prepare("
SELECT count(1)
FROM tish_images
WHERE username = :username
");
$checkUserStmt->execute(array(":username" => $username));
// fetch the count result
if ($checkUserStmt->fetchColumn() > 0) {
// username already exists
} else {
// username available
} //if
A few notes.
You still might get a duplicate entry error if you have two users trying to register the same username at close interval.
You should hash the password see Secure hash and salt for PHP passwords
To check if username or email already exists. I added email in there as this is also useful. You don't want two users with the same email address. Well I wouldn't see the need for it. :)
Complete code added and up to date.
$query_check_user_name = $this->db_connection->prepare('SELECT user_name, user_email FROM users WHERE user_name=:user_name OR user_email=:user_email');
$query_check_user_name->bindValue(':user_name', $user_name, PDO::PARAM_STR);
$query_check_user_name->bindValue(':user_email', $user_email, PDO::PARAM_STR);
$query_check_user_name->execute();
$result = $query_check_user_name->fetchAll();
if ($result > 0) {
echo "Someone with that username/email already exists.";
} else {
//Continue with proccessing the form
}
OR
$query_check_user_name = $this->db_connection->prepare('SELECT user_name, user_email FROM users WHERE user_name=:user_name OR user_email=:user_email');
$query_check_user_name->bindValue(':user_name', $user_name, PDO::PARAM_STR);
$query_check_user_name->bindValue(':user_email', $user_email, PDO::PARAM_STR);
$query_check_user_name->execute();
$result = $query_check_user_name->fetchAll();
if ($result > 0) {
return true;
} else {
return false;
}
Trying to handle the input from a check box as a boolean so that I can input the value amongst others into a database. The value is "mailingList" and i thought i had cracked it but it now just returns a pre defined error in my "catch" which should be unrelated. Below is the $_Post from the form
<?php
if (isset($_POST['register'])) {
$email = trim($_POST['email']);
$password = trim($_POST['pwd']);
$retyped = trim($_POST['conf_pwd']);
$firstname = trim($_POST['fname']);
$lastname = trim($_POST['lname']);
$company = trim($_POST['company']);
$mailinglist = trim($_POST['mailingListCheckbox']);
require_once('./includes/register_user_pdo.inc.php');
}
?>
then there is the related register_user_pdo.inc.php
<?php
require_once('./classes/CheckPassword.php');
$errors = array();
if (preg_match('/\s/', $email)) {
$errors[] = 'Email should not contain spaces.';
}
if (!isset($mailingList)) {
$mailingListValue = FALSE;
}
else {
$mailingListValue = TRUE;
}
$checkPwd = new Ps2_CheckPassword($password, 10);
$checkPwd->requireMixedCase();
$checkPwd->requireNumbers(2);
$checkPwd->requireSymbols();
$passwordOK = $checkPwd->check();
if (!$passwordOK) {
$errors = array_merge($errors, $checkPwd->getErrors());
}
if ($password != $retyped) {
$errors[] = "Your passwords don't match.";
}
if (!$errors) {
// include the connection file
require_once('./includes/connection.inc.php');
$conn = dbConnect();
// create a salt using the current timestamp
$salt = time();
// encrypt the password and salt with SHA1
$pwd = sha1($password . $salt);
// prepare SQL statement
$sql = 'INSERT INTO users (email, salt, pwd, lastName, firstName, company, mailingList)
VALUES (:email, :salt, :pwd, :lastName, :firstName, :company, :mailingList)';
$stmt = $conn->prepare($sql);
// bind parameters and insert the details into the database
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':salt', $salt, PDO::PARAM_INT);
$stmt->bindParam(':pwd', $pwd, PDO::PARAM_STR);
$stmt->bindParam(':lastName', $lname, PDO::PARAM_STR);
$stmt->bindParam(':firstName', $fname, PDO::PARAM_STR);
$stmt->bindParam(':company', $company, PDO::PARAM_STR);
$stmt->bindParam(':mailingList', $mailingListValue, PDO::PARAM_BOOL);
try {
$stmt->execute();
// check number of rows affected by previous insert
if ($stmt->rowCount() == 1) {
$success = "$email has been registered. You may now log in.";
}
}catch(PDOException $e){
if ($e->getCode() == 23000)
$errors[] = "Email is already in use. Please use another email address.";
else
$errors[] = 'Sorry, there was a problem with the database.';
}
}
?>
Any help would be much appreciated! Thanks in advance!
In your top segment of code you are defining
$mailinglist = trim($_POST['mailingListCheckbox']);
however in your second segment of code you are referencing
$stmt->bindParam(':mailingList', $mailingListValue, PDO::PARAM_BOOL);
You need to change your first part to
$mailingListValue = ....
EDIT
The above answer is wrong, actually it could be this :-
if (!isset($mailingList)) {
"L" is capitalised
Me again, more issues that I really can't find the cause off.
The below code is producing: "Issue" which means the first IF statement is false, should be true.
PHP:
function login($email, $password, $mysqli) {
//Use prepared statements to stop SQL Injection
if ($stmt = $mysqli->prepare("SELECT id, email, password, salt, perms FROM users WHERE email = ? LIMIT = 1")) {
$stmt->bind_param('s', $email); //Bind "$email" to paramater
$stmt->execute(); //Execute the query
$stmt->store_result();
$stmt->bind_result($user_id, $email, $db_password, $salt, $perms); //get variables from result
$stmt->fetch();
$password = hash('sha512', $password.$salt); //hash the password with the unique salt
if ($stmt->num_rows == 1) { //If user exists
//Check that user account isn't locked
if (checkbrute($user_id, $mysqli) == true) {
//Account is locked, alert user
return false;
} else {
if ($db_password == $password) { //Check that passwords match
//matches
echo "matches";
}
}
} else {
echo "No user found!";
}
} else {
echo "Issue";
}
}
$email and $password are not blank, and the $mysqli is the database object. Any ideas?
I can't figure it out at all, all looks fine to me.
You should really add mysql error reporting. It would of told you there was an issue in your query near LIMIT = 1.
Query should be:
SELECT id, email, password, salt, perms FROM users WHERE email = ? LIMIT 1
To add the error reporting, change the echo "issue"; to be:
echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
Limit = 1 should be LIMIT 1. Here's the if corrected :
if ($stmt = $mysqli->prepare("SELECT id, email, password, salt, perms FROM users WHERE email = ? LIMIT 1"))