I have a simple demo php scripts am trying out. i have been using the deprecated mysql_ extensions earlier, trying to migrate from that to mysqli_ is being overly buggy. when trying to use mysqli_real_escape_string php throws a variable not defined error cant seem to figure out why.
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "bridgoo";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
//do stuff
}
// prepare and bind
$stmt = $conn->prepare("INSERT INTO bridgoo_users (username, email, password) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $username, $password, $email);
//generate password hash using blowfish algorithm
$password_hash = password_hash($_POST['password'], PASSWORD_BCRYPT, ["cost" => 9]);
$username = clean_input($_POST['username']);
$password = clean_input($password_hash);
$email = clean_input($_POST['email']);
function clean_input($input){
$input = htmlentities($input);
$input = htmlspecialchars($input,ENT_QUOTES);
$input = mysqli_real_escape_string($conn,$input);
return $input;
}
$stmt->execute();
$stmt->close();
$conn->close();
?>
php error Notice: Undefined variable: conn in C:\xampp\server1\htdocs\bridgoo\inc\register.php on line 24
The error about undefined variable $conn has to do with PHP variable scope, and other people have answered that.
But your code needs some other suggestions too.
You don't need to clean inputs at all if you use query parameters. That's the point of using query parameters: No need for mysqli_real_escape_string() because parameters are automatically safe.
In fact, you must not use mysqli_real_escape_string(), because your data will be inserted to your database literally with \' escaped apostrophes.
Simply put: SQL parameters and mysqli_real_escape_string() are mutually exclusive. Don't do both.
Also, it makes no sense to use htmlentities() or htmlspecialchars () at all for sanitizing SQL inputs, even if you use mysqli_real_escape_string() instead of parameters.
Those html-related functions are for HTML output only. They're very important for protecting your web app against XSS vulnerabilities, which is another unrelated web security risk you need to know about. But they're not needed for sanitizing SQL input.
Other comments:
It's confusing that you're re-using username and password variables for both the mysqli connection and the application data. There's no reason to re-use variables, they don't cost you anything.
Make sure the order of parameters in your INSERT matches the order of bind variables you pass to bind_param().
Always check the return value of prepare() and execute(). They return FALSE if they fail. If they fail, you must log the error and report to the user that the page didn't work.
I prefer to log the technical error message to the PHP error log
file, and report something more friendly to the user.
Get into the habit of keeping a window open to watch your PHP error log during development, it'll help you a lot.
Here's how I suggest you write your code:
<?php
$mysql_servername = "localhost";
$mysql_username = "root";
$mysql_password = "";
$mysql_dbname = "bridgoo";
$conn = new mysqli($mysql_servername, $mysql_username, $mysql_password, $mysql_dbname);
if ($conn->connect_error) {
error_log($conn->connect_error);
die("Sorry, a database error occurred.");
}
$stmt = $conn->prepare("
INSERT INTO bridgoo_users (username, password, email)
VALUES (?, ?, ?)");
if ($stmt === false) {
error_log($conn->error);
die("Sorry, a database error occurred.");
}
$stmt->bind_param("sss", $username, $password_hash, $email);
//generate password hash using blowfish algorithm
$password_hash = password_hash($_POST['password'], PASSWORD_BCRYPT, ["cost" => 9]);
$username = $_POST['username'];
$email = $_POST['email'];
if ($stmt->execute() === false) {
error_log($conn->error);
die("Sorry, a database error occurred.");
}
if ($stmt->affected_rows == 1) {
echo "Success!"
} else {
echo "Sorry, an unknown problem occurred, and your record was not saved."
}
Your clean_input function does not have access to your $conn variable, it lives in a different scope.
The easy solution would be to add the connection as a parameter to the function. Something like this:
<?php
...
$username = clean_input($_POST['username'], $conn);
$password = clean_input($password_hash, $conn);
$email = clean_input($_POST['email'], $conn);
function clean_input($input, $conn){
...
Wether that is the best or cleanest solution I'll leave in the middle, but it should work just fine.
You should pass $conn as parameter to your function clean_input;
$username = clean_input($conn, $_POST['username']);
$password = clean_input($conn, $password_hash);
$email = clean_input($conn, $_POST['email']);
function clean_input($conn, $input){
$input = htmlentities($input);
$input = htmlspecialchars($input,ENT_QUOTES);
$input = mysqli_real_escape_string($conn,$input);
return $input;
}
Related
The form sends the data to this page. The print_r outputs everything I want to put into the table onscreen to check it's there, but nothing goes to the table. I have only managed to populate the table manually in phpmyadmin. Iam sorry if it's a really easy fix - I have only been learning for two weeks!
There are no errors showing in the logs or on screen when I run the page. The print_r does echo the array as it should be but nothing appears in the table
<?php
session_start();
// Change this to your connection info.
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '';
$DATABASE_NAME = 'users';
$username = ($_POST['username']);
$password = ($_POST['password']);
$companyName = ($_POST['companyName']);
$confirmPassword = ($_POST['confirmPassword']);
// 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());
}
print_r ($_POST);
// Now we check if the data was submitted, isset() function will check
//if the data exists.
if (!isset($_POST['username'], $_POST['password'],
$_POST['companyName'])) {
// Could not get the data that should have been sent.
die ('Please complete the registration form!');
}
// Make sure the submitted registration values are not empty.
if (empty($_POST['username']) || empty($_POST['password']) ||
empty($_POST['companyName'])) {
// One or more values are empty.
die ('Please complete the registration form');
}
print_r ($_POST);
// We need to check if the account with that username exists.
if ($stmt = $con->prepare('SELECT id, password FROM phplogin WHERE
username = ?')) {
// Bind parameters (s = string, i = int, b = blob, etc), hash the
//password using the PHP password_hash function.
$stmt->bind_param('s', $_POST['username']);
$stmt->execute();
$stmt->store_result();
// Store the result so we can check if the account exists in the
// database.
if ($stmt->num_rows > 0) {
// Username already exists
echo 'Username exists, please choose another!';
} else {
// Username doesnt exists, insert new account
/* $stmt = $con->prepare('INSERT INTO phplogin (username, password,
companyName ) VALUES (?, ?, ?)');*/
if (false !== true){
/* We do not want to expose passwords in our database, so hash the
password and use password_verify when a user logs in.
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt->bind_param('sss', $_POST['$username'], $password,
$_POST['$companyName']);
$stmt->execute();*/
$sql = 'INSERT INTO phplogin (username, password, companyName )
VALUES ($username, $password, $companyName)';
echo 'You have successfully registered, you can now login!';
echo (" ".$password." ".$username." ".$companyName);
echo ' well done';
} else {
/* Something is wrong with the sql statement, check to make sure accounts table exists with all 3 fields.*/
echo 'Could not prepare the new statement!';
print_r ($_POST);
}
}
}
$con->close();
?>
//$sql = 'INSERT INTO phplogin (username, password, companyName ) VALUES ($_POST[username], $password, $_POST[companyName])';
PHP thinks it should execute VALUES even though it is not any proper action. Use /* THIS IS COMMENT */ because it prevents stuff like this happening.
Also as a side note: Do not assign values in if statement. You can assign $stmt on its own line and just check
If($stmt === true) {}
Or
If($stmt !== true) {}
You get the point.
Also another side note is that you should prefer using PDO. It is alot of easier to handle and understand because of ts syntax and it makes OOP much much more easier. Mysqli is ok to use, but i personally do not recommend using it.
I'm trying to create a simple login using mySQLi with PHP. I have everything set up using a variable $username and $password that holds the login information rather than using post from a form as I just want to get it working first before advancing to this and injection protection. So all in all if the variables match the table in the data base then it prints Logged In! otherwise it'll print Invalid username or password but every time I run this I get an error:
Error:
Warning: mysqli_query() expects parameter 1 to be mysqli, null given
<?
$dbhost = 'localhost';
$dbuser = 'xxxx';
$dbpass = 'xxxx';
$dbname = 'xxxx';
$con = mysqli_connect($dbhost, $dbuser, $dbpass,$dbname);
$sql="SELECT email, pass FROM lg_user";
$username = 'Admin';
$password = "123qweQWE";
$query = "SELECT `user` FROM `lg_user` WHERE `user`='$username' AND `pass`='$password'";
var_dump($query);
if($query_run = mysqli_query($conn,$query)){
$query_num_rows = mysqli_num_rows($query_run);
if($query_num_rows == 0){
print("Invalid username or password");
}
else if($query_num_rows == 1){
print("Logged In!");
}
}
?>
Just to make my point that doing it the right way is not over complicated here you go.
$dbhost = 'localhost';
$dbuser = 'xxxx';
$dbpass = 'xxxx';
$dbname = 'xxxx';
$Pdo = new PDO("mysql:host={$dbhost};dbname={$dbname};charset=utf8", $dbuser, $dbpass);
$Pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$Pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$Pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$username = 'Admin';
$password = "123qweQWE"; //create a password with password_hash($password, PASSWORD_DEFAULT);
$stmt = $Pdo->prepare("SELECT `user`,`pass` FROM `lg_user` WHERE `user`=:username"); //don't pull user by looking for the password.
$stmt->execute([':username' => $username]);
if($stmt->rowCount() == 1){
$row = $stmt->fetch();
if(password_verify($password, $row['pass'])){
//verify does not require hashing the incoming password (assuming password was made with password_hash)
print("Logged In!");
}else{
print("Invalid password");
}
}else{
print("Invalid username");
}
23 lines, 3 of which are optional ($Pdo->setAttribute). The original attempt 17 lines.
Both of these have at least 2 extra lines in (username/password canned data). So for 6 extra lines (3 of which are optional) We can do this the right way. Coincidentally the other 3 lines are here (separate error for password/username):
}else{
print("Invalid password");
}
So pretty much the same number of lines.
Major notes,
Do not check password by querying it.
Hashes are case sensitive, DB typically is not (unless you use UTF8_bin).
It's not a cryptologically secure evaluation of the hash
You can't tell if it's a bad password or a bad username
Use prepared statements.
Use PHP's built in password functions
Use PDO,
the OOP API for PDO is better
the fetch modes are far better than mysqli
the error handling is far better (with exception mode)
all this saves a lot of work in the long run (my opinion).
References:
http://php.net/manual/en/function.password-verify.php
http://php.net/manual/en/function.password-hash.php
http://php.net/manual/en/class.pdo.php
I would also strongly recommend making the username a unique index in the Database itself. This will give you 100% guarantee that usernames cannot be duplicated. It will also throw an exception with PDO, which is very easy to catch and report.
I've been having a bit of trouble with my PHP code.
I'm trying to insert a new row in table gebruikers.
I'm using a JSON API to post the data from my C# Android app to the server.
running the code returns an invalid request error.
PHP:
function registerUser($api_data)
{
// connection
$servername = "xxx";
$username = "xxx";
$password = "xxx";
$database = "test";
$mysqli = new mysqli($servername, $username, $password, $database);
//check connection
if(mysqli_connect_errno())
{
API_Response(true, 'connection error');
}
$register_data = json_decode($api_data);
$leerlingnummer = intval($register_data->leerlingnummer); //passed as string, int in database
$wachtwoord = $register_data->wachtwoord; //string
$email = $register_data->email; //string
$result = $mysqli->query("INSERT INTO `gebruikers` (`Leerlingnummer`, `Wachtwoord`, `Email`) VALUES ({$leerlingnummer}, {$wachtwoord}, {$email})");
if ($result == false)
{
API_Response(true, "{$mysqli->error}");
}
else
{
API_Response(false, 'SUCCESS');
}
$mysqli->close();
}
database is looking as follows:
database layout
I've never felt this stupid before, but the error came from the fact that I was still referencing to an older .php file. I was so focussed on the PHP script that I didn't notice this error in my app before.
the quotes advised by Sean and fuso were needed later on though so thanks for that.
Problem solved, sorry for wasting some of your time :/
You should quote your data in the insert query.
... VALUES ('{$email}','{$other}')
I have setup a basic table and connected a PHP file with the database. I can fetch data from the database by using SELECT. However, when I try to use UPDATE or INSERT INTO, I get the message:
"INSERT command denied to user ''#'localhost' for table 'table_data'".
When I try to use the query in PMA, i am able to insert data. But when i want to adjust user rights, it says i don't have the rights to do so. But when i use the SQL SHOW GRANTS, i receive:
"Grants for xxx#10.0.% GRANT USAGE ON . TO 'xxxl'#'10.0.%'
IDENTIFIED BY PASSWORD GRANT ALL PRIVILEGES ON
'database_name'.* TO 'xxx'#'10.0.%' WITH GRANT OPTION.
I am using the only MySQL account provided by my host so I assume it is the root user.
$servername = "mysql.domain_name.nl";
$username = 'xxx';
$password = 'xxx';
$conn = new mysqli($servername, $username, $password);`
$username = $_POST['username'];
$password = $_POST['password'];
$query = "INSERT INTO 'game'.'login_data' ('username', 'password') VALUES ('".$username."', '".$password."')";
$data = mysql_query ($query)or die(mysql_error());
Please help me to gain rights to be able to INSERT.
First you need to read up on using mysqli. Everything you need is here: http://php.net/manual/en/book.mysqli.php
You will see that you are missing 1 parameter from your $conn
Needs to be new mysqli('localhost', 'my_user', 'my_password', 'my_db');
$servername = "mysql.domain_name.nl";
$username = 'xxx';
$password = 'xxx';
$conn = new mysqli($servername, $username, $password, **add database**);
$username = $_POST['username'];
$password = $_POST['password'];
For the sake of security you want to use prepared statements.
Change it to the following:
if ($stmt = $conn->prepare("INSERT INTO `game`.`login_data` (username, password) VALUES (?, ?)")) {
$stmt->bind_param('ss', $username , $password );
// Execute the prepared query.
if (! $stmt->execute()) {
$stmt->close();
}
}
}
Of course this is not the way you should completely treat a user database. You want to be hashing passwords, storing salts etc. But for this question. The above should be enough.
I have tidied up your code, fixed the syntax errors, as well as switched the entire code to PDO.
MySQL is deprecated and MySQLi is open to SQL injection hacks, even with mysqli_real_escape_string!
<?php
$user = 'xxx';
$pass = 'xxx';
$conn = new PDO('mysql:host=localhost;dbname=mysql.domain_name.nl', $user, $pass);
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $conn->prepare("INSERT INTO `game`.`login_data` ('username', 'password') VALUES (:username, :password)");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();
?>
For more information on PDO, consult the manual here: http://php.net/manual/en/book.pdo.php
Somehow my conditional simply doesnt work. Once I click the button on my login form which is set to "post" and has the action defined as the below login script I only get directed to the script but not redirected as defined in my conditional statement. What is wrong with my code?
session_start();
$servername = "localhost";
$username = "root";
$password = "";
$database = "project";
$connection = mysqli_connect($servername, $username, $password, $database) or exit(header("location:maintenance.php"));
function login_check() {
global $connection;
$name = $_POST['name'];
$password = $_POST['password'];
$prepared = mysqli_stmt_init($connection);
$request = mysqli_stmt_prepare($prepared, "SELECT id FROM members WHERE name = ? AND password = ?");
mysqli_stmt_bind_param($prepared, "ss", $name, $password);
$result= mysqli_stmt_bind_result($request);
$rows_counter = mysqli_num_rows($result);
mysqli_stmt_close($prepared);
if ($rows_counter > 0) {
$_SESSION['member'] = $name;
header("location:../../success.php");
}
else {
header("location:../../relogin.php");
}
}
Here is my input and approach to your code.
First of all before writing a solution and tell to much, it is always a good practice to make step by step code troubleshooting.
Before going and building a complete login system and put if statement or make prepare statement with inputs etc.
Make your solution in small working chops and put the puzzle together.
You question was focused on if statement and most of the help and answer was also focused on if statement which is nice, but the problem was not there.
I removed the if statement and a lot and just focused to see if I get some thing returned, I did not.
You $result= mysqli_stmt_bind_result($request); missed arguments, when that fixed, the next line missed also something else. I already there quit debugging.
I have rewrite your code and it works, what I did I have redefined the naming of variable so they are crystal clear to understand what is name, call it username, database username call it dbUser or dbUsername etc.
And if you want to check your code returning some thing or not, use var_dump($someVariable).
Last thing, before making a post form, you could create a dummy username and password in your database and inject that directly in your code like, just to see if every thing is working, and then move to your form:
$username = "user1";
$password = "1234";
The solution I did is just to demonstrate how to do it and not necessarily representation of the best logic, but it is up to you to find the correct logic and all depends on your strategy.
Here is my suggestion:
<?php
session_start();
$dbHost = "localhost";
$dbUser = "root";
$dbPass = "";
$dbName = "product";
$connection = new mysqli($dbHost, $dbUser, $dbPass, $dbName);
// Check connection
if ($connection->connect_error)
{
header("location:maintenance.php");
exit();
// or for debugging, activate following line
//die("Connection failed: " . $connection->connect_error);
}
$username = $_POST['username'];
$password = $_POST['password'];
//if username and password empty stop login
if (!$username || !$password)
{
//do something, die is only example
die ("Not all the fields were filled in");
} else
{
login_check($username, $password);
}
function login_check($username, $password)
{
global $connection;
//sql statements is corrected, change field name to username
$sql = "SELECT * FROM `members` WHERE `username` = ? AND `password` = ?";
$stmt = $connection->prepare($sql);
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$output = $stmt->get_result();
$row = $output->fetch_array(MYSQLI_NUM);
$stmt->close();
//print what comes out in $row
//print_r($row);
//check if $row has data
if ($row)
{
echo "success do something";
$_SESSION['member'] = $username;
} else
{
echo "fail do something";
}
}
After defining the function login_check(), you should also call it (if the conditions are right):
function login_check() {
// your implementation as above
}
if (isset($_POST['name']) && isset($_POST['password'])) {
login_check(); // actually call the function
}
As a side note, it is good practice to also explicetely close the connection before redirecting.
Edit
as KhomeHoly comments, only call the function when necessary...
You need to call your functions if you define them. Not doing so is like building a room within a new house but forgetting the door. It's there, but nobody can use or access it.
So what you need to do is the following:
// your script as it is right now
if (isset($_POST['name']) && isset($_POST['password'])) {
login_check(); // actually call the function
}
With isset() you check if the certain $_POST parameters are set, but not validated. You should at least do a basic validation of the data to see if they are correct!
Something like this would work, depends on your requirements
if (isset($_POST['name']) && strlen($_POST['name') >= 4 && isset($_POST['password']) && strlen($_POST['password']) >= 4) {
login_check(); // actually call the function
}
The code above would check if those paramters are set and check if name and password are at least 4 characters long. (I wouldn't accept usernames lower than 4 chars personally, passwords should be at least 8 for me)
Now of course this misses an correct error reporting and all that stuff, but I think that should give you the basic idea based on your quesiton.
Always, always, always put exit() after header redirect call. Even in that case, it might solve your issue.
header("location:../../success.php");
exit();
Why?