Issue with PHP and Mysql - php

Good evening everyone, I'm having issues with my below code, Variable $uname is declared from a http post but for some reason the print out the the err log stays blank where it should show the results of the MySQL query
Field in table is called firstname (no caps)
$da= mysqli_query($c,
"SELECT * FROM users WHERE username='".$uname."'") or die(mysqli_error($c));
while ($row = mysqli_fetch_assoc($da)) {
error_log("User $Uname: match.");
error_log("FN : ".$row['firstname']."");
}
Any ideas ?

Add a message to tell you if no results were found by the query.
Since there can be only one user with a given username (I assume), you don't need a while loop. Just fetch that one row.
$row = mysqli_fetch_assoc($da));
if ($row) {
error_log("User $uname: match.");
error_log("FN : ".$row['firstname']."");
} else {
error_log("User $uname: no match.");
}
You also had a typo in your echo statement, $Uname should have been $uname.

First of all use a prepared statement: for security reasons you should never trust user inputs, prepared statements do the escaping for you.
Other than that I only see two reasons why nothing is logged:
error reporting is turned off ( this seems unlikely since you expect to see something in there)
the query is returning an empty result set and the while loop is skipped
try to print $uname or the full query and execute it

Related

How to check if a row has been updated? [duplicate]

This question already has answers here:
mysqli_affected_rows in PHP insert
(3 answers)
Closed 6 years ago.
I'm working with PHP and mysqli, what the program is doing is that it is asking for a reset code and email address if the email add and reset code are found in the database it sets the password,this part of the function is working,
I need help with this part: what I need to do is tell the user if the password was set or not so if the update was successful or not.
What I'm working on:
$uinsert = "UPDATE member SET password = '$password' WHERE emailadd = '$emailadd' AND resetCode = '$resetcode'";
$update = mysqli_query($mysqli, $uinsert) or die(mysqli_error($mysqli));
if(mysqli_affected_rows($update) == 1 ){ //ifnum
header("location: ../index.php"); // Redirecting To Other Page
}
else{
echo "<script> alert('Incorrect code, try again!');</script>";
}
Note: $mysqli is my connection string
"#Fred-ii- Thank you so much that works! – Coffee coder 58 secs ago"
Use if(mysqli_affected_rows($mysqli) >0 ) or no comparison at all.
Sidenote: ==1 is only comparing for 1, as opposed to >0 which you may be trying to update more than one row. However and on the rare occasion, >0 is required where this has also happened to me before; that is the reason of my answer.
affected_rows() uses the connection, not the one for the query.
http://php.net/manual/en/mysqli.affected-rows.php
Plus, if you're storing plain text passwords, use password_hash() since it's much safer:
http://php.net/manual/en/function.password-hash.php
Sidenote: If you do decide to move over to that function, make sure that you do not manipulate the password at all. Hashing/verifying it takes care of that and you may be doing more harm than good in doing so and limiting passwords.
I.e.: A valid password of test'123 would be interpreted as test\'123 and rendering FALSE when using real_escape_string() for example.
Or you may still be using hash_hmac as per your other question Comparing/check if correct Password from mysqli database [hash_hmac]
and a prepared statement:
https://en.wikipedia.org/wiki/Prepared_statement
It is also best to add exit; after header. Otherwise, your code may want to continue to execute.
header("location: ../index.php");
exit;
Change the parameter of mysqli_affected_rows(), the parameters must be the mysql connection
mysqli_affected_rows($update)
to
mysqli_affected_rows($mysqli)
Please see this reference
https://www.w3schools.com/php/func_mysqli_affected_rows.asp
if (mysqli_affected_rows($mysqli) == 1 ) {
Because mysqli_affected_rows() does not use the query $update as its parameter, it uses the connection variable: $mysqli
pass your mysqli connection object ($connection) to mysqli_affected_rows(connection_object) to check affected rows.
connection_object is like - $con=mysqli_connect("localhost","bd_user","db_password","your_db_name");
So , code will be
if(mysqli_affected_rows($con)== 1 ){
header("location: ../index.php");
}

Why is INSERT INTO followed by SELECT LAST_INSERT_ID() not outputting anything?

The PHP code I have inserts the HTML form data from the previous page into the database and in the same SQL statement return the PostID back from the inserted data. The PostID column is AUTO_INCREMENTING. I have been researching this problem for a week or two now and have found no significant solutions.
<?php
include("dbconnect.php");
mysql_select_db("astral_database", $con);
session_start();
$username = $_SESSION['username'];
$forumtext = $_POST["forumtext"];
$forumsubject = $_POST["forumsubject"];
$postquery = 'INSERT INTO Forums (Creator, Subject, Content) VALUES ("$username", "$forumsubject", "$forumtext"); SELECT LAST_INSERT_ID()';
$result = mysql_query($postquery, $con);
if (!$con) {
echo "<b>If you are seeing this, please send the information below to astraldevgroup#gmail.com</b><br>Error (331: dbconnect experienced fatal errors while attempting to connect)";
die();
}
if ($username == null) {
echo "<b>If you are seeing this, please send the information below to astraldevgroup#gmail.com</b><br>Error (332: Username was not specified while attempting to send request)";
die();
}
if ($result != null) {
echo "last id: " . $result;
$fhandle = fopen("recentposts.txt", "r+");
$contents = file_get_contents("recentposts.txt");
fwrite($fhandle, json_encode(array("postid" => $result, "creator" => $username, "subject" => $forumsubject, "activity" => time())) . "\n" . $contents);
fclose($fhandle);
mysql_close($con);
header("location: http://astraldevgroup.com/forums");
die();
} else {
die("<b>If you are seeing this, please send the information below to astraldevgroup#gmail.com</b><br>Error (330: Unhandled exception occured while posting forum to website.)<br>");
echo mysql_error();
}
mysql_close($con);
?>
First off, the mysql_query doesn't return anything from the SELECT statement. I haven't found anything that will properly run both the SELECT statement and the INSERT statement in the same query. If I try running them in two different statements, it still doesn't return anything. I tried running the following statement in the SQL console and it ran perfectly fine without errors.
INSERT INTO Forums (Creator, Subject, Content) VALUES ("Admin", "Test forum 15", "This is a forum that should give me the post id."); SELECT LAST_INSERT_ID();
The mysql_query function does not run multiple statements
Reference: http://php.net/manual/en/function.mysql-query.php
mysql_query() sends a unique query (multiple queries are not supported) to the currently active database on the server ...
That's one reason your call to mysql_query isn't returning a resultset.
The most obvious workaround is to not try to run the SELECT in the same query. You could use a call to the mysql_insert_id instead.
Reference: PHP: mysql_insert_id http://php.net/manual/en/function.mysql-insert-id.php
Answers to some of questions you didn't ask:
Yes, your example code is vulnerable to SQL Injection.
Yes, the mysql_ interface has been deprecated for a long time.
Yes, you should being using either PDO or mysqli interfaces instead of the deprecated mysql_ functions.
FOLLOWUP
Re-visiting my answer, looking again at the question, and the example code.
I previously indicated that the code was vulnerable to SQL Injection, because potentially unsafe values are included in the SQL text. And that's what it looked like on a quick review.
But looking at it again, that isn't strictly true, because variable substitution isn't really happening, because the string literal is enclosed in single quotes. Consider what the output from:
$foo = "bar";
echo '$foo';
echo '"$foo"';
Then consider what is assigned to $postquery by this line of code:
$postquery = 'INSERT ... VALUES ("$username", "$forumsubject", "$forumtext")';
Fixing that so that $username is considered to be a reference to a variable, rather than literal characters (to get the value assigned to $username variable incorporated into the SQL text) that would introduce the SQL Injection vulnerability.
Prepared statements with bind placeholders are really not that hard.
$result will never be null. It's either a result handle, or a boolean false. Since you're testing for the wrong value, you'll never see the false that mysql_query() returned to tell you that the query failed.
As others have pointed out, you can NOT issue multiple queries in a single query() call - it's a cheap basic defense against one form of SQL injection attacks in the PHP mysql driver. However, the rest of your code IS vulnerable other forms of injection attacks, so... better start reading: http://bobby-tables.com
Plus, on the logic side, why are you testing for a null username AFTER you try to insert that very same username into the DB? You should be testing/validating those values BEFORE you run the query.

PHP MySQLi Prepare Statement Failing to return rows

I have been converting a lot of my old MySQL stuff to MySQLi in PHP and am getting a problem on the following code:
### FETCH INCLUDES ###
$player=$_POST['player'];
$password=md5($_POST['password']);
#### DB CONNECTION ####
if(!$mysqli=new mysqli(DBHOST,DBUSER,DBPWD,DBNAME)) {$err=$mysqli->error; print($err); }
$sql="SELECT * FROM accounts WHERE name='?' AND passkey='?'";
if($stmt=$mysqli->prepare($sql)) {
//$stmt->bind_param('ss',$player,$password);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows==1) {
$account=$stmt->fetch_assoc();
// purely for debugging
print_r($account);
if($_SESSION['account']=$account) $account=true;
} else {
echo "Failed. Row count: ";
print($stmt->num_rows);
echo "<br />";
$query=str_replace('?','%s',$sql);
printf($query,$player,$password);
$account=false;
}
$stmt->close();
} else {
$err=$mysqli->error;
print($err);
}
I have narrowed down the fault to the query itself. I am getting 0 rows returned, no errors, so I thought I would output the query (the str_replace thing I have going there) and I can use the query to return a row from the database using the same query from PHPMyAdmin
Where am I going wrong?
EDIT
I tried changing the query to a basic one without binding params - "SELECT * FROM table"
still get no rows returned. So it is isn't the query itself, it would be something in my order/format of the prepare,execute situation
second edit: I have added the $stmt->store_result() to the code and still returns 0 row count.
Third Edit:
I investigated the connection and user settings which seem fine. I can connect via console to the database using the same user and password, and the database name is the same. I am really stumped on this :(
Add a $stmt->store_result(); after $stmt->execute();, as it seem's it must be called once before $stmt->num_rows... At least they do this in the examples (see http://php.net/manual/en/mysqli-stmt.store-result.php). And they meantion a dependency in the documentation of "num_rows".
Other ideas: You check for if($stmt->num_rows==1) {, are you sure num_rows is 0? I don't know your database structure for the table "accounts". Is "name" the primary key (or at least a unique index)? If not, there could be multiple columns that match. That's just a quick idea what could be wrong, and cause you looking hours for the problem in your source code. While the problem is somewhere else.
Ok, I did check your code. First you should fix your error handling when connecting. Don't check for "$mysqli" is true but check mysqli_connect_errno() like this:
$mysqli=new mysqli(DBHOST,DBUSER,DBPWD,DBNAME);
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
On my server the your code worked with correct credentials (e.g. DBHOST,DBUSER,DBPWD,DBNAME needed to be replaced).
And the statement $account=$stmt->fetch_assoc(); doesnt work. There is no fetch_assoc() function in the $stmt object. The fetch_assoc() is for mysqli::result objects obtained by using normal queries (not prepared statements). You need to use $stmt->bind_result(); and then $stmt->fetch(); Also you should to put a list of all column names in the query instead of "*", this defines a field order...
I got it working, I ended up needing the $stmt->store_result();
But I also noticed I had added single quotes around the ? in the prepare statement which was causing problems.
After taking those out and leaving in the store_result method it works!

PHP MySQL SELECT Query only returning resources

I'm currently working on building a download platform in which a user receives a random code and uses it to access an mp3 for download for up to three downloads. I generated a list of random codes using Python and imported them into a SQL table with an empty column for an associated email addresses and a default 0 for the use count. I wrote the following PHP script in order to associate an email with a certain code and add to the count so a download can be accessed up to three times.
$email = $_POST["email"];
$email = stripslashes($email);
$uniqueCode = $_POST["uniqueCode"];
$uniqueCode = stripslashes($uniqueCode);
// check that all fields are filled
if($uniqueCode=="" || $email=="")
apologize("Please fill out all fields.");
// check to make sure that the e-mail is valid
if (verifyEmail($email) == FALSE)
apologize("Please enter a valid e-mail address.");
// check if uniqueCode input is alphanumeric
if (verifyCode($uniqueCode) == FALSE)
apologize("Download codes are alphanumeric.");
// check to see if unique code is correct
$sql = mysql_query("SELECT * FROM wd009 where uniqueCode='$uniqueCode'");
$result = mysql_fetch_array($sql);
if($sql==FALSE)
{
apologize("Your download code is invalid. Please try again");
}
// only allow users with less than 3 downloads to proceed
else if ($result['count'] <= 3) {
if ($result['email'] == ""){
mysql_query("UPDATE wd009 SET email='$email', count=1 WHERE uniqueCode='$uniqueCode'");
apologize("added email");
}
else if ($result['email'] != $email)
apologize("different email from record!!");
else if ($result['email'] == $email){
mysql_query("UPDATE wd009 SET count=count+1 WHERE uniqueCode='$uniqueCode'");
apologize("updated the count!");
}
else
apologize("Your download code is used up!");
Obviously I use some functions in the above that aren't included in the code but I've checked all of them and none of them should interfere with the MySQL query. It may be of note that apologize() exits immediately after apologizing. When I input a correct code into the form, it works correctly and updates the SQL database. However, as long as the download code input is alphanumeric, the form will accept it even though the string definitely does not match any in the table. Namely, mysql_query returns a resource no matter the input. I've checked the database connection but since the table is correctly updated when the download code is correct, that doesn't seem to be the problem.
I've tried debugging this every way I could think of and am genuinely befuddled. Any help you could offer would be greatly appreciated!
As you can see in the manual, mysql_query always returns a resource for a valid query so you need to change your logic and count the number of rows it returns, not the result of mysql_query.
Apart from that, mysql_query, is deprecated and you should use mysqli or PDO.
You can count the number of rows with the - equally deprecated - mysql_num_rows function. 0 rows would be no valid code in your case.
This
if($sql==FALSE)
should probably be something like
if(mysql_num_rows($sql) == 0)
Edit: I agree, mysqli or PDO is preferred now.
The issue probably is this line:
if($sql==FALSE)
{
apologize("Your download code is invalid. Please try again");
}
Since the sql is a string it is accepting is as true and passing it as valid. One thing you also might like to do to avoid sql injection is use parameters instead of directly injecting user input.
$sql = mysql_query("SELECT * FROM wd009 where uniqueCode='$uniqueCode'");
Instead, do something like this:
$stmt = $mysqli->prepare("SELECT * FROM wd009 where uniqueCode=?");
$stmt->bind_param($uniqueCode);
$stmt->execute();
while ($stmt->fetch()) {
.....
You'll also want to do it this way for the update statement too.
If you have a lot of data in that table you may want to restrict the columns returned in the SQL statement so it lessens the load on the database.

php authentication script

I need the following authentication script finished. I am weak at php/pdo so I do not know how to ask for the number of rows equalling one and then setting the session id's from the results of the query. I need to not only set the $_SESSION['userid'] but also the ['company'] and the ['security_id'] as well from the results.
here is what I have:
$userid = $_POST['userid'];
$password = $_POST['pass'];
if ( $userid != "" || $password != "" )
{
$sql = "SELECT * FROM contractors WHERE userid = '" . $userid . "' AND password = '" . $password . "'";
$result = $dbh->query( $sql );
} else
{
echo "login failed. Your fingers are too big";
}
Optional Information:
Browser: Firefox
DO NOT EVER USE THAT CODE!
You have a very serious SQL injection open there. Every user input that you take, whether from cookies or CGI, or wherever, must be sanitized before it's used in an SQL statement. I could easily break into that system by attempting a login with an username like:
user'; UPDATE contractors SET password = '1337'
... after which I could then login as anyone. Sorry if I sound aggressive, but what that code does is like forgetting to lock the front door into your company which probably doesn't even contain an alarm system.
Note that it doesn't matter whether the input is actually coming from the user or not (perhaps it's in a pre-filled, hidden from). From the security point of view, anything that comes from anywhere outside has to be considered to contain malicious input by the user.
As far as I know, you need to use the quote function of PDO to properly sanitize the string. (In mysql, this would be done with mysql_real_escape_string().) I'm not an expert on PDO, mind you, somebody please correct if I'm wrong here.
Also you probably shouldn't store any passwords directly in the database, but rather use a hash function to create a masked password, then also create a hash from the user provided password, and match the hashes. You can use the PHP hash function to do this.
As for other issues, I don't know if the approach you have on SQL SELECT is the best approach. I would just select the corresponding user's password and try matching that in the program. I don't think there's any fault in the method you're using either, but it just doesn't seem as logical, and thus there's a greater chance of me missing some bug - which in case of passwords and logins would create a window for exploits.
To do it your way, you need to notice that the result you are getting from the PDO query is a PDOStatement, that doesn't seem to have a reliable function to diretly count the amount of result rows. What you need to use is fetchAll which returns an array of the rows, and count that. However, as I said this all feels to me like it's open for failures, so I'd feel safer checking the password in the code. There's just too much distance from the actual password matching compasion for my taste, in such a security-critical place.
So, to the get the resulting password for the userid, you can use PDOStatement's fetch() which returns the contents of the column from the result. Use for example PDO::FETCH_ASSOC to get them in an associative array based on the column names.
Here's how to fix it:
$userid_dirty = $_POST['userid'];
$password_dirty = $_POST['pass'];
$success = false; // This is to make it more clear what the result is at the end
if ($userid != "" || $password != "") {
$userid = $dbh->quote($userid_dirty);
$passwordhash = hash('sha256',$password_dirty);
$sql = "SELECT userid, passwordhash, company, security_id FROM contractors WHERE userid = ".$userid;
$result = $dbh->query( $sql );
if ($result) { // Check if result not empty, that userid exists
$result_array = $result->fetch(PDO::FETCH_ASSOC);
if ($result_array['PASSWORDHASH'] == $passwordhash) {
// login success
$success = true;
// do all the login stuff here...
// such as saving $result_array['USERID'], $result_array['COMPANY'], $result_array['SECURITY_ID'] etc.
} // else fail, wrong password
} // else fail, no such user
} else {
// fail, userid or password missing
echo ' please enter user id and password.';
}
if (!$success) {
echo ' login failed.';
}
Of course, the code can be cleaned up a bit, but that should explain what needs to be done. Note that since the password is both hashed, and never used in the SQL, it doesn't actually need cleaning. But I left it there just in case, since in the original code it was used in the query.
Note that all the code concerning storing passwords need to be changed to store the hash instead of the password. Also, it would be a very good idea to use a salt added to the password before hashing.
Also, I provided the code simply for educational purposes - I just thought that code was the clearest way to explain how to do this. So do not mistake this site as a service to request code. :)
The php manual is an excellent resource for learning PHP. It looks like you know a little SQL, and you have heard of PDO, which is a good start. If you search google for "PDO", or look in the PHP manual for the term, you'll find the PDO section of the manual. It looks like you've found the ->query function, so now you need to see what that returns. Going to the that function's manual page, we see that it returns a PDOStatement object. The word PDOStatement is helpfully linked to the relevant page in the manual, which lists the methods available on that object. There is a rowCount() method that will likely do what you want.

Categories