PDO returning MySQL error with bindParam - mysql

Hey Guys I'm running this little function here
function getBeaches() {
$request=Slim::getInstance()->request();
$args=filter_var_array(func_get_args(),FILTER_SANITIZE_STRING);
$sql="SELECT * FROM beaches WHERE state=:state AND city=:city";
// var_export($args); die();
// array ( 0 => 'wa', 1 => 'seattle', )
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindValue('state', $args[0], PDO::PARAM_STR); //should bind wa
$stmt->bindValue('city', $args[1], PDO::PARAM_STR); //should bind seattle
$stmt->execute();
$stmt = $db->query($sql);
$beaches = $stmt->fetchObject();
$db = null;
echo '{"map": ' . stripslashes(json_encode($beaches)) . '}';
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
/* {"error":{"text":SQLSTATE[42000]: Syntax error or access violation:
* 1064 You have an error in your SQL syntax; check the manual that
* corresponds to your MySQL server version for the right syntax to use
* near ':state AND city=:city' at line 1}}
*/
}
And am getting the error I commented at the bottom, trying to run this like so
mysql$ SELECT * FROM beaches WHERE state='wa' AND city='seattle';
May be this rings some bells?

You need the semicolons before your param names: (Not 100% true, see edit)
$stmt->bindValue(':state', $args[0], PDO::PARAM_STR); //should bind wa
$stmt->bindValue(':city', $args[1], PDO::PARAM_STR); //should bind seattle
From the PHP docs on PDOStatement::bindValue():
Parameter identifier. For a prepared statement using named placeholders, this will be a parameter name of the form :name. For a prepared statement using question mark placeholders, this will be the 1-indexed position of the parameter.
EDIT
As #jeroen has pointed out the problem (the same one in your pastebin) that you overwrite the $stmt variable before you get the data from it. In you code the problem is around the 17th line:
$stmt->execute(); // $stmt now has query results (from the query with parameters bounded)
$stmt = $db->query($sql); // You redo the query. Now $stmt has no query results and no parameters are bound
$beaches = $stmt->fetchObject(); // Statement assumes you want to execute query and does so but not parameters are bound
You can remedy this by changing the above lines to:
$stmt->execute();
$beaches = $stmt->fetchObject();

Not sure if it helps, but I always used bindParam over bindValue. If you chose to do so, modify your binders as such:
$stmt->bindParam(':state', $args[0], PDO::PARAM_STR);
$stmt->bindParam(':city', $args[1], PDO::PARAM_STR);
Other than that, everything you're doing looks fine to me.

Related

What's the best way to fetch an array

Alright, so I believe that there is a better way that I can fetch an array from the database, here's the code right now that I have.
$id = 1;
$userquery = mysql_query("SELECT * FROM login WHERE id='$id'");
while($row = mysql_fetch_array($userquery, MYSQL_ASSOC)) {
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
So If I am not wrong, you want a better way to get all the returned rows from mysql in a single statement, instead of using the while loop.
If thats the case, then I must say mysql_ drivers do not provide any such functionality, which means that you have to manually loop through them using foreach or while.
BUT, since mysql_ is already depricated, you are in luck! you can actually switch to a much better and newer mysqli_ or the PDO drivers, both of which DO actually have functions to get all the returned rows.
For mysqli_: mysqli_result::fetch_all
For PDO : PDOStatement::fetchAll
Eg.
mysqli_fetch_all($result,MYSQLI_ASSOC);
// The second argument defines what type of array should be produced
// by the function. `MYSQLI_ASSOC`,`MYSQLI_NUM`,`MYSQLI_BOTH`.
Like the comments already told you: PHP's mysql driver is deprecated. And you should use prepared statements and parameters.
for example in PDO your code would look something like this:
//connection string:
$pdo= new PDO('mysql:host=localhost;dbname=my_db', 'my_user', 'my_password');
//don't emulate prepares, we want "real" ones:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//use exception-mode if you want to use exception-handling:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$id = 1;
//it's always better to strictly use backticks for db-names (db, tables, fields):
$sql = "SELECT * FROM `login` WHERE `id` = :id";
try
{
//create your prepared statement:
$stmt = $pdo->prepare($sql);
//bind a parameter and explicitly use a parameter of the type integer (in this case):
$stmt->bindParam(":id", $id, PDO::PARAM_INT);
//execute the query
$stmt->execute();
}
catch(PDOException $e)
{
exit("PDO Exception caught: " . $e->getMessage());
}
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
here you go: your PHP-MySQL routine is save against SQL-injections now and no longer uses deprecated PHP-functions! it's kinda state of the art ;)

can i use where and order by in mysql together?

Can i use where and order by in mysql together like this
$results=mysql_query("SELECT `status_content`
FROM `status`
WHERE `user_id`=".$_SESSION['user_id']."
ORDER BY `status_time` DESC" );
her is my code, but it is giving me error
Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\xampp\htdocs\lr\profile.php on line 65
<?php
$results=mysql_query("SELECT status_content FROM status
WHERE user_id=".$_SESSION['user_id']."
ORDER BY status_time DESC" );
while($row=mysql_fetch_array($results)) {
echo $row['status_content'];
}
?>
yes, this is valid as google will tell you http://dev.mysql.com/doc/refman/5.0/en/select.html
For your actual error, from the php docs:
For SELECT, SHOW, DESCRIBE, EXPLAIN and other statements returning resultset, mysql_query() returns a resource on success, or FALSE on error.
// Perform Query
$result = mysql_query($query);
// Check result
// This shows the actual query sent to MySQL, and the error. Useful for debugging.
if (!$result) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
// Use result
// Attempting to print $result won't allow access to information in the resource
// One of the mysql result functions must be used
// See also mysql_result(), mysql_fetch_array(), mysql_fetch_row(), etc.
while ($row = mysql_fetch_assoc($result)) {
// do something
}
Also: you should not use the mysql_* functions anymmore since they are deprecated and unsafe.
Use mysqli_* or PDO instead.

Prepaired statements in Zend_Db insert query

I currently use Zend_Db to manage my queries
$stmt = $db->prepare("INSERT INTO test (ID_Test) VALUES (:ID)");
$stmt->bindParam(':ID', 4, PDO::PARAM_INT);
$stmt->execute();
But this does seem to work throwing an error "Fatal error: Cannot pass parameter 2 by reference"
What am I doing wrong?
bindParam wants parameter two to be a variable, so it can reference or "link to" the variable instead of copying it, making it better for larger variables but annoying in your case, try:
$stmt = $db->prepare("INSERT INTO test (ID_Test) VALUES (:ID)");
$id = 4;
$stmt->bindParam(':ID', $id, PDO::PARAM_INT);
$stmt->execute();

How to fix call to undefined function prepare() in PDO?

QUESTION: Why am I getting Call to undefined function prepare() error ?
How can I fix it?
I know this is similar to my question, but I don't know how to apply the answer to my case.
$myNull = null;
$table="test_results";
$sql = "INSERT INTO $table (instance, uid, testid, quizstart, quizend, score)
VALUES (
:instance,
:uid,
:testid,
:quizstart,
:quizend,
:score)";
try {
/*** connect to DB ***/
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$stmt = $dbh>prepare($sql); // **************ERROR HERE****************
$stmt->bindParam(':instance', $myNull, PDO::PARAM_INT);
$stmt->bindParam(':uid',$userID, PDO::PARAM_INT);
$stmt->bindParam(':testid', $tid, PDO::PARAM_STR);
$stmt->bindParam(':quizstart', $quizstart,PDO::PARAM_STR);
$stmt->bindParam(':quizend', $quizend,PDO::PARAM_STR);
$stmt->bindParam(':score', $score,PDO::PARAM_STR);
$stmt->execute();
/*** display the id of the last INSERT ***/
$lastInsertValue=$dbh->lastInsertId();
$stmt->closeCursor();
/*** close the database connection ***/
$dbh = null;
}
You are missing the -. Try this
$stmt = $dbh->prepare($sql);
You have used greater than operator instead of arrow (->)
$dbh>prepare($sql); //WRONG
$dbh->prepare($sql); // CORRECT

How to insert array into mysql using PDO and bindParam?

I'm using the following code. The code works, but I want to change it so that it uses bindparam
try {
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$stqid=array();
for ($i=0; $i<$array_count; $i++){
$stqid[$i][0]=$lastInsertValue;
$stqid[$i][1]=$qid[$i][0];
$stqid[$i][2]=$qid[$i][1];
}
$values = array();
foreach ($stqid as $rowValues) {
foreach ($rowValues as $key => $rowValue) {
$rowValues[$key] = $rowValues[$key];
}
$values[] = "(" . implode(', ', $rowValues) . ")";
}
$count = $dbh->exec("INSERT INTO qresults(instance, qid, result) VALUES ".implode (', ', $values));
$dbh = null;
}
catch(PDOException $e){
echo $e->getMessage();
}
I replaced the following
$count = $dbh->exec("INSERT INTO qresults(instance, qid, result) VALUES ".implode (', ', $values));
with
$sql = "INSERT INTO qresults (instance, qid, result) VALUES (:an_array)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':an_array', implode(',', $values),PDO::PARAM_STR);
$stmt->execute();
but the insert doesn't work anymore (I didn't get any error messages though).
QUESTION: What am I doing wrong? How can I rewrite the code to use bindParam?
You're trying to create a statement and bind a param.
Statement are great because it potentially nullify any kind of SQL injection. And it does it by removing the concept of a query being only seen as a string. The SQL query is seen as a string with a parameter list and an the associated data as binded variables.
So the query is not only text, but text + data.
I mean:
This simple query:
SELECT * FROM A WHERE val="$param"
It is not safe because the query is only viewed as a string. And if $param is not checked, it is a SQLi hole.
But when create a statement, your query becomes:
SELECT * FROM A WHERE val=:param
Then you use bindparam to specify the value a :param. Which mean the value is not appended to the query string, but the query is already parsed and the data is provided.
In your case, you bind to the param :array an imploded array (I assume "data1", "data2", etc..). Which is only one parameter with the value as a string ( "data1, data2, data3..." ), so it will only result in one insert and not multiple insertions.
You can change your statement generation by generating a query with enough parameters to handle your array
$sql = "INSERT INTO qresults (instance, qid, result) VALUES ( :val0, :val1, :val2, ...)";
Then loop on your array and call the bindparam method for each parameters.
$count = 0;
foreach($values as $val)
{
$stmt->bindParam(":val$count", $val,PDO::PARAM_STR);
$count++;
}
This will work.
Edit: This solution show how it works for a one dimensional array, but can be easily extended to your problem by tweaking the statement query generation and modify the bindparam loop.
Your statement should looks like:
$sql = "INSERT INTO qresults (instance, qid, result) VALUES (:val0, :val1, :val2) , (:val3, :val4, :val5), ...";
You just have to count the number of element in your base array.