I'm new to PHP and I'm trying to get a prepared statement to work. Its for my final year project at university and I remember reading that prepared statements are good practice and also good for SQL injections. However the following code gives me a Server 500 error.
<?php
$email = "blah#blah.co.uk";
$hash = "somerandomhashedpassword";
$db = new mysqli("localhost", "root", "1234", "UEAnetwork");
$sql = "INSERT INTO Students (Email, Password) VALUES (?,?)";
$stmt = $db->prepare($sql);
$stmt->bindValue(1, $email);
$stmt->bindValue(2, $hash);
if ($stmt->execute()) {
echo "You have registered!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
}
?>
If I run the following then a row is inserted, so I'm pretty sure I'm connecting to the database properly.
<?php
$db = new mysqli("localhost", "root", "1234", "UEAnetwork");
$sql = "INSERT INTO Students (Email, Password) VALUES ('blah#blah.co.uk','somerandomhashedpassword')";
$stmt = $db->prepare($sql);
if ($stmt->execute()) {
echo "You have registered!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
}
?>
Am I using bindValue incorrectly? I've seen it used this way in many tutorials online but I must be doing something wrong.
mysqli has a very different API than PDO. There is no mysql_stmt::bindValue. You want to use mysql_stmt::bind_param, but the syntax is quite different:
$stmt->bind_param('ss', $email, $hash);
Related
This question already has an answer here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(1 answer)
Closed 3 years ago.
My php code for registration does not insert values to the database. I tried different ways but it is still not working. Here is the code:
Database connection:
<?php $link=mysqli_connect("localhost", "root", "");
mysqli_select_db($link, "dataadventurers");
?>
My registration form PHP code:
<?php
include "connection.php"; ?>
<?php
if(isset($_POST['submit1'])){
$firstname = $_POST['first_name'];
$lastname = $_POST['last_name'];
$middle = $_POST['middle_initial'];
$idnum = $_POST['id_number'];
$email = $_POST['email_add'];
$pass = $_POST['password'];
$bday = $_POST['birthdate'];
$course = $_POST['course'];
$year = $_POST['year'];
mysqli_query($link, "insert into member_registration values('', '$firstname', '$lastname'
, '$middle', '$idnum', '$email', '$pass', '$bday', '$course', '$year')");
?>
Welcome to StackOverflow.
First of all, your code is vulnerable to SQL Injection. This is a major flaw but thankfully, one that's easily fixed. It is important that you do not leave this open to SQL Injection, even if this is something just for you to use. It'll keep your data safe in the event that someone else manages to access it and also gets you in to good habits.
Secondly, your code isn't working because you haven't specified what columns you want to insert into.
Using your example as a basis, here's a working version.
DO NOT USE THIS, IT IS VULNERABLE CODE
<?php
$link=mysqli_connect("localhost", "root", "");
mysqli_select_db($link, "dataadventurers");
?>
<?php
include "connection.php";
?>
<?php
if(isset($_POST['submit1'])){
$firstname = $_POST['first_name'];
$lastname = $_POST['last_name'];
$middle = $_POST['middle_initial'];
$idnum = $_POST['id_number'];
$email = $_POST['email_add'];
$pass = $_POST['password'];
$bday = $_POST['birthdate'];
$course = $_POST['course'];
$year = $_POST['year'];
//If someone passes 2019'); drop table member_registration; -- for example as the year parameter, MySQL interprets the query string as two separate queries. One to insert a record and the second to drop the table and will execute both
mysqli_query($link, "insert into member_registration (firstname, lastname, middle, idnum, email, pass, bday, course, year) values( '$firstname', '$lastname', '$middle', '$idnum', '$email', '$pass', '$bday', '$course', '$year')");;
}
?>
A MORE SECURE VARIANT
I have a couple of SQL convenience functions based on PDO I use on a regular basis.
They pick up their credentials from an ini file stored outside of the publicly accessible folder structure.
The GetData procedure returns the results in the form of an associative array
UpdateData returns the amount of rows affected.
Ini file example
host=localhost
dbname=dataadventurers
username=user
password=pass
Convenience Functions
/*Put credential ini file path here*/
$credentialFile = "...";
function GetData($sql, $params = null, $paramtypes = null){
//Get database connection details
$credentialsArray = parse_ini_file($credentialFile);
//Create PDO Instance
$db = new PDO('mysql:host='.$credentialsArray['host'].';dbname='.$credentialsArray['dbname'].';charset=utf8mb4', $credentialsArray['username'], $credentialsArray['password'], array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
if(is_null($params)){ //If no parameters supplied, execute the query as is
$stmt = $db->query($sql);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
else{
if(count($params) <> count($paramtypes)){ //Check that the parameter count and type count are the same
throw new InvalidArgumentException;
}
$stmt = $db->prepare($sql); //Prepare the statement
for($i=0; $i<count($params); $i++){ //Bind the parameters
$stmt->bindValue($i+1, $params[$i], $paramtypes[$i]);
}
$stmt->execute(); //Execute query
$results = $stmt->fetchAll(PDO::FETCH_ASSOC); //Return the results as an associative array
}
return $results;
}
function UpdateData($sql, $params){
//Get database connection details
$credentialsArray = parse_ini_file($credentialFile);
//Create PDO Instance
$db = new PDO('mysql:host='.$credentialsArray['host'].';dbname='.$credentialsArray['dbname'].';charset=utf8mb4', $credentialsArray['username'], $credentialsArray['password'], array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
try{
$stmt = $db->prepare($sql); //Prepare the statement
is_null($params){ //If there aren't any parameters to bind...
$stmt->execute(); //...execute statement as is
}
else{
$stmt->execute($params); //otherwise execute with the supplied parameters
}
$results = $stmt->rowCount(); //Return the rowcount
return $results;
}
catch(PDOException $ex){ //Catch any PDO Exceptions
return $ex->getMessage(); //Return the exception message
}
}
Usage
The usage is simple. When selecting data, pass a SQL string, an array containing any parameters and an array containing the parameter types. These arrays must be of the same length.
When updating/inserting/deleting data, pass a SQL string and an array containing the parameters. There is no parameter type requirement for UpdateData.
//GetData with no parameters
$results = GetData('select * from member_registration', [], []);
//GetData with one parameter of type String.
$results2 = GetData('select * from member_registration where firstname = ?', ['David'], [PDO::PARAM_STR]);
//Your insert example
$parameters = [
$firstname,
$lastname,
$middle,
$idnum,
$email,
$pass,
$bday,
$course,
$year
];
$rowsAffected = UpdateData('insert into member_registration (firstname, lastname, middle, idnum, email, pass, bday, course, year) values(?, ?, ?, ?, ?, ?, ?, ?, ?)', $parameters);
Final Thoughts
You'll need to substitute the column names for the fields you have in your database. If any are auto-generated, such as an auto-incrementing ID field, omit that field so it works correctly.
One of your parameters is called $pass. If you're storing passwords in a database, ALWAYS store them in an encrypted form, preferably using bCrypt. This StackOverflow answer explains why/how.
I am very new to PHP and MySQL. I have the following code that works but now I need to incorporate prepared statements into. I have tried many things but with no luck.
The following is the original PHP code:
$sql = "SELECT name, address, city, phone, id FROM Lab7 WHERE name = '$name' ";
mysql_select_db('muftih_Registration');
$retval = mysql_query( $sql, $conn );
This is my attempt that did not work:
$sql = "SELECT name, address, city, phone, id FROM Lab7 WHERE name = ?";
$sql->bindParam('s', $name);
mysql_select_db('muftih_Registration');
$retval = mysql_query( $sql, $conn );
I keep getting:
Fatal error: Call to a member function bindParam() on a non-object
The mysql_ family does not support prepared statements, you'll need to migrate to mysqli_ which is a different driver library. Furthermore, you cannot mix mysql_ and mysqli_ libraries together.
Lastly, mysql_ has been deprecated for several years now, and has been removed in php 7.
Synopsis: do not use mysql_.
You need to use mysqli on order to use prepared.
Let me show an example.
$mysqli = new mysqli('localhost', 'username', 'password', 'database');
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
if ($stmt = $mysqli->prepare("SELECT name, address, city, phone, id FROM Lab7 WHERE name = ?")) {
$stmt->bind_param("s", $name);
$stmt->execute();
$stmt->bind_result($name, $address, $city, $phone, $id);
$stmt->fetch();
echo "$name, $address, $city, $phone, $id"; // Print the retrieved row
$stmt->close();
}
Hope this helps.
Peace! xD
I am trying to run an sql query using PDO prepared statements
$sql = "INSERT INTO tickets (ticketnumber, status) VALUES (1234, Open) ";
$stmt = $connection->prepare($sql);
$stmt->execute();
But it is just not inserting. What have I done wrong?
Here is my connection:
$host = "localhost";
$db_name = "";
$username = "";
$password = "";
$connection = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
Try this. It's much more secure.
Make sure you have included your connection file.
EDITED
$sql = "INSERT INTO `tickets` (ticketnumber, status) VALUES (:ticketnumber, :status)";
$stmt = $connection->prepare($sql);
$stmt->bindValue(':ticketnumber', 1234, PDO::PARAM_INT);
$stmt->bindValue(':status', 'Open', PDO::PARAM_STR);
$stmt->execute();
Also, the named parameters used above must NOT be enclosed in quotes. If you do so, it'll be treated as a literal string and not a named parameter.
You need to use quotes on strings before inserting them into a database.
Why use prepare if you're not preparing your data before sending it to the database?
I've been using mysql and mysqli in the past, but am starting a new project, so wanted to go back to OOP with PDO-mysql .. however, it doesn't want to work:
$dbh = new PDO('mysql:host='.$host.';dbname='.$database, $username, $password);
if(isset($_POST["name"]) && isset($_POST["password"]))
{
$pwdHasher = new PasswordHash(8, FALSE);
$hash = $pwdHasher->HashPassword($_POST["password"]);
//$insert = $dbh->prepare('insert into users (username,password) values ("?","?")');
$insert = $pdo->prepare("insert into users (username,password) values (?,?)");
$insert->bindParam(1,$_POST["name"]);
$insert->bindParam(2,$hash);
$insert->execute();
echo "Registration Success!";
}
edit: The above code works if I change the code from the commented line to the non-commented (i.e. single quote to double quotes) However, this doesn't work later:
$query = $pdo->prepare("select * from users where username = ?");
$query->bindParam(1,$_POST["name"]);
$result = $query->execute()
Ok, you've found the answer to your first question.
For the second one it would be
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
called right after connect.
it will tell you what's going wrong with your query.
error_reporting(E_ALL);
also always helps with such errors like misspelled variables ($pdo is not $dbh for example)
If you want to use ? for placeholders, you are supposed to send an array to the execute-method matching the positions of the question marks. $insert->execute(array('value1', 'value2'));
You could however use named placeholders .. WHERE x = :myxvalue and use $insert->bindValue(':myxvalue', 'thevalue', PDO::PARAM_STR);
Also, please have a look at the difference between bindParam and bindValue
The answer to this question is simple and embarrassing:
I need to change the single quotes surrounding the sql statement being prepared to double quotes (and remove the double quotes where the '?' mark is.
change:
$insert = $dbh->prepare('insert into users (username,password) values ("?","?")');
to
$insert = $dbh->prepare("insert into users (username,password) values (?,?)");
and everything works.
I cannot for the life of me get binding to work with PDO queries, they always return false.
On this example, it checks that the value of a field is between 2 other values.
This works:
$query = $db->query("SELECT * FROM table WHERE field1 > '$start' AND field1 < '$finish'");
This doesn't:
$query = $db->query("SELECT * FROM table WHERE field1 > :start AND field1 < :finish");
$query->bindParam(":start", $start);
$query->bindParam(":finish", $finish);
UPDATE: The above query now works thanks to the help. The following still doesn't.
I have been trawling through various PDO posts on here but I have not found a solution, and I don't know what else to try.
UPDATE2: Okay, it seems it is not finding $db and therefore not connecting and returning false. The $db connection line is in a connect.php file that is required on all main pages. The content on those pages is called by a function that then includes the relevant file/page. Because PDO does not work by itself in functions, is it losing the $db through the function to include the file containing the query? I may not have explained myself clearly enough.
Basically, example function in functions.php:
function getRegistration() {
include("registration.php");
}
main.php
require_once("connect.php");
require_once("functions.php");
getRegistration();
registration.php contains:
$sql = $db->prepare("INSERT INTO tempus_members(username, email, password, activation_code, registration_date, registered_ip, name) VALUES(:username, :email, :password, :activation_code, :registration_date, :registered_ip, :name)");
$sql->bindParam(":username", $username);
$sql->bindParam(":email", $email);
$sql->bindParam(":password", $hash);
$sql->bindParam(":activation_code", $activation_code);
$sql->bindParam(":registration_date", $registration_date);
$sql->bindParam(":registered_ip", $registered_ip);
$sql->bindParam(":name", $name);
$sql->execute();
Is it losing the $db variable through the function to include the page? If so, how do I carry $db through all functions?
Try:
$stmt = $db->prepare("SELECT * FROM table WHERE field1 > :start AND field1 < :finish");
$stmt->bindParam(":start", $start);
$stmt->bindParam(":finish", $finish);
$stmt->execute();
You were using PDO::query instead of PDO::prepare.
As for the other query, what errors are you getting back? Try the following code and see if any errors are spit out onto the page:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try{
$sql = $db->prepare("INSERT INTO tempus_members(username, email, password, activation_code, registration_date, registered_ip, name) VALUES(:username, :email, :password, :activation_code, :registration_date, :registered_ip, :name)");
$sql->bindParam(":username", $username);
$sql->bindParam(":email", $email);
$sql->bindParam(":password", $hash);
$sql->bindParam(":activation_code", $activation_code);
$sql->bindParam(":registration_date", $registration_date);
$sql->bindParam(":registered_ip", $registered_ip);
$sql->bindParam(":name", $name);
$sql->execute();
}
catch(PDOException $e){
echo $e->getMessage();
}