PDO parameterized query code review, how safe am i? - php

I'm a PHP newbie that just starts to code. Before coding any further, I need to know if I already on the right path on making a secure web. So please review my code samples below.
PHP Version 5.4.34
Database Server version: 5.5.40-cll - MySQL Community Server (GPL)
on connection.php
//should I use utf8mb4 and set server connection collation to utf8mb4_general_ci?
//also on html, is including <meta charset="utf-8"> necessary?
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
$db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // enabled by default?
select query
$query = "SELECT * FROM tbname WHERE username = :username";
$params = array(':username' => $_POST['username']);
try
{
$stmt = $db->prepare($query);
$result = $stmt->execute($params);
}
catch(PDOException $ex)
{
die();
}
insert query
$query = "INSERT INTO log (
username,
email,
ip,
time
) VALUES (
:username,
:email,
:lastip,
:lastlog
)";
$params = array(
':username' => $_POST['username'],
':email' => $_POST['email'],
':lastip' => $_SERVER['REMOTE_ADDR'],
':lastlog' => time()
);
try
{
$stmt = $db->prepare($query);
$result = $stmt->execute($params);
}
catch(PDOException $ex)
{
die();
}
update query
$params = array(
':username' => $_SESSION['userdata']['username'],
':email' => $_POST['email'],
':age' => $_POST['age'],
':gender' => $_POST['gender']
);
$query = "UPDATE users SET
email = :email,
age = :age,
gender = :gender
where username = :username";
try
{
$stmt = $db->prepare($query);
$result = $stmt->execute($params);
}
catch(PDOException $ex)
{
die();
}
How safe am i from SQL injection? Safe enough from 2nd order attack?

Totally safe. The PDO Statement prepares the query to avoid SQL injections. Even if they try, the prepare() function make the necessary changes before send to the database.

Related

Connect the database

I try to do the booking form and in the PHP I type the $stmt->bind_param part come out syntax error. However, I don't know where I did wrong. Here is my phpMyAdmin setting phpmyadmin table structure:
. Below is my code:
$conn = mysqli_connect($servername, $username, $password,$database);
// Check connection
if($conn->connect_error){
die("Connection Failed : ". $conn->connect_error);
} else {
$stmt = $conn->prepare("insert into event_and_inquiry_form (Name,Mail,Phone_Number,Date,Propose,Person,Theme,Event_Package,Remarks)VALUES (Name, Mail, Phone_Number,Date,Propose,Person,Theme,Event_Package,Remarks);
$stmt->bind_param("sssisisss", $Name,$Mail,$Phone_Number,$Date,$Propose,$Person,$Theme,$Event_Package,$Remarks);
$execval = $stmt->execute();
echo $execval;
$stmt
$stmt->close();
$conn->close();
}
You do happen to have a few issues.
When you prepare your mysqli statement the values to be inserted are to be held by a question mark ?. I believe you can hold them with :name :secondname as well but that's a story for another question.
You have not closed your quotes or bracket on the prepare function.
You have a random $stmt variable at the end of your script.
I corrected your code with what I noticed and posted it below:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = mysqli_connect($servername, $username, $password,$database);
$stmt = $conn->prepare("INSERT INTO `event_and_inquiry_form`
(`Name`,`Mail`,`Phone_Number`,`Date`,`Propose`,`Person`,`Theme`,`Event_Package`,`Remarks`)
VALUES
( ? , ? , ? , ? , ? , ? , ? , ? , ?)");
$stmt->bind_param("sssisisss", $Name,$Mail,$Phone_Number,$Date,$Propose,$Person,$Theme,$Event_Package,$Remarks);
$execval = $stmt->execute();
$stmt->close();
$conn->close();
It seems you're getting confused between mysqli and PDO - although there are syntax issues either way!
mysqli
With mysqli the short answer is that you need to replace all of the variables in VALUES( ... ) with ?.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // Enable error reporting
$mysqli = new mysqli($servername, $username, $password, $database); // Create connection to database
$sql = "
INSERT INTO event_and_inquiry_form
(Name,Mail,Phone_Number,Date,Propose,Person,Theme,Event_Package,Remarks)
VALUES (?,?,?,?,?,?,?,?,?)
";
$query = $mysqli->prepare($sql);
$query->bind_param("sssisisss", $Name, $Mail, $Phone_Number, $Date, $Propose, $Person, $Theme, $Event_Package, $Remarks);
$query->execute();
PDO
You can do it the same way in PDO.
Of course the connection method is different and we'll pass an array of the values to the execute function instead.
// Connect to the database
$pdo = new pdo(
"mysql:host={$servername};dbname={$database}",
$username,
$password,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => FALSE
]
);
$sql = "
INSERT INTO event_and_inquiry_form
(Name,Mail,Phone_Number,Date,Propose,Person,Theme,Event_Package,Remarks)
VALUES (?,?,?,?,?,?,?,?,?)";
$query = $pdo->prepare($sql);
$query->execute([$Name, $Mail, $Phone_Number, $Date, $Propose, $Person, $Theme, $Event_Package, $Remarks]);
Finally, in some cases you may prefer to name your placeholders. In this case the name will be :some_name and the array will need to be associative ["some_name"=> "Some value"].
// Connect to the database
$pdo = new pdo(
"mysql:host={$servername};dbname={$database}",
$username,
$password,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => FALSE
]
);
$sql = "
INSERT INTO event_and_inquiry_form
(Name,Mail,Phone_Number,Date,Propose,Person,Theme,Event_Package,Remarks)
VALUES
(:name, :mail, :phone_number, :date, :propose, :person, :theme, :event_package, :remarks)";
$query = $pdo->prepare($sql);
$query->execute([
"name" => $Name
"mail" => $Mail
"phone_number" => $Phone_Number
"date" => $Date
"propose" => $Propose
"person" => $Person
"theme" => $Theme
"event_package" => $Event_Package
"remarks" => $Remarks
]);

php PDO prepare(" INSERT ..(variables ) VALUES(?,?,) produces an error need assistance

$query = $this->link->prepare("INSERT INTO surveys (`username`,`inspected`,
`comments`,`ip_address`,`date`,`time`)
VALUES '(?,?,?,?,?,?)';);
$values = array ($username,$inspected,$comments,$ip_address,$date,$time);
var_dump($query);$rowCount = $query->rowCount();
$return $rowCount;
You can base yourself on the following which I've prepared for you.
Sidenote: I'm not entirely sure as to why you want to use rowCount() for, so I left it out for now.
If you're looking to check if a record exists using rowCount(), let me know.
The following method works to insert data into a database, which is based on a method I use.
<?php
$dbname = 'xxx';
$username = 'xxx';
$password = 'xxx';
try {
$pdo = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
exit( $e->getMessage() );
}
$sql = "INSERT INTO surveys (
username,
inspected,
comments,
ip_address,
date,
time
) VALUES (
:username,
:inspected,
:comments,
:ip_address,
:date,
:time)";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':username', $_POST['username'], PDO::PARAM_STR);
$stmt->bindParam(':inspected', $_POST['inspected'], PDO::PARAM_STR);
$stmt->bindParam(':comments', $_POST['comments'], PDO::PARAM_STR);
$stmt->bindParam(':ip_address', $_POST['ip_address'], PDO::PARAM_STR);
$stmt->bindParam(':date', $_POST['date'], PDO::PARAM_STR);
$stmt->bindParam(':time', $_POST['time'], PDO::PARAM_STR);
// $stmt->execute();
$stmt->execute(array(':username' => $_POST['username'],':inspected' => $_POST['inspected'],':comments' => $_POST['comments'],
':ip_address' => $_POST['ip_address'],':date' => $_POST['date'],':time' => $_POST['time']));
if($stmt != false) {
echo "success!";
} else {
echo "an error occured saving your data!";
}

Change mysql_ functions with PDO

I need to rewrite my php code with mysql_* functions with PDO so I have:
<?php
$con = mysql_connect('localhost', 'gmaestro_agro', 'pass') or die('Error connecting to server');
mysql_select_db('gmaestro_agro', $con);
mysql_select_db('gmaestro_agro', $con);
$query = "INSERT INTO `stat` (`Name`, `Gender`, `Age`, `Donuts eaten`) VALUES (";
$query .= "'".mysql_real_escape_string($_POST['Name']) . "', ";
$query .= "'".mysql_real_escape_string($_POST['Gender']) . "', ";
$query .= "'".mysql_real_escape_string($_POST['Age']) . "', ";
$query .= "'".mysql_real_escape_string($_POST['Donuts_eaten']);
$query .= "')";
$result = mysql_query($query);
if($result != false) {
echo "success!";
} else {
echo "an error occured saving your data!";
}
?>
and I try to write this but with PDO function like this:
<?php
/* Your Database Name */
$dbname = 'gmaestro_agro';
/* Your Database User Name and Passowrd */
$username = 'gmaestro_agro';
$password = 'pass';
$stmt = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$stmt->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO stat(Name,
Gender,
Age,
Donuts eaten
) VALUES (
:Name,
:Gender,
:Age,
:Donuts_eaten)";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':Name', $_POST['name'], PDO::PARAM_STR);
$stmt->bindParam(':Gender', $_POST['gender'], PDO::PARAM_STR);
$stmt->bindParam(':Age', $_POST['age'], PDO::PARAM_STR);
// use PARAM_STR although a number
$stmt->bindParam(':Donuts_eaten', $_POST['Donuts_eaten'], PDO::PARAM_STR);
$stmt->execute();
if($stmt != false) {
echo "success!";
} else {
echo "an error occured saving your data!";
}
?>
I dont get any error just nothing happend? Any idea how to solve my problem?
Edit (successful test code)
Table and data creation codes used for the successful insertion (test).
Column Donuts_eaten has been used with an underscore instead of a space.
You can base yourself on this:
Table creation codes in PHPmyadmin
Note: Change your_db_name to your Database name.
CREATE TABLE `your_db_name`.`stat` (
`Name` VARCHAR( 255 ) NOT NULL ,
`Gender` VARCHAR( 255 ) NOT NULL ,
`Age` INT NOT NULL ,
`Donuts_eaten` INT NOT NULL
) ENGINE = MYISAM
HTML form
Note: <input type="text" name="Donuts_eaten"> - Donuts_eaten is not the same as donuts_eaten notice the lowercase d
<form action="insert.php" method="post">
Name:
<input type="text" name="name">
<br>
Gender:
<input type="text" name="gender">
<br>
Age:
<input type="text" name="age">
<br>
Donuts eaten:
<input type="text" name="Donuts_eaten">
<br>
<input type="submit" name="submit" value="Submit">
</form>
PHP/SQL
<?php
/* Your Database Name */
$dbname = 'dbname'; // change this
/* Your Database User Name and Passowrd */
$username = 'username'; // change this
$password = 'password'; // change this
$pdo = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO stat (Name,
Gender,
Age,
Donuts_eaten
) VALUES (
:Name,
:Gender,
:Age,
:Donuts_eaten)";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':Name', $_POST['name'], PDO::PARAM_STR);
$stmt->bindParam(':Gender', $_POST['gender'], PDO::PARAM_STR);
$stmt->bindParam(':Age', $_POST['age'], PDO::PARAM_STR);
// use PARAM_STR although a number
$stmt->bindParam(':Donuts_eaten', $_POST['Donuts_eaten'], PDO::PARAM_STR);
// old execute
// $stmt->execute();
$stmt->execute(array(':Name' => $_POST['name'],':Gender' => $_POST['gender'],':Age' => $_POST['age'],':Donuts_eaten' => $_POST['Donuts_eaten']));
if($stmt != false) {
echo "success!";
} else {
echo "an error occured saving your data!";
}
?>
Original answer
You need to wrap Donuts eaten in backticks (for your column name), due to the space.
$sql = "INSERT INTO stat(Name,
Gender,
Age,
`Donuts eaten`
) VALUES (
:Name,
:Gender,
:Age,
:Donuts_eaten)";
Using spaces in column names is discouraged. Use an underscore instead for your table's column.
Also, change:
$stmt = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$stmt->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
to:
$pdo = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
because you're using $pdo in $stmt = $pdo->prepare($sql);
You are mixing up your variables, $pdo is undefined / not your database connection.
You can probably solve it by using:
$pdo = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
instead of:
$stmt = new PDO("mysql:host=localhost;dbname=$dbname", $username, $password);
$stmt->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
And if a table or column name contains spaces, you need to quote them in backticks:
Gender,
Age,
`Donuts eaten`
) VALUES (
But with the first change, PDO should throw an exception to show you this problem.

Data insert into mysql db table using PDO - Doesn't Insert Data

I'm 'Connected to database'. There is no data in the table, and $result doesn't echo anything. Even though I'm 'Connected to database', the error is as follows:
SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected
I've read the relevant postings, with no luck.
<?php
include("/directory outside of html/db.php");
try {
$dbh = new PDO("mysql:host=$host;database=$database", $username, $password);
/*** echo a message saying we have connected ***/
echo 'Connected to database';
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//try to insert data
$fname = 'BOB';
$lname = 'JONES';
$email = 'me#mymail.com';
$phone = '410-310-3456';
$resident = TRUE;
$age = '25=30';
$zip = '23456';
$result = FALSE;
$stmt = $dbh->prepare('INSERT INTO volunteers
(
lname,
fname,
email,
)
VALUES
(
:lname,
:fname,
:email,
)');
$result = $stmt->execute(array(
':lname' => $lname,
':fname' => $fname,
':email' => $email,
));
echo $result;
//catch any errors from try()
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
Use dbname= instead of database= , like this:
$dbh = new PDO("mysql:host=$host;dbname=$database", $username, $password);
Alternatively, you can select later a different database with USE, like this:
$dbh->query("use newdatabase");

PHP changing old mysql_query to PDO

I have some old mysql_query queries in my code which i want to convert in to PDO but am struggling to get to work.
my original code was:
mysql_query("UPDATE people SET price='$price', contact='$contact', fname='$fname', lname='$lname' WHERE id='$id' AND username='$username' ")
or die(mysql_error());
now i am trying:
$sql = "UPDATE people SET price='$price', contact='$contact', fname='$fname', lname='$lname' WHERE id='$id' AND username='$username'";
$q = $conn->query($sql) or die("failed!");
but can't seem to get it to work, any ideas?
UPDATED CODE:
$conn = new PDO("mysql:host=$host;dbname=$db",$user,$pass);
// check if the form has been submitted. If it has, process the form and save it to the database
if (isset($_POST['submit']))
{
// confirm that the 'id' value is a valid integer before getting the form data
if (is_numeric($_POST['id']))
{
// get form data, making sure it is valid
$id = $_POST['id'];
$fname = mysql_real_escape_string(htmlspecialchars($_POST['fname']));
$lname = mysql_real_escape_string(htmlspecialchars($_POST['lname']));
$contact = mysql_real_escape_string(htmlspecialchars($_POST['contact']));
$price = mysql_real_escape_string(htmlspecialchars($_POST['price']));
// check that firstname/lastname fields are both filled in
if ($fname == '' || $lname == '' || $contact == '' || $price == '' )
{
// generate error message
$error = 'ERROR: Please fill in all required fields!';
//error, display form
renderForm($id, $fname, $lname, $contact, $price, $error);
}
else
{
// save the data to the database
$username = $_SESSION['username'];
$query = "UPDATE people
SET price=?,
contact=?,
fname=?,
lname=?
WHERE id=? AND
username=?";
$stmt = $db->prepare($query);
$stmt->bindParam(1, $price);
$stmt->bindParam(2, $contact);
$stmt->bindParam(3, $fname);
$stmt->bindParam(4, $lname);
$stmt->bindParam(5, $id);
$stmt->bindParam(6, $username);
$stmt->execute();
// once saved, redirect back to the view page
header("Location: view.php");
}
For more information visit this link: PHP PDO
based on your example,
<?php
$query = "UPDATE people
SET price=?,
contact=?,
fname=?,
lname=?
WHERE id=? AND
username=?";
$stmt = $dbh->prepare($query);
$stmt->bindParam(1, $price);
$stmt->bindParam(2, $contact);
$stmt->bindParam(3, $fname);
$stmt->bindParam(4, $lname);
$stmt->bindParam(5, $id);
$stmt->bindParam(6, $username);
$stmt->execute();
?>
PDO Prepared statements and stored procedures
Note that when working with the mysql driver for PDO you always have to disable emulated prepared statements:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = 'UPDATE people SET';
$sql.= ' price = :price,';
$sql.= ' contact = :contact,';
$sql.= ' fname = :fname,';
$sq;.= ' lname = :lname';
$sql.= ' WHERE id= :id AND username = :username';
$stmt = $pdo->prepare($sql);
$stmt->execute(array(
':price' => $price,
':contact' => $contact,
':fname' => $fname,
':lname' => $lname,
':id' => $id,
':username' => $username,
));
As you can see I have used named parameters, because when you have lots of them it is imho way clearer what you are doing.
Note: that ircmaxell is currently working on getting the default to always use real prepared statements, but until that (which may take some while) you always have to disable them for mysql.
If you're going to use PDO, you need to look at prepare() and execute otherwise you're losing the security that PDO is offering and retaining the SQL Injections. So, given your example:
$conn = new PDO(/*connection info*/);
$query = $conn->prepare("UPDATE people "
. "SET price = :price, "
. " contact = :contact, "
. " fname = :fname, "
. " lname = :lname "
. "WHERE id = :id "
. " AND username = :username");
$result = $query->execute(array(
':price' => $price,
':contact' => $contact,
':fname' => $fname,
':lname' => $lname,
':id' => $id,
':username' => $username
));
That's more the lax way, but you can also bindParam and be explicit as to the data type it's expecting.
Few things you have to be clear while using PDO extension is that there are multiple ways to get things done.
The way you are currently using being one of them including few more. However it is always a good idea to bind parameters separately, because this prevents many problems like SQL Injection and many more.
Other important things to look at are statement, prepare and execute.
$conn = new PDO("...."); //Creating the handler
//Create the statement
$stmt = $conn -> prepare("UPDATE people SET price = :price, contact = :contact, fname = :fname, lname = :lname WHERE id= :id AND username = :username");
// Bind the params
$stml -> bindParam(":contact", $contact, PDO::PARAM_STR); //This way you can also define the DATATYPE of the parameter
//Execute
$stmt -> execute(array(
":price" => $price, //another way of binding the params
":fname" => $fname,
":lname" => $lname,
":id" => $id,
":username" => $username));

Categories