A Strategy for using PDO? (Pushing results into an Array) - php

Here is my somewhat broken strategy
If it is a query with no input ( always the same ), just use query();
$results = $this->database_top->query( $query );
If a single row is returned and there is input, do the prep (not shown here) and use
$results = $pdoStatement->fetch(PDO::FETCH_ASSOC);
If multiple rows are returned and there is input,do the prep (not shown here) and use:
$results = $pdoStatement->fetchAll();
Problem I'm facing is that I need the first method to return an array or array of arrays like the second and third.
Prep looks like this FYI
$this->database_top->quote($query); // quote it
$pdoStatement = $this->database_top->prepare($query); // prepare it
$results = $pdoStatement->execute($parameterArray); // execute it
How can I modify my code so that all 3 methods return arrays or array of arrays?
Iterating over query()
$result_array = $this->DatabaseObject->_pdoQuery( 'multiple', 'tweet_model' );
foreach( $result_array as $array_1d )
{
$array_2d[]=$array_1d;
}

query does not return results, so I'm not sure what you meant on the first example. query returns a PDOStatement. It's basically the same as:
$qry = $db->query("...");
//equiv:
$qry = $db->prepare("...");
$qry->execute();
As vicTROLLA noted, the simplest solution is to just use:
$results = $stmt->fetch(PDO::FETCH_ASSOC);
However, if you need to process the results as you go for some reason, you could always loop over them manually.
$stmt = ...;
$results = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$results[] = $row;
}
//use or return $results
$results will thus always be an array with 0 or more arrays inside of it.
I find it useful to build arrays where the array key is the primary key of the record:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$results[$row['id']] = $row;
}
Also, I suspect that you've misunderstood the purpose and functionality of quote. It is used for escaping strings that you are going to interpolate into a query, not for magically escaping all values in a query (hence $db->quote($query) makes no sense).
Even worse is that drivers are not required to support quote. (Though it does at least return false if there's no support.)
prepare is massively preferred over quote.

In all of those cases, you can do
$arrayOfAssocArrays = $pdoStatement->fetchAll(PDO::FETCH_ASSOC);

Related

How to return empty array or resultset from a query with mysqli_fetch_all()?

My PHP code:
function get_something() {
global $link;
$sql = "SELECT * FROM new";
$result = mysqli_query($link, $sql);
$names = mysqli_fetch_all($result, MYSQLI_ASSOC);
return $names;
}
What is my problem:
When my table new is empty, I get the following error:
mysqli_fetch_all() expects parameter 1 to be mysqli_result`
If it isn't empty everything is working fine.
I need to check if my database is empty and if it's not, I will call mysqli_fetch_all. Otherwise, my function should return an empty array.
How is this possible to do?
Use mysqli_num_rows($result) to check how many rows were returned from the query. But if table new doesn't exist, $result will be false so we have to check that $result is valid as well:
if ($result && mysqli_num_rows($result) > 0)
$names = mysqli_fetch_all($result, MYSQLI_ASSOC);
else
$names = array();
return $names;
mysqli_fetch_all($result, MYSQLI_ASSOC) generates an indexed array of associative arrays. When there are no rows found, it will deliver an empty array (which is what you want). It is absolutely pointless to call mysqli_num_rows(), so don't make your script do any unnecessary work.
Furthermore:
many developers will advise you not to make global declarations to pass variables in your custom function scope. Instead, pass the connection variable into your function as a parameter.
I always try to avoid declaring single use variables. For your case, $sql and $names will only be used/referenced once after being declared, so just don't declare them.
As a matter of personal preference, I recommend using OO syntax with mysqli functions because it is less verbose, but in my following snippet I'll leave it like your original post.
Suggested Code:
function get_something($link) {
if (!$result = mysqli_query($link, "SELECT * FROM new")) {
return []; // check mysqli_error($link) because your query failed
}
return mysqli_fetch_all($result, MYSQLI_ASSOC);
}

Fetch multiple rows in mysql single query in php with different id

I have different id's, i am getting the values of these id from users
$id=array();
$id[0]=$_GET["id0"];
$id[1]=$_GET["id1"];
$id[2]=$_GET["id2"];
now to fetch data from database i am using following query:
for($j=0;$j<count($id);$j++)
{
$res=mysql_query("SELECT * FROM mutable WHERE id='$id[$j]'")
while($row=mysql_fetch_array($res))
{
$row[]=array("email"=>$row[2],"name"=>$row[3],"address"=>$row[5]);
echo JSON_encode($row);
}
}
now i am getting proper result from this query using for loop but the result is not in proper JSON format, is there any way to do it more efficentyly and getting proper result in JSON array and JSON object format
Place json_encode() outside of your loops.
Let's modernize and refine things...
*Unfortunately prepared statements that use an IN clause suffer from convolution. pdo does not suffer in the same fashion.
Code: (untested)
if(isset($_GET['id0'],$_GET['id1'],$_GET['id2'])){
$params=[$_GET['id0'],$_GET['id1'],$_GET['id2']]; // array of ids (validation/filtering can be done here)
$count=count($params); // number of ids
$csph=implode(',',array_fill(0,$count,'?')); // comma-separated placeholders
$query="SELECT * FROM mutable WHERE id IN ($csph)";
$stmt=$mysqli->prepare($query); // for security reasons
array_unshift($params,str_repeat('s',$count)); // prepend the type values string
$ref=[]; // add references
foreach($params as $i=>$v){
$ref[$i]=&$params[$i]; // pass by reference as required/advised by the manual
}
call_user_func_array([$stmt,'bind_param'],$ref);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_array(MYSQLI_NUM))
$rows=["email"=>$row[2],"name"=>$row[3],"address"=>$row[5]];
}
$stmt->close();
echo json_encode($rows);
}
Three things:
Always, always, always used prepared statements and bound parameters when dealing with untrusted (i.e., $_GET) input. Just do it.
As regards your problem with JSON, you only need to run json_encode once:
$results = [];
for($j=0;$j<count($id);$j++) {
...
while($row=mysql_fetch_array($res)) {
results[] = ...
}
}
json_encode( $results );
Use a single SQL statement, since you have a known number of IDs to collect:
$dbh = new PDO($dsn, $user, $password);
$sql = "SELECT * FROM mutable WHERE id IN (?, ?, ?)";
$sth = $dbh->prepare( $sql );
foreach ( $sth->execute( [$_GET['id0'], $_GET['id1'], $_GET['id2']] ) as $row ) {
...
This is more efficient then multiple round trips to the database. For this contrived case it probably doesn't matter, but getting into good habits now will serve you in the long run.
you have used $row wrongly, declare array variable outside of loop like
$json_response = array();
for($j=0;$j<count($id);$j++) {
$res=mysql_query("SELECT * FROM mutable WHERE id='$id[$j]'")
while($row=mysql_fetch_array($res)) {
$json_response[]=array("email"=>$row[2],"name"=>$row[3],"address"=>$row[5]);
echo json_encode($json_response); // not good to echo here
}
}
// echo json_encode($json_response); // ideally echo should be here

array_unique not removing duplicate values php

Sorry if this is a duplicate, I have tried searching but cannot seem to find an answer. I may just have the piece of code in the wrong place.
I have counted the duplicate values input from various select boxes, which were sent over via $_GET. Using these duplicates, if more than (whatever the set amount is) then it will run through a mysql query. This is all working fine.
The issue is that I need to remove duplicates that are returned from the mysql query. Here is my code:
if ($countGearSelected >= 2) {
$gearSets = array_keys(array_filter(array_count_values($_GET['gearPiece']), function($v) {
return $v > 1;
}));
foreach ($gearSets as $gearSetKey => $gearSetValue) {
$result = mysqli_query($con,"SELECT twoPieceBonus FROM sets WHERE setName='".$gearSetValue."';");
while($row = mysqli_fetch_array($result)){
$twoPieceBonus .= urldecode($row['twoPieceBonus']).'</br></br>';
}
$twoPieceBonus = implode(',',array_unique(explode(',', $twoPieceBonus)));
$twoSelected = substr($twoPieceBonus, 0, -10);
}
}else{
$twoSelected = '';
}
As you can see, I have tried the array_unique option on various other posts on SE but it doesn't appear to be working. I think I may be using it incorrectly?
Using DISTINCT doesn't work in the mysql query, as a few of the "sets" that are being queried have the same result (if that makes sense?).
Any help is very much appreciated.
First: your code is vulnerable to SQL injection: use prepared statements to avoid this.
Secondly, it is often a bad idea to execute a query in each iteration of a loop. And in this case it can be avoided. Instead of an equality comparison in your where clause, you could use the in operator and compare to all gear sets in one go.
This will also solve the matter of getting distinct values. With only one query executing, you can use distinct now.
Here is how the code would look like. I could not test this, but I expect mistakes (if any) can be easily fixed:
$twoSelected = '';
if ($countGearSelected >= 2) {
$gearSets = array_keys(array_filter(
array_count_values($_GET['gearPiece']), function($v) {
return $v > 1;
}
));
// Create comma separated list of question marks
$placeHolders = implode(",", array_fill(0, count($gearSets), "?"));
// Prepare SQL statement with it
$stmt = mysqli_prepare($con,
"SELECT DISTINCT twoPieceBonus
FROM sets
WHERE setName IN ($placeHolders);");
// All gearSet values are strings:
$types = str_repeat("s", count($gearSets));
// Turn the gearSets into references
$gearSetRefs = [];
foreach ($gearSets as $i => $_) {
$gearSetRefs[] = &$gearSets[$i];
}
// Bind arguments
mysqli_stmt_bind_param($stmt, $types, ...$gearSetRefs); // the splat operator
// Now we are all set to (safely) execute the query
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
// Let the result of the URL decoding still be an array
$twoPieceBonus = [];
while ($row = mysqli_fetch_array($result)) {
$twoPieceBonus[] = urldecode($row['twoPieceBonus']);
}
mysqli_stmt_close ($stmt);
// ... and then use implode to insert those HTML breaks
$twoSelected = implode("</br></br>", $twoPieceBonus);
}

While loop to display all data after SELECT query

I know this might be a very basic question, but I am new to php and databases, I'm trying to figure out a while condition that will keep while loop running until all (would be also nice to know how to do it for fixed amount) of data is taken form database.
$stmt = $db->prepare("SELECT * FROM icecreams");
$stmt -> execute();
$row = $stmt -> fetchAll(PDO::FETCH_ASSOC);
So now I need to figure out what while condition I need, the logic is
while (there is data to fetch) {
echo "<h1>$row['flavour']</h1>";
echo "...";
}
fetchAll() returns an array containing all of the result set rows, whereas fetch() returns a single row from the result-set.
fetchAll() Usage:
$array = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($array as $row) {
# code...
}
fetch() Usage:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
# code...
}
If you're going to use this for printing HTML, the second option seems nicer. For small recordsets, the performance difference shouldn't really matter, but if you're working with a lot of records, then fetchAll() might be a little slower, as it tries to map the entire data into a single array at once.
$stmt = $db->prepare("SELECT * FROM properties");
$stmt -> execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
//$row['column_name']
}
fetchAll does fetch everything as an associative array (as flag FETCH_ASSOC tells). It does it automatically for, you don't have to worry about it.
If you do this then you will see that you have all of your data in an array already:
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>'.print_r($row, true).'</pre>';
So now you can simply loop the items an access the data:
foreach($row as $k=>$v)
{
echo $k.'<br>'; // this will show you what row # you are on, sometimes useful :)
echo $v['title'].'<br>';
// etc....
}

PHP MySQLi prepared statements and fetching subset of columns

I am using MySQLi and PHP to call a stored MySQL routine with prepared statements. It returns a result set with dozens of columns.
$stmt = $dbconnection->prepare("CALL SomebodysDbProcedure(?);");
$stmt->bind_param("s", $idvalue);
$stmt->execute();
$stmt->bind_result($col1, $col2, $col3, ...);
However, I am only interested in a subset of the output columns.
The documentation says bind_result() is required to handle the complete set of returned columns:
Note that all columns must be bound after mysqli_stmt_execute() and
prior to calling mysqli_stmt_fetch().
Do I need to add code also for those columns I'm uninterested in? If so the application will break if the MySQL stored routine result set is expanded in the future, or even columns rearranged. Is there a workaround for this?
I'm assuming that you just don't want to write out all those variables for the bind_result() function. You could use a function like below instead of the bind_result() function. Pass it your $stmt object and you'll get back an array of standard objects with the fields you want.
function getResult($stmt)
{
$valid_fields = array('title', 'date_created'); // enter field names you care about
if (is_a($stmt, 'MySQLi_STMT')) {
$result = array();
$metadata = $stmt->result_metadata();
$fields = $metadata->fetch_fields();
for (; ;)
{
$pointers = array();
$row = new \stdClass();
$pointers[] = $stmt;
foreach ($fields as $field)
{
if (in_array($field->name, $valid_fields)) {
$fieldname = $field->name;
$pointers[] = &$row->$fieldname;
}
}
call_user_func_array('mysqli_stmt_bind_result', $pointers);
if (!$stmt->fetch())
break;
$result[] = $row;
}
$metadata->free();
return $result;
}
return array();
}
The answer of Jonathan Mayhak guided me in the right direction. On PHP bind_result page, nieprzeklinaj provides a function called fetch(). It works; use it like this:
$stmt = $conn->prepare("CALL SomebodysDbProcedure(?);");
$stmt->bind_param("s", $idvalue);
$stmt->execute();
$sw = (array)(fetch($stmt));
$s = $sw[0]; // Get first row
$dateCreated = $s['date_created']; // Get field date_created
Edit: Unfortunately successive calls within the same PHP file don't seem to work with this method.
Try using fetch_fields php method:
array mysqli_fetch_fields ( mysqli_result $result )
http://php.net/manual/en/mysqli-result.fetch-fields.php

Categories