I know of two ways to use PDO in PHP to update a MySQL database record. Please could someone explain which one I should use for better security and the difference and I am a little confused.
Method One:
$user = "root";
$pass = "";
$dbh = new PDO('mysql:host=somehost;dbname=somedb', $user, $pass);
$sql = "UPDATE coupons SET
coupon_code = :coupon_code,
valid_from = :valid_from,
valid_to = :valid_to,
discount_percentage = :discount_percentage,
discount_amount = :discount_amount,
calculationType = :calculationType,
limit = :limit
WHERE coupon_code = :coupon";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':coupon_code', $_POST['coupon_code'], PDO::PARAM_STR);
$stmt->bindParam(':valid_from', $_POST['$valid_from'], PDO::PARAM_STR);
$stmt->bindParam(':valid_to', $_POST['valid_to'], PDO::PARAM_STR);
$stmt->bindParam(':discount_percentage', $_POST['discount_percentage'], PDO::PARAM_STR);
$stmt->bindParam(':discount_amount', $_POST['discount_amount'], PDO::PARAM_STR);
$stmt->bindParam(':calculationType', $_POST['calculationType'], PDO::PARAM_STR);
$stmt->bindParam(':limit', $_POST['limit'], PDO::PARAM_STR);
$stmt->bindParam(':coupon', $_POST['coupon_code'], PDO::PARAM_STR);
$stmt->execute();
Method Two:
$dbtype="somedbtype";
$dbhost="somehost";
$dbname="somedb";
$dbuser="someuser";
$dbpass= "somepass";
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);
$title = 'PHP Pattern';
$author = 'Imanda';
$id = 3;
$sql = "UPDATE books
SET title=?, author=?
WHERE id=?";
$q = $conn->prepare($sql);
$q->execute(array($title,$author,$id));
From what I can see, method two does not bind the data, rather insert it directly into the query as an array type. Does this make the script more susceptible to SQL injection or other security risks?
The only difference between the two is that if you pass the array in to the execute function rather than calling bindParam yourself, it treats all parameters as PDO::PARAM_STR automatically, whereas in calling bindParam yourself you could bind them as integers, etc.
From the docs:
input_parameters
An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as PDO::PARAM_STR.
You can also see from the examples there that you can use named parameters (e.g. :limit) when passing the array into the execute function. You don't have to just put ?. In that case you give the array a key:
$sth->execute(array(':calories' => $calories, ':colour' => $colour));
It's mostly a matter of preference. Both protect you from injection.
Though I think it's much easier to force data type with bind(), where as using execute(array()) will be using strings.
Related
I'm building an API with a bunch of db queries. To avoid repeating some pre established values in each query I created some PHP constants. However I'm not sure about the right way to include them in Mysqli prepared statements. I know that constants can't be passed by reference. So I wonder if I should create a variable for the query that includes the constants or if I could just pass the string directly with the constants to the prepare() function. So it is okay if I do it like this or should I create a variable and storing the string there prior to calling prepare()?
$stmt = $this->conn->prepare("SELECT city FROM masters WHERE email = ? AND estado != '" . STATE_INACTIVE . "'");
$stmt->bind_param("s", $email );
VERSUS
$query = "SELECT city FROM masters WHERE email = ? AND estado != '" . STATE_INACTIVE . "'";
$stmt = $this->conn->prepare($query);
$stmt->bind_param("s", $email );
Since you're using a constant value, you're not exposing yourself to potential SQL injection attacks by concatenating the value into your query. So, I think what you have is fine. Your other option would be to assign the constant value to a variable and bind it, like this:
$query = "SELECT city FROM masters WHERE email = ? AND estado != ?";
$inactiveState = STATE_INACTIVE;
$stmt = $this->conn->prepare($query);
$stmt->bind_param("ss", $email, $inactiveState);
It's worth pointing out as well here that this is mysqli, not PDO. If you were using PDO you could do this:
$query = "SELECT city FROM masters WHERE email = ? AND estado != ?";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(1, $email, PDO::PARAM_STR);
$stmt->bindValue(2, STATE_INACTIVE, PDO::PARAM_STR);
I am preparing mysql configuration settings using class. I am confused about it. I always use bindParam. It also possible to insert using array. I mean, what are the differences between array and bindparam.
eg array
$query = $db->prepare("INSERT INTO users SET
username = :uname,
password = :upass,
email = :umail");
$insert = $query->execute(array(
"upass" => "123456",
"umail" => "user#user.com",
"uname" => "username",
));
if ( $insert ){
$last_id = $db->lastInsertId();
}
eg
$stmt = $this -> db_conn -> prepare("INSERT into users(username, password) VALUES(:uname, :upass)");
$stmt -> bindParam(':uname', $username);
$stmt -> bindParam(':upass', $password);
$stmt -> execute();
Desconsidering the fact that with execute you can't choose the data type (it's always PDO::PARAM_STR) There's only a main difference between both (which is from core). PDOStatement::bindParam is by reference while PDOStatement::execute isn't. PDOStatement::execute do internnaly the same thing as PDOStatement::bindValue, but twice.
Internally (in C), bindValue calls the same method which execute calls. The method name which is called is really_register_bound_param.
On the other hand, bindParam calls other method called register_bound_param.
It means that bindValue calls the same method called by execute more than one time while bindParam calls a method to bind as a reference and only "really register" the param when execute is called.
Thinking about bind by reference, it's only possible using bindParam:
//fictional code
$stmt= $pdo->prepare("INSERT INTO table (column) VALUES (:value)");
$stmt->bindParam(":value", $randomValue);
for($i = 0 ; $i < 1000; $i))
{ $randomValue = rand(1000,1000000);
$stmt->execute();
}
Is it worthy? Perhaps while a while with a complex insert with multiples parameters could reduce the overhead with rebinding a new parameter or a big amount of them.
I have a MySQL query which works from the command line, but not from PHP.
Can anyone see what I am doing wrong?
$sqlText = 'SELECT FROM customers WHERE login_name=:name
AND password=:password';
$query = $pdo->prepare($sqlText);
$query->bindParam(':name', $userName);
$query->bindParam(':password', sha1($password));
$result = $query->fetch(PDO::FETCH_ASSOC);
and $result is false.
But, from the command line,
SELECT * FROM customers WHERE login_name="a"
AND password="4192dee2f886e99ececbb2eee0d2f37f11257974"
works.
When I debug userName is a and $password is 4192dee2f886e99ececbb2eee0d2f37f11257974.
Can some one make me say D'oh ?
You've forgotten about execute I suppose:
$sqlText = 'SELECT FROM customers WHERE login_name=:name AND password=:password';
$query = $pdo->prepare($sqlText);
$hash = sha1($password);
$query->bindParam(':name', $userName);
$query->bindParam(':password', $hash);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
You forgot execute().
Moreover, if really $password` is `4192dee2f886e99ececbb2eee0d2f37f11257974, then you must be running sha1() twice. Either remove the sha1() from the bind line, or keep $password in the clear.
I'd suggest naming the database column "passwordHash", and the variable either $password if it is in cleartext, or $passwordHash if you already ran sha1() on it. That way, you would have written
$query->bindParam(':passwordHash', sha1($passwordHash));
and immediately spotted the extra sha1() call.
you have to call $query->execute(); to execute the query in PDO
$sqlText = 'SELECT FROM customers WHERE login_name=:name AND password=:password';
$query = $pdo->prepare($sqlText);
$query->bindParam(':name', $userName);
$query->bindParam(':password', sha1($password));
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
The prepare method only prepares the sql statement you passed in and returns a preparedstatement object.
As mentioned above, you need to set the params and execute it to get the resultset back.
The advantages of prepared statement besides the security is that you can repeatedly assign parameters and execute a preparedstatement which is considered to be faster than compiling the same sql query string again and again.
$stmt = $this->_db->prepare("SELECT userid FROM users WHERE login = ? AND md5pass = ?");
#$stmt->bindParam(1, $login, PDO::PARAM_INT);
#$stmt->bindParam(2, $pass, PDO::PARAM_STR);
$stmt->execute(array($login,$pass));
$res = $stmt->fetch(PDO::FETCH_NUM);
Which way is better to transfer variables to prepeared statment bindParam or execute(array)? Both working but what is differense? Only PDO::PARAM checking? For SELECT I think array would be enough and for INSERT I sould use the bindParam. Am I right? Thanks to all. Just learning =)
With bindParam you can add the datatype and also important with bind param you are binding the variables by reference.
The current error when running this from the command line is "Call to a member function bindParam() on a non-object" which I've worked out to being a problem with the variable $orderPO. Something does not like non-numeric characters which led me to the bindParam PARAM_STR business which does not work either. The database fields are both varchar 50.
My search skills are failing me. I know this must be posted somewhere about a million times but I can't seem to find it. I am completely open to doing this another way if someone has a better idea.
Current attempt code:
try
{
$orderNum = '123456';
$orderPO = '123456-A';
$dbh = new PDO("mysql:host=localhost;dbname=dbname", 'someuser', 'somepass');
$stm = $dbh->prepare("insert into some_table (order_number, order_po)");
$stm->bindParam(':order_number', $orderNum, PDO::PARAM_STR);
$stm->bindParam(':order_po', $orderPO, PDO::PARAM_STR);
$stm->execute();
print_r($stm);
print_r($dbh);
$arr = $stm->errorInfo();
print_r($arr);
$stm->closeCursor();
$dbh = null;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
In order to bind parameters using PDO, you will need to use placeholders, like this:
$stm = $dbh->prepare("
INSERT INTO `some_table` SET
`order_number` = :order_number,
`order_po` = :order_po
");
$stm->bindParam(':order_number', $orderNum, PDO::PARAM_STR);
$stm->bindParam(':order_po', $orderPO, PDO::PARAM_STR);
Notice the inclusion of the : character before the named placeholder. I also added column names to your query.
Read further and see examples: PDO bindParam
The correct syntax is
$stm = $dbh->prepare("insert into some_table (order_number, order_po) VALUES (?, ?)");
$stm->bindParam(1,$orderNum);
$stm->bindParam(2,$orderPO);
include the questions marks, the numbers in the bindParam call refer to which question mark you're binding the parameter to
You are trying to use bindparam, but bind param matches ? not cursors :. You have not included any parameters or values.
Also, you are missing your VALUES statement within the query, which is causing the query to fail. This is why you get the "Call to a member function bindParam() on a non-object"
To use the :value syntax, use bindValue, not bindParam. to use bindParam, switch the :value to ? in your query and number them in order is your execute array.
try
{
$orderNum = '123456';
$orderPO = '123456-A';
$dbh = new PDO("mysql:host=localhost;dbname=dbname", 'someuser', 'somepass');
$stm = $dbh->prepare("insert into some_table (order_number, order_po) VALUES (:order_number, :order_po)");
$stm->bindvalue(':order_number', $orderNum, PDO::PARAM_STR);
$stm->bindvalue(':order_po', $orderPO, PDO::PARAM_STR);
$stm->execute();
print_r($stm);
print_r($dbh);
$arr = $stm->errorInfo();
print_r($arr);
$stm->closeCursor();
$dbh = null;
}
catch(PDOException $e)
{
echo $e->getMessage();
}