I know you can run multiple queries with mysqli_multi_query but I have a problem :
For a registration page I want to perform 2 checks and then an insert :
Check1 = Does username exist?
Check2 = Email already been used?
If both checks are negative then do the insert query.
But how can I sepperate the errors ?
when a username exists it has to return 'Username already exists'
if email is already been used it has to return 'Email already in use'
Here is my code:
$sql = "check username query; ";
$sql .= "check email query; ";
$sql .= "Insert query";
if (mysqli_multi_query($conn,$sql)) {
do
{
if ($result=mysqli_store_result($conn)) {
while ($row=mysqli_fetch_row($result)) {
if (mysqli_num_rows($result) > 0) {
//DO STUFF
//Here do i need to return if the username or email exists or not.
};
mysqli_free_result($result);
};
} else {
echo 'Query fout!';
};
while (mysqli_next_result($con));
};
mysqli_close($con);
You do not write a ; after an if statement or a loop. Furthermore, your do {} while(); loop is not in the correct format.
Correct Format:
$sql = "check username query; ";
$sql .= "check email query; ";
$sql .= "Insert query";
if (mysqli_multi_query($conn,$sql)) {
do {
if ($result = mysqli_store_result($conn)) {
while ($row = mysqli_fetch_row($result)) {
if (mysqli_num_rows($result) > 0) {
//DO STUFF
//return if the username or email exists
}
mysqli_free_result($result);
}
}
else {
echo 'Query fout!';
}
} while (mysqli_next_result($con));
mysqli_close($con);
}
mysqli_multi_query() is not the tool to use for this.
That mysql[i] requires you to jump through hoops to execute more than one DML operation per call provides a lot of protection against sql injection (but it still falls a long way of a full solution for such attacks). There is no need to implement these as a multi-statement-query.
There is a performance and scalability benefit to limiting the number of round trips to the database - but you can do this:
SELECT SUM(IF('$username'=user.username, 1, 0)) AS usernames,
SUM(IF('$email'=user.email, 1, 0)) as emails
FROM users
WHERE username='$username' OR email='$email'
to get the results in a single query.
It would be even more efficient to not bother with a SELECT, but instead add a unique index to each of the attributes in the database then handle a duplicate record error if the INSERT fails although this does not make for such a nice user experience. OTOH it does prevent enumeration attacks against the database.
Related
I'm new to PHP and am practicing by programming a very basic signup form, which dumps the info into a MySQL database. However, I'm having a problem where, even if the name is taken, my program still adds the account to the SQL table.
This is my code to check if the name exists:
$sql = "SELECT * FROM accounts WHERE name = '$name'";
$result = $conn->query($sql);
if (mysql_fetch_array($result) === true) {
die("Error: Username has been taken");
} else {
//register account
}
Every time I run this, no matter what the name is, the program runs the block of code inside the else statement. I can provide more info if needed.
if you are using mysqli then use.
if ($result->num_rows > 0) {
die("Error: Username has been taken");
}
else {
// register here;
}
P.S do not use mysql read here.
You can alter the table and add make the field unique.
EDIT: 'solution' in my comment below
I am doing an AJAX POST to my back-end PHP where form data gets sent to a dedicated CRUD php form and is used to create a record.
The SQL syntax is such that I need 2 commands. Therefore, I use a BEGIN TRANSACTION; statements; COMMIT; structure, thus:
START TRANSACTION;
INSERT INTO tblTask (subject, dateOpened, priority) VALUES
('test 1', '2017-02-22 07:09:33', 3);
INSERT INTO tblTaskContent (idTask, dateEntered, text) VALUES
(LAST_INSERT_ID(), '2017-02-22 07:09:33', 'fdsa');
COMMIT;
*formatted for clarity, though all statements separated by ; and a following space.
That MySQL statement is spat out to the web console via a PHP echo statement, so that's what the program is outputting verbatim.
Here's the PHP:
if($action == 1) //CREATE
{
if($taskVarArr['subject'] && $taskVarArr['priority'] && $taskVarArr['content']) //can create the initial record
{
if(ReadTask($taskVarArr)) //task exists, consider updating existing record
{
echo "Row exists!"; //TODO IS DEBUG
return http_response_code(400);
die();
}
else if(CreateTask($taskVarArr)) //new record, insert
{
return http_response_code(200);
die();
}
}
//if this reached, bad request
return http_response_code(400);
die();
}
elseif($action == 2) //READ ...not used yet
{
}
EDIT: Here are the PHP functions CreateTask and ReadTask:
// Create - CRUD
function CreateTask($taskVarArr) //sorry for your eyes
{
$conn = OpenConnection();
$workingDate = date('Y-m-d h:i:s');
$sql = "START TRANSACTION; ";
$sql .= "INSERT INTO tblTask (subject, dateOpened, priority) VALUES ".
"('".$taskVarArr['subject']."', '$workingDate', ".$taskVarArr['priority']."); "; //TODO below this breaks
$sql .= "INSERT INTO tblTaskContent (idTask, dateEntered, text) VALUES ".
"(LAST_INSERT_ID(), '$workingDate', '".$taskVarArr['content']."'); "; //LAST_INSERT_ID() grabs last autonumber
$sql .= "COMMIT;";
//TODO IS DEBUG
echo $sql;
//TODO IS DEBUG
$result = mysqli_query($conn, $sql);
if($result)
{
return true;
}
return false;
}
// Read - CRUD; Only checks if record exists
function ReadTask($taskVarArr)
{
$conn = OpenConnection();
$sql = "SELECT idTask from tblTask WHERE subject = '".$taskVarArr['subject']."';";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$row = mysqli_fetch_assoc($result);
return $row['idTask'];
}
return false;
}
I get a 400 error on creation since ReadTask doesn't find the record and CreateTask doesn't complete successfully. However, when I paste the same statement into my MySQL PuTTY window without additional formatting, it accepts it just fine. After trying to run again with the same information, the program detects the row(s) exist and echoes "Row exists!" as it's supposed to. I have verified all credentials are correct and the connection is being opened as expected.
Is LAST_INSERT_ID() limited to PDO or a specific implementation within PHP? I thought MySQL was meant to interpret that.
If you're curious, I've split up tblTask and its content in tblTaskContent because I want the user to be able to add updates to their task as they go along. There's a tblTask id FK and a timestamp in tblTaskContent to keep the data linked and sortable based on update entry time.
Fixed.
// Create - CRUD
function CreateTask($taskVarArr) //sorry for your eyes
{
$conn = OpenConnection();
$workingDate = date('Y-m-d h:i:s');
$sql = "INSERT INTO tblTask (subject, dateOpened, priority) VALUES ".
"('".$taskVarArr['subject']."', '$workingDate', ".$taskVarArr['priority']."); ";
if(mysqli_query($conn, $sql))
{
$sql = "INSERT INTO tblTaskContent (idTask, dateEntered, text) VALUES ".
"(LAST_INSERT_ID(), '$workingDate', '".$taskVarArr['content']."'); "; //LAST_INSERT_ID() grabs last autonumber
if(mysqli_query($conn, $sql))
{
return true;
}
}
return false;
}
That's a dumb solution. I was hoping utilizing both mysqli_autocommit and mysqli_commit after the mysqli_querys would work, but it don't. It seems if I want a transaction I'll have to (learn how to) use PDO.
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 7 years ago.
Improve this question
I am trying to create an activation page that will GET the API & ACT codes from the url.
Then I am trying to query the DB on those codes to check if they're valid.
If they are not valid, I would like to echo an error stating echo "<strong><font color=red>Your Activation Code has Expired, or Your Activation Code is not Valid!</font></strong>";
If it is valid, then I would like to update with the 2nd SQL Query - "UPDATE users SET status='1', date_activated='$Activation_Date', Activation='' WHERE Activation='$Activation' AND API='$API' AND status='0'"
If there is NO API&ACT code in the URL, I would like to echo "CONTENT"
<?
require 'admin/config.php';
require 'Connection.php';
error_reporting(E_ALL);
$API = $_REQUEST['api'];
$Activation = $_REQUEST['act'];
$sql= mysql_query("SELECT * WHERE Activation='$Activation'");
if ($sql = 0) { echo"ERROR";}
else {
$Activation_Date = date('m-j-y - h-iA');
$sql = mysql_query("UPDATE users
SET status='1', date_activated='$Activation_Date', Activation=''
WHERE Activation='$Activation' AND API='$API' AND status='0'");
if($sql == 0){
echo "<strong><font color=red>Your Activation Code has Expired, or Your Activation Code is not Valid!</font></strong>";
} elseif ($sql > 0) {
echo "content";
}
}
?>
What you need to check for, is if a row exists.
To check if it exists and base yourself on the following model:
$sql = mysql_query("SELECT * WHERE Activation='$Activation'");
if(mysql_num_rows($sql) > 0){
//do something here or show error because relation already exists
}
else{
//relation already do not exists. so you can insert the record here
}
Then, to check if your UPDATE was truly successful, use mysql_affected_rows():
Sidenote: This function may require that you pass a db connection variable to it.
$sql = mysql_query("UPDATE users .... ");
if(mysql_affected_rows() > 0){
// do something
}
else {
// do something else
}
Check for errors against your PHP and MySQL:
Add error reporting to the top of your file(s) right after your opening PHP tag
for example <?php error_reporting(E_ALL); ini_set('display_errors', 1); then the rest of your code, to see if it yields anything.
Also add or die(mysql_error()) to mysql_query().
If you get errors about deprecation notices, then you will need to switch over to either mysqli_ or PDO.
You can consult one of my answers here https://stackoverflow.com/a/22253579/1415724 to check if a row exists.
It uses a few methods, including a prepared statement which is something you should be using because you are open to an SQL injection.
Sidenote: The connection API that you are using is unknown. Make sure that you are using the same one as your query being mysql_. If it's mysqli_ or PDO, those different APIs do not intermix. You must use the same one from connecting to querying.
Also, just a quick note about if ($sql = 0). The single equal sign "assigns" instead of "comparing" such as == or ===.
You stated in comments:
"IF the Activation code is active (the md5 has will be there)"
I hope you're not using that for password storage. If so, don't. That function is no longer safe to use to store passwords with.
Use one of the following:
CRYPT_BLOWFISH
crypt()
bcrypt()
scrypt()
On OPENWALL
PBKDF2
PBKDF2 on PHP.net
PHP 5.5's password_hash() function.
Compatibility pack (if PHP < 5.5) https://github.com/ircmaxell/password_compat/
Other links:
PBKDF2 For PHP
Seeing <? make sure that short tags are enabled. If not, change that to <?php.
HTML stickler.
<font color=red> the <font> tag is deprecated/obsole and isn't supported by HTML5.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font
It's best to use inline CSS if you are sending anything via Email.
I.e.: <p style="color:red;">Hello world</p>
Here are a few references:
http://www.tizag.com/cssT/inline.php
Inline <style> tags vs. inline css properties
http://webdesign.about.com/od/beginningcss/qt/tipcssinlinesty.htm
Remarks
Checking mandatory parameters:You can test if parameters are set like this:
isset(variable_name).
In the SELECT query there is missing the FROM clause which states the table to select from.I assume it is "user" like in the UPDATE query.
After a SELECT query, the cursor should be freed again, when it is no longer in use: mysql_free_result($sql);
(Error) Tests
The result of a query is ===false if the query could not be executed corectly.
After having SELECTed records, the function mysql_num_rows() shows the number or records retrieved.
After having UPDATed a table, the function mysql_affected_rows() gives the number of affected records.
Code snippet
// Get parameters and check if mandatory parameters are set
$API = isset($_REQUEST['api']) ? $_REQUEST['api'] : false;
$Activation = isset($_REQUEST['act']) ? $_REQUEST['act'] : false;
if ( ($API===false) || ($Activation===false)) {
$which = ($API === false ) ? '"api"' : '';
$which .= ($Activation === false) ? ((empty($which) ? '' : ', ') . '"act"') : '';
echo "ERROR: Parameter(s) missing: $which";
return;
}
// Select activation record
$sql= mysql_query("SELECT * FROM users WHERE Activation='$Activation'");
if ($sql===false) {
echo "SQL ERROR: " . mysql_error();
return;
} else {
$nrows = mysql_num_rows();
mysql_free_result($sql);
if ($nrows < 1) {
// No matching record found
echo "ERROR: No activation record found";
return;
} else {
// Update users record
$Activation_Date = date('m-j-y - h-iA');
$sql = mysql_query("UPDATE users
SET status='1', date_activated='$Activation_Date', Activation=''
WHERE Activation='$Activation' AND API='$API' AND status='0'");
if ($sql===false) {
echo "SQL ERROR: " . mysql_error();
} elseif(mysql_affected_rows() < 1) {
// No matching record found for updating
echo '<span style="color:red; font-weight:bold;">Your Activation Code has Expired, or Your Activation Code is not Valid!</span>';
} else {
echo "content";
}
}
}
Here is what I ended up with.
This is a Tweak from #hherger's answer....
// Report all errors
error_reporting(E_ALL);
// Get parameters and check if mandatory parameters are set // Get parameters and check if mandatory parameters are set
$API = isset($_REQUEST['api']) ? $_REQUEST['api'] : false;
$Activation = isset($_REQUEST['act']) ? $_REQUEST['act'] : false;
if ( ($API===false) || ($Activation===false)) {
}
// Select activation record
$sql= mysql_query("SELECT * FROM users WHERE Activation='$Activation'");
if ($sql===false) {
echo "SQL ERROR: " . mysql_error();
return;
} else {
$nrows = mysql_num_rows($sql);
mysql_free_result($sql);
if ($nrows < 1) {
// No matching record found
echo "REDIRECT USER TO HOME PAGE";
return;
} else {
// Update users record
$Activation_Date = date('m-j-y - h-iA');
$sql = mysql_query("UPDATE users
SET status='1', date_activated='$Activation_Date', Activation=''
WHERE pinAPP_Activation='$Activation' AND API='$API' AND status='0'");
if ($sql===false) {
echo "SQL ERROR: " . mysql_error();
} elseif(mysql_affected_rows() < 1) {
// No matching record found for updating
echo '<span style="color:red; font-weight:bold;">Your Activation Code has Expired, or Your Activation Code is not Valid!</span>';
} else {
echo "ECHO SUCCESS DISPLAY!";
}
}
}
This is the code I use at login:
$q = $lacz->query("SELECT email, pass, activation_code
FROM users
WHERE email='". $nazwa_uz_l ."'
AND pass = '". $haslo_l ."'
AND activation_code IS NULL ");
if($q->num_rows>0) {
$_SESSION['prawid_uzyt'] = $nazwa_uz_l; }
else
{
echo 'Pass or Log are wrong, or activation code is not confirmed (check email).';
exit;
}
In this query I check for all 3 things: email, password and activation code, and then output an error. What I want to do is to output an first error when Pass or Log are wrong and second error (something like elseif) when activation code IS not NULL. I tried else if and two queries, but I was getting the errors. Can You help me? I check the answers and give points, thanks.
Remove "AND activation_code IS NULL" from your query and do something like
if($q->num_rows>0)
{
$row = $q->fetch_assoc();
if(!is_null($row['activation_code']))
{
$_SESSION['prawid_uzyt'] = $nazwa_uz_l;
}
else
{
echo 'Activation code is not confirmed (check email).';
exit;
}
}
else
{
echo 'Pass or Log are wrong.';
exit;
}
Don't check the activation code in the query. Just get the user information, along with the activation code field:
SELECT email, pass, activation_code
..
WHERE email='foo' and pass='bar'
Then you can test the individual conditions in your code:
if (number_of_rows == 0) {
... bad username/password
} else if ($activation_code == '') {
... code is blank/null
}
If you remove the AND activation_code IS NULL from the query's WHERE clause, you'll be able to pull data for a user matching the given email/password. Then, with that, you'll be able to determine if the user exists, or if their activation code is empty:
$q = $lacz->query("SELECT email, pass, activation_code
FROM users
WHERE email='". $nazwa_uz_l ."'
AND pass = '". $haslo_l ."'");
if ($q->num_rows === 0) {
echo 'Password or email address are wrong.';
exit;
} else {
$row = $result->fetch_assoc();
if (empty($row['activation_code'])) {
echo 'Activation code is not confirmed.';
exit;
} else {
$_SESSION['prawid_uzyt'] = $nazwa_uz_l;
}
}
Side-note (not answer related): I highly suggest using a parameterized query instead of directly inserting the values into the SQL; if you prefer the current way, make sure you're sanitizing the input first to prevent SQL Injection.
I have a textbox UserName and a Check Availability button next to it..... I have checked the availability by passing UserName textbox value..... But it doesn't seem to work....
Here is what i am doing?
echo $UserName = $_GET['CheckUsername'];
$_SESSION['state'] = $State;
$queryres = "SELECT dUser_name FROM tbl_login WHERE dUser_name='$UserName'";
$result = mysql_query($queryres,$cn) or die("Selection Query Failed !!!");
if($result==true) // this condition doesn't seem to work
{
echo "User Name Available";
}
else
{
echo "Sorry user name taken";
}
Please make sure you're escaping your inputs for MySQL. Passing data directly from $_GET, $_POST or any of the other superglobals is unsafe.
// Escape any quote characters in the input
$UserName = mysql_real_escape_string($_GET['CheckUsername'], $cn);
$_SESSION['state'] = $State;
$queryres = "SELECT dUser_name FROM tbl_login WHERE dUser_name='$UserName' LIMIT 1";
$result = mysql_query($queryres, $cn) or die("Selection Query Failed !!!");
if (mysql_num_rows($result) > 0) {
echo 'User name exists in the table.';
} else {
echo 'User name does not exist in the table.';
}
if ($result == false)
{
echo "not available";
}
else
{
echo "available";
}
The reason yours doesn't work is because the value of $result will not be true as it contains an array. You could do it by reversing the statement to check for false first.
You can also do it with mysql_num_rows
if (mysql_num_rows($queryres) > 0)
{
echo "User name taken";
}
from http://php.net/mysql_query :
Return Values
For SELECT, SHOW, DESCRIBE, EXPLAIN and other statements returning resultset, mysql_query() returns a resource on success, or FALSE on error.
So to start off with, your if statement will never evaluate to false, because you have the "or die" on the mysql_query (which is activate when mysql_query returns false).
But your if condition is wrong altogether, because you don't want to know if the query failed, but if any results were returned. For this you probably want to use mysql_num_rows.
As a small tip, since you only need to know if there's 1 matching username, add "LIMIT 1" to the end of your query. Then mysql will return as soon as it hits the first match, instead of searching th whole table for more results.
As an alternative method, you could use a COUNT() query, and check the number returned in the result set.
Although this question has already an adequate answer, I'll give you another option. Simply remove the "==true" in the IF condition and it will automatically test for the presence of a value instead of a boolean comparison.
if($result) // this condition will now work
{
echo "User Name Available";
}
else
{
echo "Sorry user name taken";
}
You can use this if you want to preserve the signature of your code.
After Executing the Query just mysql_num_rows($result) which will return you the Count of Rows is fetched.
$queryres = "SELECT dUser_name FROM tbl_login WHERE dUser_name='$UserName'";
$result = mysql_query($queryres,$cn) or die("Selection Query Failed !!!");
if (mysql_num_rows($result))
{
echo "Username available";
}
else
{
echo "Username not available";
}