PHP - Binding array of strings to IN() clause using PDO - php

I am struggling to bind an array of strings to an IN() clause in a MySQL statement. I have found a lot of info on this with regards to integers, but all using methods which don't work with strings.
Here's my code so far:
$dbconnect = new PDO(...);
$brands = array('Nike', 'Adidas', 'Puma');
$i = 1;
try {
$dbconnect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$data = $dbconnect->prepare("SELECT * FROM clothing WHERE brand IN (:brands)");
$data->bindParam(':brands', $brands);
$data->execute();
while($row = $data->fetch()) {
echo $i++ . " - ". $row['brand'] . "<br>";
}
} catch(PDOException $er) {
echo 'Error: ' . $er->getMessage();
}
Thanks in advance for any help!

I like to loop through and create an associative array of the values. Then concatenate the keys to a string of params to bind. Then loop through the associative array to bind them to the prepared statement. Something along the following (there may be some syntax errors, but this is the gist):
$in_clause_array = array();
foreach($brands as $index => $brand) {
$in_clause_array[':brand_'.$index] = $brand;
}
//Below creates a string like ":brand_1 , :brand_2 , :brand_3"
$in_clause_string = implode(" , ", array_keys($in_clause_array));
$data = $dbconnect->prepare("SELECT * FROM clothing WHERE brand IN ( $in_clause_string )");
//now bind the params to values in the associative array
foreach($in_clause_array as $key=>$brand) {
$data->bindValue("$key", $brand);
}

$array_fields = array();
$i=0;
$res = $db->query("yourkey ".TABLE_ADS);
while($row = mysql_fetch_row($res)) {
$array_fields[$i] = $row[0];
$i++;
}

Related

Is there any option to get column names in empty table mysql pdo? [duplicate]

How can I get all the column names from a table using PDO?
id name age
1 Alan 35
2 Alex 52
3 Amy 15
The info that I want to get are,
id name age
EDIT:
Here is my attempt,
$db = $connection->get_connection();
$select = $db->query('SELECT * FROM contacts');
$total_column = $select->columnCount();
var_dump($total_column);
for ($counter = 0; $counter < $total_column; $counter ++) {
$meta = $select->getColumnMeta($counter);
$column[] = $meta['name'];
}
print_r($column);
Then I get,
Array
(
[0] => id
[1] => name
[2] => age
...
)
I solve the problem the following way (MySQL only)
$q = $dbh->prepare("DESCRIBE tablename");
$q->execute();
$table_fields = $q->fetchAll(PDO::FETCH_COLUMN);
This will work for MySQL, Postgres, and probably any other PDO driver that uses the LIMIT clause.
Notice LIMIT 0 is added for improved performance:
$rs = $db->query('SELECT * FROM my_table LIMIT 0');
for ($i = 0; $i < $rs->columnCount(); $i++) {
$col = $rs->getColumnMeta($i);
$columns[] = $col['name'];
}
print_r($columns);
My 2 cents:
$result = $db->query('select * from table limit 1');
$fields = array_keys($result->fetch(PDO::FETCH_ASSOC));
And you will get the column names as an array in the var $fields.
$sql = "select column_name from
information_schema.columns where
table_name = 'myTable'";
PHP function
credits : http://www.sitepoint.com/forums/php-application-design-147/get-pdo-column-name-easy-way-559336.html
function getColumnNames()
{
$sql = "SELECT column_name FROM information_schema.columns WHERE table_name = 'myTable'";
#$sql = 'SHOW COLUMNS FROM ' . $this->table;
$stmt = $this->connection->prepare($sql);
try {
if ($stmt->execute())
{
$raw_column_data = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($raw_column_data as $outer_key => $array)
{
foreach($array as $inner_key => $value
{
if (!(int)$inner_key)
{
$this->column_names[] = $value;
}
}
}
}
return $this->column_names;
}
catch (Exception $e)
{
return $e->getMessage(); //return exception
}
}
Here is the function I use. Created based on #Lauer answer above and some other resources:
//Get Columns
function getColumns($tablenames) {
global $hostname , $dbnames, $username, $password;
try {
$condb = new PDO("mysql:host=$hostname;dbname=$dbnames", $username, $password);
//debug connection
$condb->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$condb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// get column names
$query = $condb->prepare("DESCRIBE $tablenames");
$query->execute();
$table_names = $query->fetchAll(PDO::FETCH_COLUMN);
return $table_names;
//Close connection
$condb = null;
} catch(PDOExcepetion $e) {
echo $e->getMessage();
}
}
Usage Example:
$columns = getColumns('name_of_table'); // OR getColumns($name_of_table); if you are using variable.
foreach($columns as $col) {
echo $col . '<br/>';
}
This is an old question but here's my input
function getColumns($dbhandle, $tableName) {
$columnsquery = $dbhandle->query("PRAGMA table_info($tableName)");
$columns = array();
foreach ($columnsquery as $k) {
$columns[] = $k['name'];
}
return $columns;
}
just put your variable for your pdo object and the tablename. Works for me
This approach works for me in SQLite and MySQL. It may work with others, please let me know your experience.
Works if rows are present
Works if no rows are present (test with DELETE FROM table)
Code:
$calendarDatabase = new \PDO('sqlite:calendar-of-tasks.db');
$statement = $calendarDatabase->query('SELECT *, COUNT(*) FROM data LIMIT 1');
$columns = array_keys($statement->fetch(PDO::FETCH_ASSOC));
array_pop($columns);
var_dump($columns);
I make no guarantees that this is valid SQL per ANSI or other, but it works for me.
PDOStatement::getColumnMeta()
As Charle's mentioned, this is a statement method, meaning it fetches the column data from a prepared statement (query).
I needed this and made a simple function to get this done.
function getQueryColumns($q, $pdo){
$stmt = $pdo->prepare($q);
$stmt->execute();
$colCount = $stmt->columnCount();
$return = array();
for($i=0;$i<$colCount;$i++){
$meta = $stmt->getColumnMeta($i);
$return[] = $meta['name'];
}
return $return;
}
Enjoy :)
A very useful solution here for SQLite3. Because the OP does not indicate MySQL specifically and there was a failed attempt to use some solutions on SQLite.
$table_name = 'content_containers';
$container_result = $connect->query("PRAGMA table_info(" . $table_name . ")");
$container_result->setFetchMode(PDO::FETCH_ASSOC);
foreach ($container_result as $conkey => $convalue)
{
$elements[$convalue['name']] = $convalue['name'];
}
This returns an array. Since this is a direct information dump you'll need to iterate over and filter the results to get something like this:
Array
(
[ccid] => ccid
[administration_title] => administration_title
[content_type_id] => content_type_id
[author_id] => author_id
[date_created] => date_created
[language_id] => language_id
[publish_date] => publish_date
[status] => status
[relationship_ccid] => relationship_ccid
[url_alias] => url_alias
)
This is particularly nice to have when the table is empty.
My contribution ONLY for SQLite:
/**
* Returns an array of column names for a given table.
* Arg. $dsn should be replaced by $this->dsn in a class definition.
*
* #param string $dsn Database connection string,
* e.g.'sqlite:/home/user3/db/mydb.sq3'
* #param string $table The name of the table
*
* #return string[] An array of table names
*/
public function getTableColumns($dsn, $table) {
$dbh = new \PDO($dsn);
return $dbh->query('PRAGMA table_info(`'.$table.'`)')->fetchAll(\PDO::FETCH_COLUMN, 1);
}
Just Put your Database name,username,password (Where i marked ?) and table name.& Yuuppiii!.... you get all data from your main database (with column name)
<?php
function qry($q){
global $qry;
try {
$host = "?";
$dbname = "?";
$username = "?";
$password = "?";
$dbcon = new PDO("mysql:host=$host;
dbname=$dbname","$username","$password");
}
catch (Exception $e) {
echo "ERROR ".$e->getMEssage();
}
$qry = $dbcon->query($q);
$qry->setFetchMode(PDO:: FETCH_OBJ);
return $qry;
}
echo "<table>";
/*Get Colums Names in table row */
$columns = array();
$qry1= qry("SHOW COLUMNS FROM Your_table_name");
while (#$column = $qry1->fetch()->Field) {
echo "<td>".$column."</td>";
$columns[] = $column;
}
echo "<tr>";
/* Fetch all data into a html table *
/
$qry2 = qry("SELECT * FROM Your_table_name");
while ( $details = $qry2->fetch()) {
echo "<tr>";
foreach ($columns as $c_name) {
echo "<td>".$details->$c_name."</td>";
}
}
echo "</table>";
?>
$q = $dbh->prepare("DESCRIBE tablename");
$q->execute();
$table_fields = $q->fetchAll(PDO::FETCH_COLUMN);
must be
$q = $dbh->prepare("DESCRIBE database.table");
$q->execute();
$table_fields = $q->fetchAll(PDO::FETCH_COLUMN);
There is no need to do a secondary query. Just use the built in oci_field_name() function:
Here is an example:
oci_execute($stid); //This executes
echo "<table border='1'>\n";
$ncols = oci_num_fields($stid);
echo "<tr>";
for ($i = 1; $i <= $ncols; $i++) {
$column_name = oci_field_name($stid, $i);
echo "<td>$column_name</td>";
}
echo "</tr>";
while ($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
echo "<tr>\n";
foreach ($row as $item) {
echo " <td>" . ($item !== null ? htmlentities($item, ENT_QUOTES) : " ") . "</td>\n";
}
echo "</tr>\n";
}
echo "</table>\n";

How to prepared statement for IN clause if there is mixed type array?

I am trying to write prepared statement for IN clause where array is mixed array. i am able to build array for 'call_user_func_array()' but i am not able to prepare statement. no output is showing.
this is my php code:
$search1 = array('pune','india','2014','mumbai','2015');
print_r($search1);
echo $param = implode(",",$search1);
$ids = array_flip(array_flip(explode(',', $param)));
var_dump($ids);
$type1 = array();
foreach ($ids as $element) {
if(is_string($element)) {
$type1[] ='s';
}elseif(is_int($element)) {
$type1[] ='i';
}
}
print_r($type1);
echo $type=implode("",$type1);
$inputArray[] = &$type;
$j = count($ids);
for($i=0;$i<$j;$i++){
$inputArray[] = &$ids[$i];
}
print_r($inputArray);
echo $clause = implode(',', array_fill(0, count($ids), '?'));
$construct .="(city in ('.$clause.') or state in ('.$clause.')
or country in ('.$clause.')) AND year in ('.$clause.') order by year desc";
$constructs ="SELECT * FROM info WHERE $construct";
if($stmt1 = mysqli_prepare($conn, $constructs)){
call_user_func_array(array($stmt1,'bind_param'),$inputArray);
if(mysqli_stmt_execute($stmt1)){
$result = mysqli_stmt_get_result($stmt1);
if(mysqli_num_rows($result) > 0){
echo $foundnum = mysqli_num_rows($result);
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)){
echo $id = $row['id'];
echo $name = $row['name'];
}
}
}
}
mysqli_stmt_close($stmt1);
please tell me what i am doing wrong here.
100% Tested and Successful Code:
$search1 = ['2014','pune','india','2014','mumbai','2015','mumbai'];
// Separate logically and remove duplicates
foreach ($search1 as $value) {
if (strlen($value)==4 && ctype_digit($value)) { // qualifies for the year column
$years[$value] = null;
} else {
$strings[$value] = null;
}
}
$years = array_keys($years); // move keys to values
$years_count = sizeof($years);
$strings = array_keys($strings); // move keys to values
$strings_count = sizeof($strings);
if (!$years_count || !$strings_count) { // this is a matter of program logic
echo "A minimum of one year value and one non-year value is required for search functionality.";
}elseif (!$conn = new mysqli("host", "user","pass","db")) {
echo "Database Connection Error: " , $conn->connect_error; // don't show to the public
} else {
$years_csph = implode(',', array_fill(0, $years_count, '?')); // comma-separated placeholders
$strings_csph = implode(',', array_fill(0, $strings_count, '?')); // comma-separated placeholders
$total_count = $strings_count * 3 + $years_count;
$total_params = array_merge($strings, $strings, $strings, $years);
$param_string = str_repeat('s', $strings_count * 3) . str_repeat('i', $years_count); // write s chars before i chars
if(!$stmt = $conn->prepare("SELECT id, name FROM info WHERE (city IN ($strings_csph) OR state IN ($strings_csph) OR country IN ($strings_csph)) AND year IN ($years_csph) ORDER BY year DESC")) {
echo "Syntax Error # prepare: " , $conn->error; // don't show to public
}else{
array_unshift($total_params, $param_string); // prepend the type values string
$ref = []; // add references
foreach ($total_params as $i => $v) {
$ref[$i] = &$total_params[$i]; // pass by reference as required/advised by the manual
}
call_user_func_array([$stmt, 'bind_param'], $ref);
if (!$stmt->execute()) {
echo "Error # bind_param/execute: " , $stmt->error; // don't show to public
} elseif (!$stmt->bind_result($id, $name)) {
echo "Error # bind_result: " , $stmt->error; // don't show to public
} else {
while ($stmt->fetch()) {
echo "<div>$id : $name</div>";
}
$stmt->close();
}
}
}
Among other potential problems, '.$clause.' didn't look good because it was writing single quotes and dots around your placeholders. Placeholder never need single quoting and that syntax would have been incorrect even if they did.

Running MySQL queries inside a loop

I want to run multiple mysql queries in a loop. Maybe this the wrong approach but thats why I'm asking.
Example:
A user submits a array of userinput and i want loop through it an perform multiple mysql queries. If I hardcode the ID it works but if I set the ID as a VAR it dosen't. When using a VAR it alway shows a result with the last entry.
Best, Tim
if(isset($_POST['list'])){
$list=$_POST['list'];
$list_arr=explode(PHP_EOL, $list);
$list_arr_len=count($list_arr);
for ($i=0; $i < $list_arr_len; $i++) {
echo $list_arr[$i]."<br>";
$result = mysqli_query($con,"SELECT col FROM table where id='$list_arr[$i]'");
$row=mysqli_fetch_array($result,MYSQLI_NUM);
echo $row[0]."<br>";
}
mysqli_close($con);
}
You can do it in one query like this:
if(!empty($_POST['list'])){
$list=$_POST['list'];
$list_arr=explode(PHP_EOL, $list);
$list_id=implode("', '", array_map('mysqli_real_escape_string', $list_arr));
$result = mysqli_query($con,"SELECT col FROM table where id IN ('{$list_id}')");
while($row=mysqli_fetch_array($result,MYSQLI_NUM)) {
echo $row[0]."<br>";
}
mysqli_close($con);
}
in this example no matter which type of colum for id u use
Create PDO object and set it in exception mode
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
try
{
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
echo 'Connection failed: ' . $e->getMessage();
}
You are posting a comma separated list (I'd post an array but what the hell), so we're going to simply parse the string into integers and stick it in MySQL's IN clause
if(isset($_POST['list']))
{
$list = str_replace(["\r", "\n"], "", $_POST['list']);
$numbers = strpos($list, ',') !== false ? explode(",", $list) : (int)$list;
// This can probably bet written nicer, the idea is to have each number explicitly typecast to int so it's safe to stick in a query directly
// Basically, you want "1,2,3,4,5" without the possibility of having some bad input here
if(is_array($numbers))
{
$numbers = implode(",", array_map(function($number)
{
return (int)$number;
}, $numbers));
}
// And the nice, one liner, where you query and fetch the records which are now in the array called $records
$records = $pdo->query(sprintf("SELECT * FROM your_table WHERE id IN(%s)", $numbers))->fetchAll(PDO::FETCH_ASSOC);
}
Note: I didn't test the code so don't copy paste it, it most likely contains errors. I wrote the answer to show how easy it is to use PDO and retrieve results easily, in one liner.
I think this shall work:
$result = mysqli_query($con,"SELECT col FROM table where id=".mysqli_real_escape_string($list_arr[$i])."");
First Create a string of all the ids and use IN(String of Ids) in your query and store all the data corresponding to id in an array.
$stringIds = "";
for ($i=0; $i < $list_arr_len; $i++)
{
if (is_null($stringIds))
{
$stringIds = '"' . $list_arr[$i] . '"';
}
else
{
$stringIds .= ',"' . $list_arr[$i] . '"';
}
}
$resulSet = mysqli_query($con, ""SELECT col FROM table where id='?'"");
while($row = mysqli_fetch_assoc($resulSet))
{
mainArray[$row['id']] = $row;
}
Now, your able to fetch all your data from the array using foreach loop and please use PDO to avoid SQL Injection.
Problem was:
\n \r
This c0de works for me now ( also IN('') might be the better idea ):
if(isset($_POST['list'])){
$list=$_POST['list'];
//echo $list;
$replace = array("\n", "\r");
$id = str_replace( $replace, ",", $list);
$id_arr = explode(",", $id);
$id_arr_len = count($id_arr);
for ($i=0; $i < $id_arr_len; $i++) {
# code...
$result = mysqli_query($con,"SELECT col1,col2 FROM table where id='$id_arr[$i]'");
while($row = mysqli_fetch_assoc($result)){
echo $row['col1'].': ';
echo $row['col2'].'<br/>';
}
}
}

Insert sql query result to a new query

So the task is:
Do a query like Select * from table.
Take some cell value
Insert this value to a new query.
What do I have so far:
$Conn = odbc_connect("...");
$Result = odbc_exec("Select ...");
while($r = odbc_fetch_array($Result))
// showing result in a table
Here it looks like I should use the r array and insert data like
$var = r['some_field'];
$query = 'Select * from table where some_field = {$var}";
But how can I fill this array with values and how to make it available out of while loop?
Here I'm using odbc, but it doesn't matter, I need the algorithm. Thanks.
The whole code looks like:
<?php
$data = array();
$state = 'false';
if($_REQUEST['user_action']=='')
{
$Conn = odbc_connect("...");
$data = array();
if($_REQUEST['name']!='')
{
$Result = odbc_exec($Conn, "select ...");
//Showing result table
while($r = odbc_fetch_array(Result))
{
array_push($data, $r['cardgroup']);
$state = 'true';
}
// print_r($data); WORKS;
}
}
if ($_REQUEST['user_action'] == 'action1')
{
//I need to use $data HERE. Doesn't work
// $state = 'false' here...
}
?>
Define array outside while loop
$data = array();//defining
while($r = odbc_fetch_array($Result))
use array_push() inside while loop
array_push($data, $r['some_field']);
then try to print array of complete data outside loop
print_r($data);
Updates
Place $data = array(); at the top of first IF statement. Try this code:
$data = array();//at top
if($_REQUEST['user_action']=='')
{
$Conn = odbc_connect("...");
if($_REQUEST['name']!='')
{
$Result = odbc_exec($Conn, "select ...");
//Showing result table
while($r = odbc_fetch_array(Result))
{
array_push($data, $r['cardgroup']);
}
// print_r($data); WORKS;
}
}
if ($_REQUEST['user_action'] == 'action1')
{
//print_r($data) works here also
}
try something like this to store data in array
$allrows = array();
while($r = odbc_fetch_array( $result )){
$allrows[] = $r;
}
use foreach loop to print or use as per your choice
foreach($allrows as $singlerow) {
//use it as you want, for insert/update or print all key value like this
foreach($singlerow as $key => $value) {
//echo $key . '=='. $value;
}
}
You can try this as i understand your query hope this is your answer
$arr ='';
while($row = odbc_fetch_array($Result)) {
$arr .= '\''.$row['some_field'].'\',';
}
$arr = trim($arr, ",");
$query = "SELECT * from table where some_field IN ($arr)";
Your all task can be completed in single query
INSERT INTO table2 (col1, col2, ..., coln)
SELECT col1, col2, ..., coln
FROM table1

PDO Prepared Statement not returning results

I've been trying to get a proof-of-concept together all day using mysqli's prepared statements but have since decided to for PDO due to it's ability to bind values -- I believe i need them due to the dynamic nature of my queries.
The form behind the scenes is like so: http://pasteboard.co/k6H0cVq.png - You can also get an idea of the concept here. My query is returning no results or errors, just a warning Array to string conversion - which occurs when binding the values.
I am also worried that my binding of the value aren't working, i can't put them in the foreach loop as it can't be situated before the $stmt variable is called, otherwise even more errors are thrown out.
I've been reading docs and watching tutorials but i can't find anything which shows how to implement a model where the queries are dynamic.
I hope i'm clear enough, it's been a frustrating endeavour trying to get my head around PDO and prepared statements in general.
Any help is much appreciated.
Thanks!
PHP
if (isset($_POST['platform'], $_POST['bandwidth'], $_POST['price'])){
$platform = $_POST['platform'];
$bandwidth = $_POST['bandwidth'];
$price = $_POST['price'];
$query = "SELECT * FROM 'hosts' WHERE";
foreach($platform as $platform) {
$query .= " 'platform' LIKE %:platform% OR";
}
$query = substr($query, 0, -2);
foreach($bandwidth as $bandwidth) {
$query .= " AND 'bandwidth' BETWEEN :bandwidth OR";
}
$query = substr($query, 0, -2);
foreach($price as $price) {
$query .= " AND 'price' BETWEEN :price OR";
}
$query = substr($query, 0, -2);
$conn = new PDO('mysql:host=127.0.0.1; dbname=test', 'root', '');
$stmt = $conn->prepare($query);
if ($_POST['platform']){
$stmt->bindValue(':platform', $_POST['platform']);
}
if ($_POST['bandwidth']){
$stmt->bindValue(':bandwidth', $_POST['bandwidth']);
}
if ($_POST['price']){
$stmt->bindValue(':price', $_POST['price']);
}
$stmt->execute();
foreach($stmt as $row) {
print_r($row);
}
}
Here's a rewrite of your code. I use arrays to build up the nested AND and OR conditions, using implode to combine them, rather than sequences of string concatenation. I give each placeholder a different name, using the array index. I changed all your BETWEEN clauses to = because BETWEEN requires two parameters, a beginning and end of the range.
if (isset($_POST['platform'], $_POST['bandwidth'], $_POST['price'])){
$platform = $_POST['platform'];
$bandwidth = $_POST['bandwidth'];
$price = $_POST['price'];
$query = "SELECT * FROM hosts";
$ands = array();
$bind_array = array();
$ors = array();
foreach($platform as $i => $platform) {
$ors[] = "platform LIKE CONCAT('%', :platform{$i}, '%')";
$bind_array[":platform{$i}"] = $platform;
}
if ($ors) {
$ands[] = "(" . implode(" OR ", $ors) . ")";
}
$ors = array();
foreach($bandwidth as $i => $bandwidth) {
$ors[] = "bandwidth = :bandwidth{$i}";
$bind_array[":bandwidth{$i}"] = $bandwidth;
}
if ($ors) {
$ands[] = "(" . implode(" OR ", $ors) . ")";
}
$ors = array();
foreach($price as $i => $price) {
$ors[] = "price = :price{$i}";
$bind_array[":price{$i}"] = $price;
}
if ($ors) {
$ands[] = "(" . implode(" OR ", $ors) . ")";
}
if ($ands) {
$query .= " WHERE " . implode(" AND ", $ands);
}
$conn = new PDO('mysql:host=127.0.0.1; dbname=test', 'root', '');
$stmt = $conn->prepare($query);
$stmt->execute($bind_array);
foreach ($stmt as $row) {
print_r($row);
}
}
UPDATE:
If you have two parameters price1[] and price2[] for a range, change the price loop to:
foreach($price1 as $i => $price) {
$ors[] = "price BETWEEN :pricelow{$i} AND :pricehigh{$i}";
$bind_array[":pricelow{$i}"] = $price;
$bind_array[":pricehigh{$i}"] = $price2[$i];
}
I'm afraid you can't iterate over the statement as you're trying to do. Instead use the fetch method to access the results of the query:
while ($row = $stmt->fetch([fetch mode, e.g., PDO::FETCH_ASSOC])) {
print_r($row);
}
Regarding the "Array to string conversion" error you get, I suspect that one or more of the POST variables is in fact an array. To test this hypothesis, try print_r($_POST).

Categories