PDO debugging update query using bindValue - php

I'm using PDO and I can't find what's wrong in there and can't seem to get an error even if PDO's setAttribute is set to.
$fields = $data['fields'];
$cartID = $data['cartID'];
$sql = "UPDATE ShoppingCart
SET shipToSameLocation_shippingLocationID = :shippingLocationID, shipToSameLocation_shippingMethod = :shippingMethod, shipToSameLocation = 1
WHERE cartID = :cartID";
$query = $conn->prepare($sql);
$query->bindValue(':shippingLocationID', $fields['shipToSameLocation_shippingLocationID'], PDO::PARAM_INT);
$query->bindValue(':shippingMethod', $fields['shipToSameLocation_shippingMethod'], PDO::PARAM_STR);
$query->bindValue(':cartID', $cartID, PDO::PARAM_INT);
$query->execute();
Anything wrong in there related to PDO?

Proabaly because you are explicitly saying that the value will be an int but not coercing the post value into and int;
$fields = $data['fields'];
$cartID = (int) $data['cartID'];
$sql = "UPDATE ShoppingCart
SET shipToSameLocation_shippingLocationID = :shippingLocationID, shipToSameLocation_shippingMethod = :shippingMethod, shipToSameLocation = 1
WHERE cartID = :cartID";
$query = $conn->prepare($sql);
$query->bindValue(':shippingLocationID', $fields['shipToSameLocation_shippingLocationID'], PDO::PARAM_INT);
$query->bindValue(':shippingMethod', $fields['shipToSameLocation_shippingMethod'], PDO::PARAM_STR);
$query->bindValue(':cartID', $cartID, PDO::PARAM_INT);
$query->execute();
The same goes for the other values you are binding so cast them to their correct type, or better yet don't use bind value. Personally I have never bothered to bind params or values, I just pass an associative array into PDO.
$locId = (int) $fields['shipToSameLocation_shippingLocationID'];
$method = $fields['shipToSameLocation_shippingMethod'];
$cartId = (int) $data['cartID'];
$params = array(
':shippingLocationID' => $locId ,
':shippingMethod' => $method,
':cartID' => $cartId
);
$query->execute($params);
works for like a charm every time. Most places I work, the other people end up adopting this method because it is so much less trouble to code and to use, but it is up to you.

Related

PDO prepared statement bind parameters once for different queries

I am using PDO prepared statements to execute two queries:
SELECT count(*) FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson;
SELECT * FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson limit 100;
The first query to get the count works as expected and i get the row count.
$stmt = $this->connection->prepare($sql);
foreach ($params as $key => $value)
$stmt->bindValue(":" . $key, $value, PDO::PARAM_STR);
$stmt->execute();
$count = $stmt->fetchColumn();
$sql .= " limit $limit;";
$sql = str_replace("count(*)", $columns, $sql);
$stmt = $this->connection->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_CLASS, $class);
But when executing the second query i get:
SQLSTATE[HY093]: Invalid parameter number: no parameters were bound
Therefore, I would like to know, if I have multiple queries where the parameters are exactly the same ,if I need to bind the same parameters again using
foreach ($params as $key => $value)
$stmt->bindValue(":" . $key, $value, PDO::PARAM_STR);
or if there is a way to bind parameters only once.
If I have multiple queries where the parameters are exactly the same, do I need to bind the same parameters again using
Yes, of course.
Parameters are bound to each query, not to PDO or a database globally.
On a side note, with PDO you don't have to bind variables explicitly, so there is a solution to your "problem": just don't bind at all but send your data directly into execute() as it shown in the Dharman's excellent answer
There is no need to modify your SQL like this. Your code basically comes down to this:
$stmt = $this->connection->prepare('SELECT count(*) FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson');
$stmt->execute($params);
$count = $stmt->fetchColumn();
$stmt = $this->connection->prepare('SELECT * FROM vocabulary WHERE `type` = :type AND `lesson` = :lesson limit 100');
$stmt->execute($params);
$result = $stmt->fetchAll(PDO::FETCH_CLASS, $class);

Which PDO bind approach should be used for greater security?

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.

Unable to change two things about a single row in mysql with php

Here's the code:
$id = intval($_POST['id']);
$score = "'" . $_POST['score'] . "'";
$shares = "'" . $_POST['shares'] . "'";
$conn = new PDO('mysql:host=localhost;dbname=news', 'root', '');
$stmt = $conn->prepare("UPDATE news SET 'shares' = :shares, 'score' = :score
WHERE id = :id");
$stmt -> execute(array(
'shares' => $shares,
'score' => $score,
'id' => $id
));
And it doesn't work. I am unsure as to how I would see the error that I assume mysql is giving somewhere, and I've tried everything I could think of.
Using double quotes and adding the variables into the statement right away.
Adding single quotes to shares and score.
How am I supposed to be doing this?
I think you need to remove the quote from the column names e.g. below:
$stmt = $conn->prepare("UPDATE news SET shares = :shares, score = :score
WHERE id = :id");
Also better to use bindParam method to bind the parameters.
$stmt ->bindParam(':shares', $shares, PDO::PARAM_INT);
$stmt ->bindParam(':score', $score, PDO::PARAM_INT);
$stmt ->bindParam(':id', $id, PDO::PARAM_INT);
$stmt -> execute();
I am assuming all the fields are INT type. If not, please update with the appropriate type.
I guess you have forgotten the colon in execute statement, here goes the edited code.
$stmt = $conn->prepare("UPDATE news SET shares = :shares, score = :score
WHERE id = :id");
$stmt -> execute(array(
':shares' => $shares,
':score' => $score,
':id' => $id
));

PHP: PDOStatement simple MySQL Select doesn't work

I have the following PHP code doing a very simple select into a table.
$statement = $db->prepare("SELECT * FROM account WHERE fbid = :fbid");
$statement->bindParam(":fbid",$uid, PDO::PARAM_STR,45);
$out = $statement->execute();
print_r($out) // 1;
//$out = $statement->execute(array(':fbid' => $uid)); // also doesn't work
$row = $statement->fetch();
$out is true (success) yet $row is null.
EDIT:
$statement->debugDumpParams();
Outputs
SQL: [40] SELECT * FROM account WHERE fbid = :fbid Params: 1 Key: Name: [5] :fbid paramno=-1 name=[5] ":fbid" is_param=1 param_type=2
If I modify the code as follows:
$statement = $db->prepare("SELECT * FROM account WHERE fbid = $uid");
$out = $statement->execute();
$row = $statement->fetch();
$row contains the record I'm expecting.
I'm at a loss. I'm using the PDO::prepare(), bindParams() etc to protect against SQL Injection (maybe I'm mistaken on that).
EDIT:
In my example, $uid is a numerical string (ie a string containing only numbers). In the database, the column type is VARCHAR(45)
EDIT:
If I change the database type from VARCHAR(45) to BIGINT, both queries work. If I change the type in the database type back to VARCHAR(45) again, it works. So what gives?
Please halp.
You need to check your fbid value. it should be always string if its integer value is greater than 2^32 (unsigned), simply cast by (string)$uid is not work, and sprintf("%.0f",...) will only works when integer value less than 2^52, because on 32-bit OS when a number is greater than 2^31(32 unsigned) PHP will assume it is double type and default precise is only 14 decimal but fbid is 20.
You have to keep fbid in string contains only [0-9] in PHP, doesn't matter it is stored as BIGINT or VARCHAR in MySQL, MySQL accepts only string sql statement and always returns result in string format.
$mi = new mysqli("localhost", "root", "xxx", "test");
$uid = "12379739851403943597"; // Works
//$uid = 12379739851403943597; // never Works
//$uid = (string) 12379739851403943597; // get "1.2379739851404E+19" wrong string !
//$suid = sprintf("%.0f", $uid); // get "12379739851403943936" lost precise
$stmt = $mi->prepare("select * from bitest where id = ?");
$stmt->bind_param('s', $uid);
$stmt->execute();
$stmt->bind_result($id, $name);
$stmt->store_result();
print "numrow: " . $stmt->num_rows . " - \n";
$stmt->fetch();
print "$id - $name \n";
$stmt->free_result();
$stmt->close();
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'xxx');
$sql = "select * from bitest where id = ?";
$sth = $pdo->prepare($sql);
$sth->bindParam(1, $uid, PDO::PARAM_STR);
$sth->execute();
var_dump($sth->fetchAll(PDO::FETCH_ASSOC));
I think there may be an issue with your PDO installation.
$uid = 552192373; // my facebook uid for testing
$statement = $db->prepare("SELECT * FROM users WHERE facebook_uid = :fbid");
$statement->bindParam(":fbid",$uid, PDO::PARAM_STR,45);
$out = $statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo '<pre>';
print_r($row);
echo '</pre>';
returns:
Array
(
[id] => 1
[facebook_name] => Jason Boehm
[facebook_uid] => 552192373
)
It's been a while... try passing a hash to execute instead:
$statement->execute(array( 'fbid' => $uid ));
Maybe try PDO::PARAM_INT
Aside from that, keep in mind bindParam() takes the variable as a reference. Maybe your demo code doesn't show you changing the value of that variable before execute() is called. See bindValue() if needed.
Try dropping the extra parameter,
$statement->bindParam (":fbid", $uid, PDO::PARAM_STR);
(edit)
Are you 100% positive there is no extra whitespace surrounding the UID? Test with trim() and pass by value:
$statement->bindValue (":fbid", trim($uid), PDO::PARAM_STR);

update query strange issue

function updateDemo($demoTitle, $desc, $keyword,
$uploadedFile, $clientname, $uploadedImage, $adminName, $demoID)
{
$query = "UPDATE demos SET dmTitle ='sdsdsdsdsd' , dmDesc = '$desc' ,
dmKey = '$keyword' , dmLink= '$uploadedFile' , client='$clientname' ,
imageTitle = '$uploadedImage' , userName = '$adminName'
WHERE id = '$demoID'";
$result = mysql_query($query);
if($result) {
return 'yes';
} else {
return mysql_error();
}
}
This is an update of the previous, question. I have the query executed and i am getting the return value as Yes, but it seems strange for me that the values are not getting updated.
Though when i check down here in PHP, i am getting the update values...
I tried to hardcode a value for title and it also seems not getting updated.
Try to check what mysql_affected_rows() returns. If it's not 1, then your $demoID is probably wrong. If it is 1, you're probably looking in the wrong place in the DB.
And please, for security's sake, consider switching to a DB interface which supports prepared statements (mysqli, PDO) if possible.
Edit
Here's your code using PDO
function updateDemo($demoTitle, $desc, $keyword,
$uploadedFile, $clientname, $uploadedImage, $adminName, $demoID)
{
$query = "UPDATE demos SET dmTitle = ? , dmDesc = ? ,
dmKey = ? , dmLink= ?, client=? ,
imageTitle = ? , userName = ?
WHERE id = ?";
global $db;
$stmt = $db->prepare($query);
$stmt->execute(Array(
$demoTitle, $desc,
$keyword, $uploadedFile, $clientname,
$uploadedImage, $adminName,
$demoId
));
return $stmt->rowCount();
}
This assumes that you have a global variable $db holding a PDO connection (there are better solutions but it's the simplest and will probably suffice).

Categories