Unable to method chaining in MySQLi prepared statement using PHP - php

I am a beginner to PHP. I tried not to put $conn->prepare($sql_stmt) in one variable and just applied method chaining. But I got "Error while executing".
<?php
include_once 'dbh.inc.php';
if(isset($_POST['submit_btn']))
{
$fullname = $_POST['name'];
$username = $_POST['username'];
$password = $_POST['password'];
$sql_stmt = "INSERT INTO signup (name, username, passwrd) VALUES (?,?,?);";
//prepare and bind
$conn->prepare($sql_stmt)->bind_param("sss", $fullname, $username, $password);
//execute
if($conn->prepare($sql_stmt)->execute())
{
echo "User created";
}
else
{
echo "Error while executing";
}
}
else
{
echo "Unable to sign up.";
}
However if I instantiate $sql = $conn->prepare($sql_stmt) like below
<?php
include_once 'dbh.inc.php';
if(isset($_POST['submit_btn']))
{
$fullname = $_POST['name'];
$username = $_POST['username'];
$password = $_POST['password'];
$sql_stmt = "INSERT INTO signup (name, username, passwrd) VALUES (?,?,?);";
//prepare and bind
$sql = $conn->prepare($sql_stmt);
$sql->bind_param("sss", $fullname, $username, $password);
//execute
if($sql->execute())
{
echo "User created";
}
else
{
echo "Error while executing";
}
}
else
{
echo "Unable to sign up.";
}
It works and returns "User created". Why is that so?

Method chaining is not possible with mysqli. The return value of bind_param() is a boolean. It does not return self. You must call the methods like you showed in the second example:
$sql = $conn->prepare($sql_stmt);
$sql->bind_param("sss", $fullname, $username, $password);
$sql->execute();
In fact, mysqli is not very suitable to be used on its own in your application. If you want something simpler, then use PDO. If for some strange reason you must use mysqli, then you require some kind of abstraction layer that will prevent you from dealing with mysqli functions directly.
As of PHP 8.1, you can pass parameters directly in mysqli_stmt::execute(), which enables you to do method chaining in one line:
$sql = $conn->prepare($sql_stmt)->execute([$fullname, $username, $password]);
Also, please stop checking the return value of execute. You should enable mysqli error reporting instead. How to get the error message in MySQLi?

Related

PHP inserting with bind_param

I am currently working trying to use the statements mysqli_prepare and bind_param in order to pass arguements more safely into my query. I was doing mysqli_query to execute them before which worked fine. My professor is requiring us to use prepare though. I currently am getting the proper values from my form but the data isn't being entered into customer table. Also, I have mysqli_error() on my execute() commands but I am not getting any errors at all which is making debugging difficult. Here is the php part located in register.php
<?php
require 'connection.php';
$result = "";
if(isset($_POST['register'])) {
#Fetch the data from the fields
$username = $_POST['username'];
$password = $_POST['password'];
$name = $_POST['name'];
$total = 0.0;
#echo $username . " " . $password . " " . $name . " " . $total;
#Prepare sql query to see if account already exists
$query = mysqli_prepare("SELECT * FROM customer WHERE username=?");
$query->bind_param("s", $username);
$query->execute() or die(mysqli_error());
if(mysqli_num_rows($query) > 0) {
#This username already exists in db
$result = "Username already exists";
} else {
$insert = mysqli_prepare("INSERT INTO customer(username, password, name, total) VALUES (?, ?, ?, ?)");
$insert->bind_param("sssd", $username, $password, $name, $total);
$insert->execute() or die(mysqli_error());
#$result = "Account registered!"
}
}
?>
I establish connection to my db like this in connection.php
$conn = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
Like I said before, I can get the query to execute with mysqli_query but for some reason I cannot get param to work. Also tried adding or die but no errors are being printed

PDO Username validation if already exists

I have a problem with register form.My form works properly but whenever i try to insert username that already exists it doesn't shows any error.
here is my php register file:
<?php
$servername = "localhost";
$username = "root";
$password = "";
try {
$conn = new PDO("mysql:host=$servername;dbname=dblogin", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if (isset($_POST['submit'])) {
$user_name = $_POST['user_name'];
$user_email = $_POST['user_email'];
$user_pass = $_POST['user_pass'];
$hash = password_hash($user_pass, PASSWORD_DEFAULT);
$stmt = $con->prepare("SELECT user_name FROM users WHERE user_name = :user_name");
if($stmt->rowCount() > 0){
echo "exists!";
}
else{
$insert = $conn->prepare("INSERT INTO users (user_name,user_email,user_pass) values(:user_name,:user_email,:user_pass)");
$insert->bindparam(':user_name',$user_name);
$insert->bindparam(':user_email',$user_email);
$insert->bindparam(':user_pass',$hash);
$insert->execute();
}
}
catch(PDOException $e)
{
echo "connection failed";
}
?>
Thanks for your support
You are not executing the select statement. You need to bind params and execute the select statement, try this after the select statemnt.
$stmt->bindparam(':user_name',$user_name);
$stmt->execute();
public function usernameCheck($username)
{
$sql = "SELECT * FROM $this->table where username = :username";
$query = $this->pdo->prepare($sql);
$query->bindValue(':username', $username);
$query->execute();
if ($query->rowCount() > 0) {
return true;
} else {
return false;
}
}
use this one in your project hope it will work... :)
missing } in if statement
if (isset($_POST['submit'])) {
$user_name = $_POST['user_name'];
$user_email = $_POST['user_email'];
$user_pass = $_POST['user_pass'];
$hash = password_hash($user_pass, PASSWORD_DEFAULT);
$stmt = $con->prepare("SELECT user_name FROM users WHERE user_name = :user_name");
if($stmt->rowCount() > 0){
echo "exists!";
}
}else{
}
I notice 4 things (2 of which have been mentioned by others):
First and smallest is you have a spelling error ($con instead of $conn) - don't worry it happens to the best of us - in you first $stmt query which means your select-results becomes NULL instead of 0 - so you rowCount find that it is not over 0 and moves on without your error message
Second you forgot to bind and execute the parameters in your first $stmt query which gives the same result for your rowCount results
Third always clean your variables even when using prepared statements - at a bare minimum use
$conn->mysql_real_escape_string($variable);
and you can with advantage use
htmlspecialchars($variable);
And fourth since you are not doing anything with the database (other than looking) you could simplify your code by simply writing:
$stmt = $conn->query("SELECT user_name FROM users WHERE user_name = '$user_name' LIMIT 1")->fetch();
as I said - no need to bind or execute in the first query
and as a general rule - don't use rowCount - ever - if you have to know the number of results (and in 99% of cases you don't) use count(); but if you as here just want to know if anything at all was found instead use:
if ( $stmt ) {
echo "exists!";
} else {
// insert new user as you did
}
Edit:
Also - as a side note - there are a few things you should consider when you initially create your connection...
Ex:
// Set variables
$servername = "localhost";
$username = "***";
$password = "***";
$database = "***";
$charset = 'utf8'; // It is always a good idea to also set the character-set
// Always create the connection before you create the new PDO
$dsn = "mysql:host=$servername;dbname=$database;charset=$charset";
// Set default handlings as you create the new PDO instead of after
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // And add default fetch_mode
PDO::ATTR_EMULATE_PREPARES => false, // And ALWAYS set emulate_prepares to false
];
// And now you are ready to create your new PDO
$conn = new PDO($dsn, $username, $password, $opt);
Just a suggestion... happy trails

PHP not posting onto mySQL database

This code should check for existing usernames and if there isn't one, it should create a new one. No matter what it won't add. Additionally, as you can see in the code it only echoes 'here' and doesn't echo 'not here'.
<?php
$password = "hey";
$username = "hi";
require "conn.php";
//$password = $_POST["password"];
//$username = $_POST["username"];
echo 'here';
$result = $conn->query("SELECT * FROM UserData WHERE username ='$username' ", MYSQLI_USE_RESULT);
echo 'not here';
if ($result) {
if($result->num_rows === 0)
{
$stmt = $conn->prepare("INSERT INTO UserData (username,password) VALUES (:username,:password)");
$params = array(
':username' => $username,
':password' => $password
);
$stmt->execute($params);
}
}
?>
This is the connection code:
<?php
//$db_name = "xxx";
//$mysql_username = "xxx";
//$mysql_password = "xxx";
//$server_name = "xxx";
// Create connection
$conn = new mysqli("xxx","xxx","xxx","xxx");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
?>
Changes:
<?php
require "conn.php";
echo "debug 1";
$stmt = $conn->prepare("SELECT * FROM UserData WHERE username = ?");
$stmt->bind_param('s', /*$_POST["username"]*/ $username );
$username = 'hi';
$stmt->execute();
$stmt->store_result();
echo "debug 2";
if ($stmt->num_rows == 0){ // username not taken
echo "debug 3";
$stmt2 = $conn->prepare("INSERT INTO UserData (username, password) VALUES (?, ?)");
$password =(/*$_POST["password"]*/ "hey");
$username =(/* $_POST["username"]*/ "hi");
$stmt2->bind_param('s',$username);
$stmt2->bind_param('s',$password);
$stmt2->execute();
if ($stmt2->affected_rows == 1){
echo 'Insert was successful.';
}else{ echo 'Insert failed.';
var_dump($stmt2);
}
}else{ echo 'That username exists already.';}
?>
This code gets through all of the debugs but for some reason, it is still not inserting.
Replace this line
$result = **$mysqli->**query("SELECT * FROM UserData WHERE username ='$username' ", MYSQLI_USE_RESULT);
with following
$result = **$conn->**query("SELECT * FROM UserData WHERE username ='$username' ", MYSQLI_USE_RESULT);
The mysqli and PDO interfaces must not be mixed. Here the database connection and the SELECT query are both using the mysqli interface. But the second INSERT query is attempting to use the PDO interface, as evidenced by the use of named placeholders, and also the passing of a data array directly to execute(). The latter two features are not supported by mysqli, hence the code fails at the second query. Also, note that the second query is using prepared statements, while the first one is not. Again, different approaches should not be mixed together.
Also it appears that passwords are being stored as plain text, with no security. The proper approach is to use the password_hash function.
Just ensure that the database field has enough width (say 80-120 characters or more) to handle the current bcrypt hash, plus allow some more for future changes.
Staying with the mysqli interface (and with password_hash), the code could go something like this:
$stmt = $conn->prepare("SELECT * FROM UserData WHERE username = ?");
$stmt->bind_param('s', $_POST["username"]);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 0){ // username not taken
$stmt2 = $conn->prepare("INSERT INTO UserData (username, password) VALUES (?, ?)");
$password = password_hash($_POST["password"], PASSWORD_DEFAULT);
$stmt2->bind_param('s', $_POST["username"]);
$stmt2->bind_param('s', $password);
$stmt2->execute();
if ($stmt2->affected_rows == 1)
echo 'Insert was successful.';
else echo 'Insert failed.';
}
else echo 'That username exists already.';
Note that the above approach would not be suitable for a high-traffic site, where there is a chance condition of another user trying to INSERT the same username, during the brief interval of time between the SELECT and INSERT database queries. That would require a different approach, like ensuring the subject database field is set to UNIQUE (which is good practice anyway), and then testing for violation of that UNIQUE field upon attempted duplicate insertion.
Assuming database and INSERT permissions are all set up OK and it is still not inserting, try enhancing the error-reporting.
Ensure the following are at the top of the page:
ini_set('display_errors', true);
error_reporting(E_ALL);
And put the following before the first query:
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ALL;
Then try again.

PHP bindParam not working - blindValue is not the solution

I can't figure this out. I've googled it and a lot of answers refer to blindValue as the solution but I've also tried that with no luck.
The problem is that the SELECT statement is returning zero records but it should return one record. If I hard code the values into the SQL statement it works but passing them in as parameters isn't. Can some one please help me out with this? Thanks.
<?php
function checklogin($email, $password){
try
{
// Connection
$conn;
include_once('connect.php');
// Build Query
$sql = 'SELECT pkUserID, Email, Password, fkUserGroupID FROM tbluser WHERE Email = :email AND Password = :password';
// $sql = 'SELECT pkUserID, Email, Password, fkUserGroupID FROM tbluser WHERE Email = "a" AND Password = "a"';
// Prepare the SQL statement.
$stmt = $conn->prepare($sql);
// Add the value to the SQL statement
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':password', $password, PDO::PARAM_STR);
// Execute SQL
$stmt->execute();
// Get the data in the result object
$result = $stmt->fetchAll(); // $result is NULL always...
// echo $stmt->rowCount(); // rowCount is always ZERO....
// Check that we have some data
if ($result != null)
{
// Start session
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Search the results
foreach($result as $row){
// Set global environment variables with the key fields required
$_SESSION['UserID'] = $row['pkUserID'];
$_SESSION['Email'] = $row['Email'];
}
echo 'yippee';
// Return empty string
return '';
}
else {
// Failed login
return 'Login unsuccessful!';
}
$conn = null;
}
catch (PDOexception $e)
{
return 'Login failed: ' . $e->getMessage();
}
}
?>
the connect code is;
<?php
$servername = 'localhost';
$username = 'admin';
$password = 'password';
try {
// Change this line to connect to different database
// Also enable the extension in the php.ini for new database engine.
$conn = new PDO('mysql:host=localhost;dbname=database', $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// echo 'Connected successfully';
}
catch(PDOException $e)
{
echo 'Connection failed: ' . $e->getMessage();
}
?>
I'm connecting to mySQL. Thanks for the help,
Jim
It was a simple but stupid error.
I had a variable called $password also in the connect.php file which was overwriting the $password that I was passing to the checklogin.
Jim

Error that will not show itself

I'm trying to code a registration system for a system I am making. Currently, I am receiving a MySQL error that makes me want to tear my head out each and every time I see it.
function UserRegister($user,$pass,$email,$first,$last)
{
$sqlfirst = mysql_real_escape_string($first);
$sqllast = mysql_real_escape_string($last);
$sqluser = mysql_real_escape_string($user);
$hashpass = crypt($pass);
$sqlpass = mysql_real_escape_string($hashpass);
$sqlemail = mysql_real_escape_string($email);
$sql = "SELECT *
FROM planerentalusers
WHERE user = '$sqluser' ";
if($result = mysqli_query($GLOBALS['db'],$sql))
{
$rowcount=mysqli_num_rows($result);
if($rowcount == 1)
{
echo "ERROR: There is already an account with that username! Click <a href='/PHPCalTest/login.php>here </a>to login if this is you. Otherwise, go back and try a different username.";
}
else
{
$sql2 = "INSERT INTO planerentalusers (first,last,user,pass,email) VALUES ('$sqlfirst','$sqllast','$sqluser','$sqlpass','$sqlemail')";
$result2 = mysqli_query($GLOBALS['db'],$sql);
if($result2 == true)
{
return true;
}
else return false;
}
}
else return false;
mysqli_free_result($result);
}
Above is the function that throws the error.
there is no PHP stack trace that is being thrown, so here is what I pinpointed it to: the query is failing. But how, I do not understand. Perhaps someone can point me in the right direction.
That is not a direct answer to your question. It has been solved somewhere between the comment lines.
Now, you can streamline and secure your code if you will:
use prepared statements. It's only natural since you are already using mysqli_* extension. Parameters that you pass to the prepared INSERT statement will be properly escaped.
utilize INSERT IGNORE syntax and check for affected rows with affected_rows. That way you do all you need to do hitting your database only once.
For INSERT IGNORE to work properly you have to have a UNIQUE constraint on username column.
ALTER TABLE planerentalusers ADD UNIQUE (username);
Now if you issue an INSERT IGNORE statement and a username doesn't exist a row will be inserted and affected_rows will return 1. If a username already exists then IGNORE clause will allow your INSERT statement to complete without throwing an error and affected_rows will return 0.
That being said an improved version of your function might look like
function UserRegister($db, $username, $pass, $email, $first, $last) {
$sql = "INSERT IGNORE INTO planerentalusers (first, last, username, pass, email) VALUES (?, ?, ?, ?, ?)";
// prepare the statement
$stmt = $db->prepare($sql);
if (!$stmt) {
die('Can\'t prepare: ' . $db->error); //TODO better error handling
}
// bind parameters
$stmt->bind_param('sssss', $first, $last, $username, $pass, $email);
if (!$stmt) {
die('Can\'t bind parameters: ' . $db->error); //TODO better error handling
}
// execute
$stmt->execute();
if (!$stmt) {
die('Query execution failed: ' . $db->error); //TODO better error handling
}
// get the number of affected rows
$affected_rows = $stmt->affected_rows;
// close the statement
$stmt->close();
return $affected_rows;
}
and the calling code
$first = $_POST['first'];
$last = $_POST['last'];
$username = $_POST['username'];
$pass = crypt($_POST['pass']);
$email = $_POST['email'];
//create a connection to the database
$db = new mysqli('localhost', 'user', 'password', 'dbname');
if ($db->connect_errno) {
die('Connection failed: ' . $db->connect_error); //TODO better error handling
}
if (!UserRegister($db, $username, $pass, $email, $first, $last)) {
echo "ERROR: There is already an account with that username! Click <a href='/PHPCalTest/login.php'>here </a>to login if this is you. Otherwise, go back and try a different username.";
} else {
echo "Account successfully created";
}
Note that
A reference to an open db connection is explicitly passed to the function instead of using $_GLOBALS['db']
presentation logic (echoing an error message and a link) is moved out to the calling code
Basic error handling is implemented throughout the function

Categories