PHP MySQL Check for Key then implement if not used - php

I am trying to check my database for a key that has already been put in. If the key exists then I need it to check to make sure the username field hasn't been filled. If it has then it needs to throw an error so that it doesn't update and overwrite the information already stored in the database.
Everything works. The update functions etc. the only part that does not work is the checking if the key exists and if the username portion is filled(not sure exactly how to do that) before updating the database.
Thanks,
Cameron Andrews
Code:
// If the Register form has been submitted
$err = array();
if(strlen($_POST['username'])<4 || strlen($_POST['username'])>32){
$err[]='Your username must be between 3 and 32 characters!';
}
if(preg_match('/[^a-z0-9 _]+/i',$_POST['username'])){
$err[]='Your username contains invalid characters!';
}
if(!checkEmail($_POST['email'])){
$err[]='Your email is not valid!';
}
$resultN = mysql_query("SELECT * FROM Users WHERE key='".$_POST['kgen']."'");
while($row = mysql_fetch_array($resultN))//for the results that are returned set the local variables
{
if($_POST['kgen'] == $row['key']){
if($_POST['username'] == $row['usr']){
$err[]='Username already in use';
}
}else if($_POST['kgen'] == ""){
$err[]='Invalid Key Code!';
}else{
$err[]='Error occured please try again';
}
}
if(!count($err)){
// If there are no errors
$_POST['email'] = mysql_real_escape_string($_POST['email']);
$_POST['username'] = mysql_real_escape_string($_POST['username']);
$_POST['pass'] = mysql_real_escape_string($_POST['pass']);
// Escape the input data
$theName = $_POST['name'];
$theUser = $_POST['username'];
$thePass = $_POST['pass'];
$theEmail = $_POST['email'];
$theType = "member";
$theRegIP = $_SERVER['REMOTE_ADDR'];
$theDate = "NOW()";
$theKey = $_POST['kgen'];
// If everything is OK register
mysql_query("UPDATE cad.Users SET name = '$theName', usr = '$theUser', pass = '$thePass', email = '$theEmail', type = '$theType', regIP = '$theRegIP', dt = '$theDate' WHERE Users.key = '$theKey'");

Here is how I would approach it:
I would use mysqli or PDO instead of deprecated mysql functions.
I would rewrite all the queries to use prepared statements instead of concatenating your query string together - you have significant SQL injection vulnerability now.
But, since I am not going to rewrite your entire section of code for you, the rest of my approach will be described based on your current mysql/concatenated-query-string approach.
I would put a unique index on name field, but allow NULL value on the field.
I would simply run an update query rather than trying to run an unnecessary select plus an update.
UPDATE cad.Users
SET
name = '$theName',
usr = '$theUser',
pass = '$thePass',
email = '$theEmail',
type = '$theType',
regIP = '$theRegIP',
dt = NOW() /* don't pass 'NOW()' in single quotes as you are currently doing */
WHERE
Users.key = '$theKey'
AND User.name IS NULL;
If you get an error here you should look at error messaging to determine if update failed due to a unique constraint violation (user tried to enter a name that was already used in another record associated with a different key), or some other unexpected reason.
Assuming there was no error, I would then call mysql_affected_rows() (or appropriate equivalent in mysqli or PDO). If the return value is 1, an update was made. If the return value is 0, then no update was made because you did not have any rows that satisfied the WHERE condition.
If you get 0 affected rows, you can re-query the database if you really want to determine if the cause was no matching key or an existing user name.
SELECT name FROM Users WHERE key = '$theKey';
If you get no rows in the result it is because the key is missing, otherwise it is because the name was not a NULL value.
The net is that in the happy path use case, you only make a single query against the database rather than two, with two queries only being necessary if you want to determine the reason no update occurred for those cases. Your current approach always requires 2 queries.

First of all, you should see this. At second, i see, you have strange logic. Try to simplify it. :) As for me, i think it should looks like this:
<?php
if (strlen($_POST['username']) < 4 || strlen($_POST['username']) > 32) {
throw new RuntimeException('Your username must be between 3 and 32 characters!');
} elseif (preg_match('/[^a-z0-9 _]+/i', $_POST['username'])) {
throw new RuntimeException('Your username contains invalid characters!');
} elseif(!checkEmail($_POST['email'])) {
throw new RuntimeException('Your email is not valid!');
} elseif (empty($_POST['kgen'])) {
throw new RuntimeException('Invalid Key Code!');
}
$resultN = mysql_query("SELECT * FROM Users WHERE `key`='{$_POST['kgen']}' AND `usr`='{$_POST['username']}';");
$user = mysql_fetch_array($resultN);
if (!empty($user)) {
throw new RuntimeException('Username already in use');
}
// if all is fine - update
You can use exceptions for checking error. Benefit - you don't go to next check, if failed prev. You also have ability to show user exception message or reason(better use custom exception for this). Negative - you can't get list of errors.

Related

PHP always reports SQL success even when it fails

This is a simple one, maybe I'm having a long brain fart or something, but whats happening is the form is used to set a record only if the name and their cpukey matches then it will continue, as this is a public page with no login, it would be rather annoying for people to be changing other peoples things without knowing 2 sets in information. So the problem here is, the function itself actually works flawlessly, the Message produced which states SUCCESS or FAILURE always produces SUCCESS, even if the function failed (due to no match on one or more rows)
Here is the code used.
if(isset($_POST['upduserNotify'])){
$ccurrentname = mysqli_real_escape_string($con, $_POST['ccnameVal']);
$cclientnotify = mysqli_real_escape_string($con, $_POST['cnotifyVal']);
$cclientcpuk = mysqli_real_escape_string($con, $_POST['ccpukeyVal']);
$changenot = "UPDATE clients SET notify = '$cclientnotify' WHERE cpukey = '$cclientcpuk' AND name = '".$_POST['ccnameVal']."'";
if (mysqli_query($con, $changenot)) {
echo'<div align ="center" style="color:#000000">Your Custom notification was updated successfully</div><br />';
} else {
echo'<div align ="center">You entered an incorrect CPUKEY/Name or used an invalid character</div><br />';
}
}
An UPDATE query that runs, but finds no rows to update, is still a successful one - it ran to completion without encountering any errors, so mysqli_query will return TRUE, per the docs. (If it were a SELECT sort of query, it'd return a mysqli_result object.)
If you want to do something different when it didn't find any rows to update, you'll want to look at the number of affected rows and act accordingly.
if(isset($_POST['upduserNotify'])){
$ccurrentname = mysqli_real_escape_string($con, $_POST['ccnameVal']);
$cclientnotify = mysqli_real_escape_string($con, $_POST['cnotifyVal']);
$cclientcpuk = mysqli_real_escape_string($con, $_POST['ccpukeyVal']);
$changenot = "UPDATE `clients` SET `notify` = '$cclientnotify' WHERE `cpukey` = '$cclientcpuk' AND `name` = '$ccurrentname'";
if (mysqli_query($con, $changenot) && mysqli_affected_rows($con) == 1 )
{
echo'<div align ="center" style="color:#000000">Your Custom Xnotify was updated successfully</div><br />';
}
else if (mysqli_query($con, $changenot) && mysqli_affected_rows($con) == 0 )
{
echo'<div align ="center">You entered an incorrect CPUKEY/Name or used an invalid character</div><br />';
}
}

Database query returning incorrect row

I'm working on some web code which uses codeigniter and the built in querybuilder to access a database.
I attempt to load data from the database for the current user
$userModel = $this->loadModel('ModelUser');
$name = $this->session->userdata('user');
$user = $userModel->getUser($name);
This is the code forgetUser:
function getUser($username)
{
$this->db->where('username',$username);
$query = $this->db->get('tblusers',1);
$res = $query->result();
if ($query->num_rows() > 0)
{
log_message('debug','Got user. ID = '.$res[0]->id);
foreach($res[0] as $key => $val)
{
$this->$key = $val;
}
return $this;
}
else {
log_message('info','failed to find user '.$username);
return NULL;
}
}
This works fine except when I let the session expire, in which case I get the details of another user.
These are the results of testing getUser:
$userModel->getUser("Admin"); //Got user. ID = Admin_ID
$userModel->getUser("john"); //Got user. ID = John_ID
$userModel->getUser(""); //Failed to find user
$userModel->getUser(null); //Failed to find user
When I log in as Admin then let the session timeout, the top snippet logs the message:
Got user. ID = John_ID
I would expect either Got user. ID = Admin_ID or Failed to find user
When $this->session->userdata('field') does not find an entry, it returns 0 instead of the "" or null that I was testing against.
Logging $this->db->last_query() showed this since the resulting query was:
SELECT * FROM tblusers WHERE username = 0 LIMIT 1;
MySQL will automatically convert strings to integers where the string starts with an integer. A string without an integer will be cast to 0 as explained in this answer. The query was returning the first entry it came across instead of finding no rows as any string that didn't start with 1-9 would match the WHERE clause.
I added a clause to getUser to return NULL if $username == ''. I did try === 0 but that yielded the same error so there's some type coercion going on that I'm not 100% certain of, but this covers the issue nicer than handling the case each time getUser is called.

If else in sql insert

I want to make a code where if the data already exists in the database and the user insert the same input again and send to the database, the sql command will detect it and will not allow the duplicate data enter the database. Addtional information, I don`t have primary key for my table. Here is my code.
$sql="INSERT IGNORE INTO tempahan(Nama,Aktiviti,No_HP,Unit,Tempat,Tarikh_Penggunaan,Masa_Mula,Masa_Akhir,Email) VALUES('$_POST[name]','$_POST[Aktiviti]','$_POST[number]','$_POST[unit]','$_POST[tempat]','$_POST[tarikh]','$_POST[masa1]','$_POST[masa2]','$_POST[email]')";
$_POST['tempat'] = $data['Tempat'] ;
$_POST['masa1'] = $data['Masa_Mula'];
$_POST['masa2'] = $data['Masa_Akhir']; if($_POST['tempat'] != $data['Tempat'] && $_POST['masa1'] != $data['Masa_Mula'] && $_POST['masa2'] != $data['Masa_Akhir']) {
echo 'the booking was successful.';
}
else
{ echo 'the place already occupied.';}
I'm new to sql and also php. Therefore, I really need help from all of you guys. I already see the other same question. But, every solution provided I've failed.
The correct way to do this is to enforce a unique constraint on your table, across the fields that you consider to be unique. You can do that as such.
alter table tempahan
add unique (Tempat, Masa_Mula, Masa_Akhir)
Your database will then reject out of hand any attempts to insert duplicate data. No need to do a prior check before inserting.
Here is a very basic demo of what happens when you set your table up with this unique constraint, and then try and insert duplicate data. In short: it errors.
$query = $db->query( // query your table );
$array = array('name'=>$_POST['name'],
'address'=>$_POST['address']);
while ($row = mysqli_fetch_all($query)) {
$diff = in_array($array, $row);
{
if(empty($diff))
{
// insert data into table
}
else{
//data already exist
}
}
}
// first check existing recors on the database
$select = "SELECT `Tempat`, `Masa_Mula`, `Masa_Akhir`
FROM `tempahan`
WHERE `Tempat` = {$_POST['tempat']}
AND `Masa_Mula` = {$_POST['masa1']}
AND `Masa_Akhir` = {$_POST['masa2']}";
$result = mysql_query($select, $dbconnection);
// check if the have existing records
// the query fetching depends on your work
// but this is a simple way only
// but have more examples on the internet
// to make query more better and ellegant
if (mysql_num_rows($select) > 0) {
echo 'the place already occupied.';
} else {
// insert new record
$sql="INSERT IGNORE INTO tempahan(Nama,Aktiviti,No_HP,Unit,Tempat,Tarikh_Penggunaan,Masa_Mula,Masa_Akhir,Email)
VALUES(
'$_POST[name]',
'$_POST[Aktiviti]',
'$_POST[number]',
'$_POST[unit]',
'$_POST[tempat]',
'$_POST[tarikh]',
'$_POST[masa1]',
'$_POST[masa2]',
'$_POST[email]')";
echo 'the booking was successful.';
}

PHP Checking if specify entered Email & Id are matching to the ones in the database

I have recently switched from Mysql_* to PDO, heard it's the new, better more secure way of connecting and working with MySQL databases.
I have learned many basics of it like queries, prepare, etc.
What do I want to do
I currently have two text fields, named 'Email' and 'ID'.
When user registers, he enters his email, after he registers he receives his own ID, something unique.
I want him to be able to check the status of his account, without any passwords.
Simply by entering his email, and id and clicking 'submit'.
After clicking submit, the system should check if there's a column with the same email & ID.
If there is a column with these same exact email & IDs, then I can create a while loop to grab information from his account's column like creation date, and others..
My Question
How would I do this?
There's what I've done so far:
if (isset($email) && isset($id) && isset($submit)) {
$fetch = $connect->prepare("SELECT * FROM users WHERE email = :email LIMIT 1");
$fetch->bindValue(':email', $email);
$fetch->execute();
$validate = $fetch->fetchColumn();
if ($validate == 0) {
echo 'failed';
} else {
echo 'not failed';
}
while($row = $fetch->fetch( PDO::FETCH_ASSOC )) {
//We can fetch here...
}
}
My friend suggested me to use fetchColumn() which is replacing mysql_num_columns function, but It doesn't seem to work.
I enter a right email address, and it is still echoing 'Failed' instead of 'Not failed'.
Why doesn't this method work? Have I done this wrong?.
Thanks!
I don't think you want to fetch columns, but rows. You also don't actually check the ID either, but you can just add an AND condition to your query if necessary.
$fetch->execute();
if ($fetch->rowCount()) {
echo "Row was returned; match found";
}
else {
echo "No match found";
exit;
}
$row = $fetch->fetch(PDO::FETCH_ASSOC);
There will probably only be one row for you to fetch as well, but in case there aren't you can use the while loop as you did above.
$validate is a string containing the email address. When doing if ($validate == 0) you're typecasting $validate to an integer, and any non-numeric string becomes (int) 0, and so the comparison is always true.
Change to if ($validate === FALSE).

PHP if statement checking variable is empty issue

This is driving me nuts, I have a login function that checks to make sure that the users credentials are correct, and also checks to see if an 'activation' field for that user is empty (if it wasn't, it means that they haven't activated yet and therefore shouldn't be able to log in). If all of those conditions check out fine, it returns a user id in a variable, and if not it returns false.
Function
The function runs correctly right up until I add the if statement that checks if the variable $activation is empty, using empty(). If the field is truly empty, it returns the user_id like it's supposed to, but if the field isn't empty and still contains the 40 char activation code - it also lets the user log in. Which is ridiculous.
Here is the login function (with irrelevant portions removed):
function loginCheck($email, $password) {
$stmt = $dbh->prepare("SELECT `salt`,`activation` FROM `users` WHERE `email`= :email LIMIT 1");
$stmt->bindParam(':email', $email);
$stmt->execute();
if ($stmt->rowCount() == 1) {
$salt = $stmt->fetchColumn(0);
$activation = $stmt->fetchColumn(1);
if (empty($activation)) {
// another few unrelated tasks and query here to grab user id which is returned below
if ($stmt->execute()) {
return $stmt->fetchColumn(1); // the returned user ID
} else {
return false;
}
} else {
return false; // It should return this false here because the field IS NOT empty!
}
} else {
return false;
}
}
1) I have performed the first query manually, and it does in fact select the fields salt and activation flawlessly.
2) I have checked to make sure that the column being fetched and applied to the var $activation is correct, it is the second column so $activation = $stmt->fetchColumn(1) is fine.
Page
Now on the login.php page which calls the above function, here is the code relating to calling the function and logging in:
$login = loginCheck($email, $password);
if ($login === false) {
$errors[] = 'Unable to log you in';
}
if (!empty($errors)) {
foreach ($errors as $error) {
echo $error, '<br />';
}
} else {
$_SESSION['user_id'] = $login;
header('Location: you/default.php');
exit();
}
I've looked and looked and can't find any errors. Why on earth is this occurring?
EDIT
The activation field in my MySQL table is set to varchar(40) with a collation of utf8_general_ci, and since the activation field is populated with numbers and letters, I'm assuming it's a string.
And yes, the user_id that is returned is the one that relates to the user logging in, so that is correct.
As you can see here: http://php.net/manual/en/pdostatement.fetchcolumn.php,
There is no way to return another column from the same row if you use
PDOStatement::fetchColumn() to retrieve data.
This is because each time you call fetchColumn it will apply over the row next to the row on which the previous call applied.
$salt = $stmt->fetchColumn(0);
$activation = $stmt->fetchColumn(1);
The second call to fetchColumn() is working over the row next to that of the first call. In your case, as there is only one row, fetchColumn() returns NULL, so that's why activation appears as empty.
Use fetch() to retrieve an array with all the values of the row:
$row=$stmt->fetch();
$salt=$row[0];
$activation=$row[1];
Consider this approach..
Columns
`activation_code` varchar(40) not null,
`activated` tinyint(1) not null default '0',
Now create an activate function elsewhere, once complete update activated === 1 for the user
When you do you login check, consider:
Check Username
Check Password
Check activated === 1
I think you are using 'char' data type in the database for the activation. So you better try this code.
if (trim($activation)!= "")
{
}
Cheers!
Prasad.

Categories