I'm reaching out after hours of fruitlessly trying to fix a small section of code that just doesnt seem to work regardless of how i try to fetch the value and store.
I will admit I'm not the most experienced and hoping it is a small error on my part that can be easily spotted by someone with more expertise.
All other functions work as expected and fetch all the required value except one, With s the member_id field. This is a linked ID from another table (companies) however in test query the statement works fine.
Whole Code Snippet
<?php
//Error reporting - DEV ONLY
error_reporting(E_ALL);
ini_set('display_errors', 'on');
//New Connection
$mysqli = new mysqli('localhost', 'USER', 'PASSWORD', 'DATABASE');
//Connection Verification
if ($mysqli->connect_errno) {
printf("Connection Failure: %s\n", $mysqli->connect_error);
exit();
}
//Start Session and assign POST values
session_start();
$username = $_POST['username'];
$password1 = $_POST['password'];
//Query prepare, execution and bind
$stmt = $mysqli->prepare("SELECT password FROM user WHERE username='$username'");
$stmt -> execute();
$stmt -> bind_result($result);
/* Fetch the value */
$stmt -> fetch();
/* Close statement */
$stmt -> close();
//Verify password match and direct user according to result
if(password_verify($password1, $result))
{
$stmt = $mysqli->prepare("SELECT member_id FROM user WHERE username='$username'");
$stmt -> execute();
$stmt -> bind_result($company);
$_SESSION['loggedin'] = true;
$_SESSION['username'] = $username;
$_SESSION['company'] = $company;
Header("Location: home.php");
}else{
sleep(5);
Header("Location: index.php");
}
$mysqli->close();
?>
Suspected Issue Code Snippet
if(password_verify($password1, $result))
{
$stmt = $mysqli->prepare("SELECT member_id FROM user WHERE username='$username'");
$stmt -> execute();
$stmt -> bind_result($company);
$_SESSION['loggedin'] = true;
$_SESSION['username'] = $username;
$_SESSION['company'] = $company;
Header("Location: home.php");
}else{
sleep(5);
Header("Location: index.php");
}
Thank you in advance for your help!
EDIT: The issue is, there is no output from:
SELECT member_id FROM user WHERE username='$username
However in a direct query with MySQL it works so feel its a binding issue. this should be bound to $_SESSION['company'].
The other answer is somewhat examplary.
As the question is going to be closed anyway, I'd take a liberty to comment the other answer.
change the name of your second instance of $stmt to something else - $stmtTwo
There is no point in doing that, as previous statement is already closed and cannot interfere in any way.
Would I be writing PHP for 15 years, I would rather suggest to do all the mysql job in one single query, without the need of second statement at all.
add a var_dump($stmtTwo); after binding the result into $company.
That's quite a random poke. Why after binding but not anywhere else?
check your MySQL log for MySQL errors.
For 99% of php users that's mission impossible. Yet it's a matter of only two commands to have the error message right on the screen on the development server.
Is the column member_id in the user table?
That is again a random poke (what about password field?) and it's have to be addressed to the error message discussed in the previous topic anyway. There is no point in asking a programmer for that. One should ask a database, as a way more reliable source.
Add a print output inside it, to show that the password_verify function is working and allowing that code block to execute.
That's the only good point.
Recommendation for using prepared statements is right too, but for some reason it is called "Object style" which is nowhere near the point.
And yes, he finally managed to spot the typo that makes whole question offtopic - fetch() statement is absent.
I suspect that your MySQL is not firing because you're using a PREPARE statement without passing it any values.
Would I be using mysqli myself, I would have known that such a query is all right.
header should be lower case. header() and should be immediately followed by a die or exit command.
Neither is actually true.
Functions in PHP are case insensitive and there is no logic behind this point - so, no manual exit is required.
Stack Overflow is not a code review site either, but nobody cares actually, as one third of answers to those celebrated 10M questions are actually code review answers. So here it goes:
<?php
//Error reporting - ALWAYS PRESENT
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
//Error displaying - DEV ONLY
ini_set('display_errors', 'on');
//New Connection
$mysqli = new mysqli('localhost', 'USER', 'PASSWORD', 'DATABASE');
//Start Session
session_start();
//Query prepare, bind, execute and fetch
$stmt = $mysqli->prepare("SELECT member_id, password FROM user WHERE username=?");
mysqli->bind_param("s",$_POST['username']);
$stmt->execute();
$stmt->bind_result($member_id, $db_pass);
$stmt->fetch();
if(password_verify($_POST['password'], $db_pass))
{
$_SESSION['username'] = $_POST['username'];
$_SESSION['company'] = $member_id;
Header("Location: home.php");
}else{
Header("Location: index.php");
}
You have not added a Fetch statement after binding the result:
if(password_verify($password1, $result))
{
$stmt = $mysqli->prepare("SELECT member_id FROM user WHERE username='$username'");
$stmt -> execute();
$stmt -> bind_result($company);
$stmt -> fetch();
/* Close statement */
$stmt -> close();
$_SESSION['loggedin'] = true;
$_SESSION['username'] = $username;
$_SESSION['company'] = $company;
Some extra notes:
You are writing your MySQL incorrectly, it is wide open to compromise.
You are using the old MySQL style approach but with the structure of the newer OOP approach, this is just as much as security risk as original MySQL.
Old - procedural- style:
mysqli_query($link, "SELECT poops FROM bathroom WHERE smell = '$bad' LIMIT 1");
New - Object Orientated style:
mysqli->prepare("SELECT poops FROM bathroom WHERE smell = ? LIMIT 1")
mysqli->bind_param("s",$bad); //the value is placed by reference rather than directly
mysqli->execute;
Also:
header should be immediately followed by a die or exit command.
header("Location:blah.php");
exit;
Related
The above error keeps coming up instead of redirecting to index.php
The code should start an admin user session on index.php.
It was originally based on MySQL then I used MYSqli
<?php
$a = $_POST["username"];
$b = $_POST["password"];
$conn = new mysqli("localhost", "root", "", "...");
$query = $conn->query("SELECT * FROM users WHERE username='$a' AND password='$b' AND isadmin=1");
$result = mysqli_query($conn, $query) or die(mysqli_error($conn));
$num_rows = mysqli_num_rows($result);
session_start();
if ($result)
{
$_SESSION["admin"] = $_POST["username"];
header ("Location: index.php");
}
elseif (!$result)
{
$_SESSION["gatekeeper"] = $_POST["username"];
header ("Location: index.php");
}
else
{
Your main error is that you call the query() method twice. Both $conn->query and mysqli_query() are the same thing, and when you pass the result of one to the other you get this cryptic error.
Another issue is that your connection for mysqli is not up to the standards. See https://phpdelusions.net/mysqli/mysqli_connect to learn more about connecting. You should also enable error reporting with mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); instead of manually checking for errors with or die(mysqli_error($conn));
You should use parameterized prepared statements instead of manually building your queries. They are provided by PDO or by MySQLi. Never trust any kind of input! Even when your queries are executed only by trusted users, you are still in risk of corrupting your data.
Never store passwords in clear text or using MD5/SHA1! Only store password hashes created using PHP's password_hash(), which you can then verify using password_verify(). Take a look at this post: How to use password_hash and learn more about bcrypt & password hashing in PHP
I haven't fixed all of your issues, I leave that as an exercise for you, but this should act as a guide on what the proper mysqli code should look like.
<?php
session_start();
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = new mysqli("localhost", "root", "", "...");
$conn->set_charset('utf8mb4');
$stmt = $conn->prepare('SELECT * FROM users WHERE username=? AND password=? AND isadmin=1');
$stmt->bind_param('ss', $_POST["username"], $_POST["password"]);
$stmt->execute();
$result = $stmt->get_result();
$firstRow = $result->fetch_assoc(); // See https://phpdelusions.net/mysqli/check_value
if ($firstRow) {
$_SESSION["admin"] = $_POST["username"];
exit(header("Location: index.php")); // Always `exit()` after `header('Location: ...');`
} elseif (!$result) {
$_SESSION["gatekeeper"] = $_POST["username"];
exit(header("Location: index.php")); // Always `exit()` after `header('Location: ...');`
}
You don't need to call $conn->query when assigning the $query variable. Just assign the string. The next line executes the query.
$query = "SELECT * FROM users WHERE username='$a' AND password='$b' AND isadmin=1";
Your code executes the query, then tries to execute the result again as if it were a query string.
Here is the code for blocking comments from blocked users. Comments are getting blocked for only the first blocked user in the database table, but i want the comments to be hidden for all the blocked users in database table.
<?php
include_once('adminpanel/dbconnect.php');
$sql_query =mysql_query("SELECT * FROM blocked_accounts WHERE
blocker_id=".$id);
$rr=mysql_fetch_array($sql_query);
if($rr['blocked_id'] == $r['id'] && $rr['blocker_id'] == $id)
{
echo "";
}
else
{ ?>
You need to go through all the records and if any of them match, then this is blocked. This code first sets a flag to say it isn't blocked, then if any of the records match, sets this to true and breaks out of the loop (not worth carrying on)...
<?php
include_once('adminpanel/dbconnect.php');
$sql_query = $conn->prepare( "SELECT * FROM blocked_accounts WHERE
blocker_id= ?");
$sql_query->bind_param("i", $id);
$sql_query->execute();
$blocked = false;
while ($rr=mysqli_fetch_assoc($sql_query)) {
if($rr['blocked_id'] == $r['id'] && $rr['blocker_id'] == $id)
{
$blocked = true;
break;
}
}
if($blocked)
{
echo "";
}
else
{ ?>
As mentioned in the comments, this is update to mysqli_ and prepared statements, you will need to change your connect to use mysqli as well (PHP mysqli connect function may helpd if you are not sure).
Using mysql_* functions is very bad practice because they have been outdated for many years. Since you're in the phase of learning, it's best to focus on learning how to use prepared statements, whether in the form of mysqli or PDO and stick with that.
As to the problem at hand, the code you've given is vague and things that are needed to send the query, such as the connection, are missing. Therefore, my answer aims to guide you into using mysqli prepared statements correctly rather than give you a full-fledged solution.
Code:
<?php
# Establish a connection to the database.
$connection = new mysqli("your host", "your username", "your password", "your db");
# Create a mysqli query.
$query = "SELECT * FROM `blocked_accounts` WHERE `blocker_id` = ?";
# Prepare the query and check whether the operation was successful.
if ($stmt = $connection -> prepare($query)) {
# Bind the parameters to the statement.
$stmt -> bind_param("i", $id); # 'i' means integer
# Execute the statement and check whether the operation was successful.
if ($stmt -> execute()) {
# Get the result out of the statement and cache it.
$result = $stmt -> get_result();
# Close the statement.
$stmt -> close();
# Fetch the first row (use 'while' if you want more).
if ($row = $result -> fetch_assoc()) {
# Check whether the user is blocked...
}
}
}
# Shut down the database connection.
$connection -> close();
?>
Notes:
When you're trying to query the database, remember to use the actual connection you established. In your mysql_query function call, there is not connection passed.
The part && $rr['blocker_id'] == $id in your if check is redundant because the value of $id is the value we used to filter the results returned by the database, so it will be always true.
I have a simple question. I'm not too good at programming yet but is this safe and correct?
Currently I am using functions to grab the username, avatars, etc.
Looks like this:
try {
$conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e)
{
echo "Connection failed: " . $e->getMessage();
}
config.php ^^
function getUsername($userid) {
require "config/config.php";
$stmt = $conn->prepare("SELECT username FROM accounts WHERE id = ? LIMIT 1");
$stmt->execute([$userid]);
$name = $stmt->fetch();
return $name["username"];
}
function getProfilePicture($userid) {
require "config/config.php";
$stmt = $conn->prepare("SELECT profilepicture FROM accounts WHERE id = ? LIMIT 1");
$stmt->execute([$userid]);
$image = $stmt->fetch();
return $image["profilepicture"];
}
Is this correct and even more important, is this safe?
Yes, it's safe with respect to SQL injections.
Some other answers are getting off topic into XSS protection, but the code you show doesn't echo anything, it just fetches from the database and returns values from functions. I recommend against pre-escaping values as you return them from functions, because it's not certain that you'll be calling that function with the intention of echoing the result to an HTML response.
It's unnecessary to use is_int() because MySQL will automatically cast to an integer when you use a parameter in a numeric context. A non-numeric string is interpreted as zero. In other words, the following predicates give the same results.
WHERE id = 0
WHERE id = '0'
WHERE id = 'banana'
I recommend against connecting to the database in every function. MySQL's connection code is fairly quick (especially compared to some other RDBMS), but it's still wasteful to make a new connection for every SQL query. Instead, connect to the database once and pass the connection to the function.
When you connect to your database, you catch the exception and echo an error, but then your code is allowed to continue as if the connection succeeded. Instead, you should make your script die if there's a problem. Also, don't output the system error message to users, since they can't do anything with that information and it might reveal too much about your code. Log the error for your own troubleshooting, but output something more general.
You may also consider defining a function for your connection, and a class for your user. Here's an example, although I have not tested it:
function dbConnect() {
try {
$conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e)
{
error_log("PDO connection failed: " . $e->getMessage());
die("Application failure, please contact administrator");
}
}
class User {
protected $row;
public function __construct($userid) {
global $conn;
if (!isset($conn)) {
$conn = dbConnect();
}
$stmt = $conn->prepare("SELECT username, profilepicture FROM accounts WHERE id = ? LIMIT 1");
$stmt->execute([$userid]);
$this->row = $stmt->fetch(PDO::FETCH_ASSOC);
}
function getUsername() {
return $this->row["username"]
}
function getProfilePicture() {
return $this->row["profilepicture"]
}
}
Usage:
$user = new User(123);
$username = $user->getUsername();
$profilePicture = $user->getProfilePicture();
That looks like it would work assuming that your config file is correct. Because it is a prepared statement it looks fine as far as security.
They are only passing in the id. One thing you could do to add some security is ensure that the $userid that is passed in is the proper type. (I am assuming an int).
For example if you are expecting an integer ID coming in and you get a string that might be phishy (possible SQL injection), but if you can confirm that it is an int (perhaps throw an error if it isn't) then you can be sure you are getting what you want.
You can use:
is_int($userid);
To ensure it is an int
More details for is_int() at http://php.net/manual/en/function.is-int.php
Hope this helps.
It is safe (at least this part of the code, I have no idea about the database connection part as pointed out by #icecub), but some things you should pay attention to are:
You only need to require your config.php once on the start of the file
You only need to prepare the statement once then call it on the function, preparing it every time might slow down your script:
The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. - PHP Docs
(Not an error but I personally recommend it) Use Object Orientation to help organize your code better and make easier to mantain/understand
As stated by #BHinkson, you could use is_int to validate the ID of the user (if you are using the IDs as numbers)
Regarding HTML escaping, I'd recommend that you already register your username and etc. HTML escaped.
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
Would you please help me sort this problem out. I don't know what I'm doing wrong. My connection to database working correct but I'm unable to login.
login.php
<?php
session_start();
$username= $_POST["username"];
$password= $_POST["password"];
include("/inc/connect.inc.php");
if(!isset($conn)){
$conn = null;
header('Location: index.php');
}
else{
$query = $conn->prepare("SELECT * FROM `users` WHERE `username`='$username' AND `password`='$password'");
$query ->execute(array(':username' =>$username, ':password' =>$password)
);
if ( ($query->rowCount() == 0) && ( ($password == null) or ($username == null) ) ){
echo "<h3>Please enter your username and password</h3>";
$conn = null;
header("Refresh: 3;URL=index.php");
}
else if ($query->rowCount() == 1)
{
$_SESSION['user_logged'] = $_POST['username'];
unset($username);
unset($password);
echo "<h3>Your password is correct</h3>";
$conn = null;
header("Refresh: 3;URL=interface.php");
}
else {
echo "<h3>The username / password combination entered is incorrect!</h3>";
unset($username);
unset($password);
$conn = null;
header("Refresh: 3;URL=index.php");
}
}
?>
Previously I didn't understand stackoverflow rules. I hope this time my question is more accurate. I have done lot of work to get to this point and only have a problem with login to my database now. My $query = $conn->prepare not finding anything. It's jumping to The username / password combination entered is incorrect! at any time. If I leave username or/and password empty or putting correct username and password always the same result.
I am posting this because it is an answer that addresses the real issue as to why the OP's code isn't working.
Firstly, a typo in bname which should read as dbname in your connection.
Now, you are mixing MySQL APIs with mysql_ functions and PDO.
Those different APIs do not intermix with each other.
In comments you said:
"You are welcome to convert my code to PDO. I can understand that this code is mixed up but have no idea how to fix it."
I don't like coming off as or sounding like the "bad man" here, but that isn't our job to convert your mysql_ code to PDO, it's yours. We don't convert code on Stack, we help out with problematic code.
There are plenty of tutorials out there for you to learn and use.
Here are but a few, which you can further your research on Stack/Google:
http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
http://code.tutsplus.com/tutorials/why-you-should-be-using-phps-pdo-for-database-access--net-12059
http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html
There is also the manuals on PHP.net
http://php.net/manual/en/ref.pdo-mysql.php
http://php.net/manual/en/pdo.query.php
On Stack:
How can I properly use a PDO object for a parameterized SELECT query
Regarding MD5 for passwords:
$password = md5($password);
MD5 is old and considered broken and no longer safe to use for password storage.
I recommend you use CRYPT_BLOWFISH or PHP 5.5's password_hash() function. For PHP < 5.5 use the password_hash() compatibility pack.
"I'm getting blank screen. Any ideas?"
Regarding "a blank screen".
This means you have syntax errors.
Doing error_reporting(0); means "Turn off all error reporting"
As per the manual on PHP.net
http://php.net/manual/en/function.error-reporting.php
What you need to do is turn error reporting on, not off.
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// rest of your code
Sidenote: Error reporting should only be done in staging, and never production.
If you look in the connection string there is a typo:
Take a look at the examples here http://php.net/manual/en/pdo.connections.php
Update: You seem to be totally lost so I'll step by step the code and the reason for things not working. The code I write will be filled with echo and print statements.
1.) You need to check your database connection but you have no code to do this. The connection might be fine but PHP does not throw an error.
try
{
$conn = new PDO('mysql:host=localhost;dbname=' . $database . 'charset=utf8', $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if(is_object($conn) && $conn != false)
{
echo "I'm connected. PDO is ready and willing";
}
else
{
echo "Sorry something went horribly wrong! Not connected to database";
{
}
catch(PDOException $e)
{
throw new pdoDbException($e);
echo die('Error Message:'.$e->getMessage());
}
2.) It will look like your connection is not working because none of functions is calling a connection. The connection object created is outside of the functions scope.
function user_exists($username)
{
global $conn; // bring the connection object into scope
$username = sanitize($username);
$query = $conn->prepare("SELECT COUNT(user_id) FROM users WHERE username = :username");
$query ->execute(array(
':username' =>$username
));
$user = $query->fetch(PDO::FETCH_ASSOC);
return $user. ' exists in database';
}
3.) there's lots of code but none of the functions looks like they are being called at runtime. Test for user exists and if database connection works at runtime in the init.php file
<?php
session_start();
require 'database/connect.php';
require 'functions/general.php';
require 'functions/users.php';
$errors = array();
// call a function to check if user exists.
echo user_exists('user_123');
?>
1st step. Change
$conn = new PDO('mysql:host=localhost;bname='.$database.'charset=utf8',$username,$password);
to
$conn = new PDO('mysql:host=localhost;dbname='.$database.';charset=utf8',$username,$password);
2st. You use mysqli and pdo in one project. For what?
I'm fairly new to PHP/MySQL and I seem to be having a newbie issue.
The following code keeps throwing me errors no matter what I change, and I have a feeling it's got to be somewhere in the syntax that I'm messing up with. It all worked at home 'localhost' but now that I'm trying to host it online it seems to be much more temperamental with spaces and whatnot.
It's a simple login system, problem code is as follows:
<?php
session_start();
require 'connect.php';
echo "Test";
//Hash passwords using MD5 hash (32bit string).
$username=($_POST['username']);
$password=MD5($_POST['password']);
//Get required information from admin_logins table
$sql=mysql_query("SELECT * FROM admin_logins WHERE Username='$username' ");
$row=mysql_fetch_array($sql);
//Check that entered username is valid by checking returned UserID
if($row['UserID'] === NULL){
header("Location: ../adminlogin.php?errCode=UserFail");
}
//Where username is correct, check corresponding password
else if ($row['UserID'] != NULL && $row['Password'] != $password){
header("Location: ../adminlogin.php?errCode=PassFail");
}
else{
$_SESSION['isAdmin'] = true;
header("Location: ../admincontrols.php");
}
mysql_close($con);
?>
The test is just in there, so I know why the page is throwing an error, which is:
`Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in 'THISPAGE' on line 12`
It seems to dislike my SQL query.
Any help is much appreciated.
EDIT:
connect.php page is:
<?php
$con = mysql_connect("localhost","username","password");
if(!$con) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("dbname", $con);
?>
and yes it is mysql_*, LOL, I'll get to fix that too.
You should escape column name username using backtick, try
SELECT *
FROM admin_logins
WHERE `Username` = '$username'
You're code is prone to SQL Injection. Use PDO or MYSQLI
Example of using PDO extension:
<?php
$stmt = $dbh->prepare("SELECT * FROM admin_logins WHERE `Username` = ?");
$stmt->bindParam(1, $username);
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
?>
Sean, you have to use dots around your variable, like this:
$sql = mysql_query("SELECT * FROM admin_logins WHERE Username = '". mysql_real_escape_string($username)."' ");
If you use your code just like this then it's vulnerable for SQL Injection. I would strongly recommend using mysql_real_escape_string as you insert data into your database to prevent SQL injections, as a quick solution or better use PDO or MySQLi.
Besides if you use mysql_* to connect to your database, then I'd recommend reading the PHP manual chapter on the mysql_* functions,
where they point out, that this extension is not recommended for writing new code. Instead, they say, you should use either the MySQLi or PDO_MySQL extension.
EDITED:
I also checked your mysql_connect and found a weird regularity which is - if you use " on mysql_connect arguments, then it fails to connect and in my case, when I was testing it for you, it happened just described way, so, please try this instead:
$con = mysql_connect('localhost','username','password');
Try to replace " to ' as it's shown in the PHP Manual examples and it will work, I think!
If it still doesn't work just print $row, with print_r($row); right after $sql=mysql_query() and see what you have on $row array or variable.