PDO prepared statement bind parameters once for different queries - php

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);

Related

Full text search with mysql php

I am trying to make a search key feature. But I am not getting any result with the following query.
public function SearchKey($key,$userid)
{
$key = mysqli_real_escape_string($this->db, $key);
$userid = mysqli_real_escape_string($this->db, $userid);
$query = mysqli_query($this->db,"SELECT * FROM posts WHERE
MATCH(theKey) AGAINST('$key' IN NATURAL LANGUAGE MODE)
AND uid = '$userid' ORDER BY sgq_id LIMIT 5") or die(mysqli_error($this->db));
while($row=mysqli_fetch_array($query)) {
$data[]=$row;
}
if(!empty($data)) {
return $data;
}
}
Then fetch,
$search = $Data->SearchKey($key, $userid);
if($search){
foreach($search as $data){
echo $data['theKey'];
}
}
For example if I search OK005 then I can not get any results. I tried Full-text Search functions https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html
Anyone can help me here, what I am missing ?
You're using single quotes to pass your variables. These will not be expanded in your query. You're better off using a prepared statement, and use parameter/value bindings to pass the variables. This will also solve the problem of SQL injection that your code appears to be vulnerable to.
You can try something like:
// Replace comment with appropriate connection data.
$pdo = new PDO(/* your DSN etc. */);
// Your query.
$sql =
'SELECT * FROM posts WHERE ' .
'MATCH(theKey) AGAINST(? IN NATURAL LANGUAGE MODE) ' .
'AND uid = ? ORDER BY sgq_id LIMIT 5';
// Create prepared statement from query.
$statement = $pdo->prepare($sql);
// Bind the values and enforce data type.
$statement->bindValue(1, $key, PDO::PARAM_STR);
$statement->bindValue(2, $userid, PDO::PARAM_INT);
// Run query.
$statement->execute();
// Get query results.
$rows = $statement->fetchAll();
// Your magic ...

Prepared statements when working with set operations

I've got a simple query that is not so easy to execute in PHP script:
SELECT `title` from `MY_TABLE` WHERE id in (30,32,33,44)
Usually I execute sql queries with prepared statements. I place a bunch of ? and than bind parameters. This time the numbers in parenthesis are an array of data I get from the user.
I tried this, but it does not work:
$ids = [30,32,33,44];
$stmt = $mysqli->prepare("
SELECT `title` from `MY_TABLE` WHERE id in (?)
");
// $stmt->bind_param();
$stmt->bind_param("i",$ids);
$stmt->execute();
$stmt->bind_result($title);
$stmt->store_result();
//fetch
How can I execute a set operation with prepared statements?
UPDATE:
After following your advice I came up with this
$ids = [30,32,33,44];
$questionMarks = rtrim(str_repeat('?,',count($ids)),", ");
$parameters = str_repeat('i',count($ids));
echo $questionMarks."<br>";
echo $parameters."<br>";
$stmt = $mysqli->prepare("
SELECT `title` from `MY_TABLE` WHERE id in (".$questionMarks.")
");
$scene_names = [];
$stmt->bind_param($parameters, $ids); //error here
$stmt->execute();
$stmt->bind_result($title);
$stmt->store_result();
I am still getting an error. This time it says:
Number of elements in type definition string doesn't match number of bind variables
I am not sure why it thinks that the number of elements (what is element in this case?) is wrong.
UPDATE 2:
Instead of:
$stmt->bind_param($parameters, $ids); //error here
I used:
$stmt->bind_param($parameters, ...$ids); //error gone
Taraam. Works fine.
Something like:
$ids = [30,32,33,44];
$types = array();
foreach($ids as $i){
array_push($types,'i');
}
$params = array_merge($ids,$types);
$sqlIN = str_repeat('?,',count($ids));
$sqlIN = rtrim($sqlIN, ',');
//Value of $sqlIN now looks like ?,?,?,?
$sql = "SELECT title from MY_TABLE WHERE id IN ($sqlIN)";
$stmt = $mysqli->prepare($sql);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$stmt->bind_result($id);
$stmt->store_result();

MSSQL php pdo pagination, some thing wrong on bindParam

Working fine with MsSQL:
$ppage = 15;
$poset = 0;
$stmt = "SELECT * FROM tbl ORDER BY ID OFFSET {:$poset } ROWS FETCH NEXT {:ppage } ROWS ONLY";
$stmt = $this->conn->prepare($stmt);
$stmt->execute();
return $row = $stmt->fetchAll();
Not working fine with MsSQL:
$ppage = 15;
$poset = 0;
$stmt = "SELECT * FROM tbl ORDER BY ID OFFSET :poffset ROWS FETCH NEXT :perpage ROWS ONLY";
$stmt = $this->conn->prepare($stmt);
$stmt->bindParam(':poffset', $poset);
$stmt->bindParam(':perpage', $ppage);
$stmt->execute();
return $row = $stmt->fetchAll();
the query is fine with I use to run with variables actual data it works but it's not working when I set the variable by bindParam, when am I missing.
thanks in advance.
Try using bindValue instead:
$stmt = $this->conn->prepare($stmt);
$stmt->bindValue(':poffset', $poset, PDO::PARAM_INT);
$stmt->bindValue(':perpage', $ppage, PDO::PARAM_INT);
$stmt->execute();
Rather than using the bindParam() function, inside of the parameters of the execute() function, add an array containing the values.
Something like this:
$stmt = $this->conn->prepare($stmt);
$stmt->execute(array(':poffset' => $poset, ':perpage' => $ppage)); // using an array rather than the bindValue function.
Use it as you would normally with the bindParam function, but substitute the commas for =>.
This way of doing things will save you having to call the bindParam() function for each value & will still protect against SQL Injection.

Left join using PDO

I am using the following PDO query:
<?php
$cadena = $_SESSION[Region];
// We Will prepare SQL Query
$STM = $dbh->prepare("SELECT `id_mesero`, `nombre_mesero`,`alias_mesero`, `rest_mesero` FROM tbmeseros WHERE cadena_mesero='$cadena'");
// For Executing prepared statement we will use below function
$STM->execute();
// we will fetch records like this and use foreach loop to show multiple Results
$STMrecords = $STM->fetchAll();
foreach($STMrecords as $row)
{
The value from the 'rest_mesero' field is the index from the table 'tbrestaurantes'.
I would need to join some fields values from 'tbrestaurantes' to the PDO query, but I don't know how to do it using PDO.
Any help is welcome.
UPDATED QUESTION TEXT
This is my proposal for the query :
$dbh->prepare("SELECT * FROM tbmeseros LEFT JOIN tbrestaurantes ON tbmeseros.rest_mesero = tbrestaurantes.id_restaurante WHERE tbmeseros.cad_mesero = ?");
But is show an error:
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound in /.../AdminMeseros.php on line 80
Line 80 is
$STM->execute();
This is my updated query:
<?php
$cadena = $_SESSION[Region];
$STM =$dbh->prepare("SELECT * FROM tbmeseros LEFT JOIN tbrestaurantes ON tbmeseros.rest_mesero = tbrestaurantes.id_restaurante WHERE tbmeseros.cad_mesero = ?");
$STM->bindParam(1, $cadena);
// For Executing prepared statement we will use below function
$STM->execute(array($cadena));
// we will fetch records like this and use foreach loop to show multiple Results
$STMrecords = $STM->fetchAll();
foreach($STMrecords as $row)
{
And here table's screenshots:
For tbmeseros:
For tbrestaurantes:
The value of $cadena is 'HQ3'.
When you put a parameter in the SQL, you need to supply the value for the parameter. There are two ways to do that:
1) Call bindParam():
$STM->bindParam(1, $cadana);
2) Provide the values when calling execute():
$STM->execute(array($cadana));
You need to fill the ? in the query:
$q = $dbh->prepare("SELECT * FROM tbmeseros LEFT JOIN tbrestaurantes ON tbmeseros.rest_mesero = tbrestaurantes.id_restaurante WHERE tbmeseros.cad_mesero = ?");
$q->bindValue( 1, 'x' );
$q->execute();
print_r( $q->fetchAll( PDO::FETCH_ASSOC );
In prepare you can use '?' and then bindValue to attach an escaped value to the query. Your query doesn't appear to have this and that is the cause of the error.

What is the fetch_array equivelant in prepared statements?

I use fetch_array(MYSQLI_ASSOC) with query but it doesn't work with prepared statements. What is the equivalent of that in prepared statements?
Here it is:
$query = "SELECT `users` FROM `table` WHERE `country` = :country";
$stmt = $pdo->prepare($query);
$stmt->execute(array(
':country' => $country
));
$result = $stmt->fetch(PDO::FETCH_ASSOC); // Here you define how results are fetched
or you can define default FETCH MODE to be an associate array, like this:
$pdo = new PDO(...);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$result = $stmt->fetch(); // The same thing now
In addition to the accepted PDO solution, here is one for mysqli:
The first thing to keep in mind is that mysqli prepared statements do not require results to be bound:
Instead of using bound results, results can also be retrieved through the mysqli_result interface. mysqli_stmt_get_result() returns a buffered result set.
So, for example:
$sql = 'SELECT * FROM mytable ORDER BY column LIMIT ?,' . SOME_CONSTANT;
Once you have bound and executed your statement, you can call get_result():
$stmt = $db->prepare($sql);
$stmt->bind_param('i', $int) || die($db->error);
$stmt->execute() || die($db->error);
$result = $stmt->get_result();
At this point we are functionally equivalent to:
if ($result = $db->query($sql)) {
And can call our familiar fetch_array:
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$results[] = $row;
}
Instead of closing the result as we would in the non-prepared equivalent, we close the statement:
$stmt->close();

Categories