Breaking select query up

I have a select query whch eturns 55 results, how do I change it so that is returns groups of 5 so I can bvreak them up to be on the left/right so i dont just get 1 long line of reslts
Heres my query

$query = "SELECT beginning_slot, ending_slot, device FROM devices WHERE rack_id = ".$_GET['id']." AND display = 1";

this?

Can i put the results in a for loop or something?

yeah, that’s really a presentation issue (php), not a query issue (sql)

$_GET['id'] ="1; 
    UPDATE users SET password = 'password_hash' WHERE login = 'admin';
    SELECT * from devices WHERE id = 0 
" 

Use preparation/escaping!!!

Yes. You could loop through them and split them into separate arrays to then output to each div, for example, or if the sequence that the query returns them allows it, you could just detect when to switch to the “other” div.

I’m not sure exactly how you want to display them - you say you’ll get 55 back but want to split them into groups of five to display on the “left/right”, but do you mean that you also want to paginate - only show ten then have a “next” button? Or do you want 23 on the left and 22 on the right?

I am not sure if this is your requirements but at least it is a start:

<?php 
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'true');

$title = '__file__ ==> ' .__file__;

$hdr = <<< ____EOT
<!doctype html>
<html lang="en-GB">	
<head>
<title> $title </title>
<style>
  dl {	
  	margin: 0 2em 1em 1em;
  	float:left; 
  	border:solid 1px red;
  }
  dl dt {
  	font-weight: 700; 
  	background-color:#ddd;
  }
  dl dd {padding-right:1em;}
</style>	
</head>
<body>	
<h1> $title </h1>
<hr>
____EOT;
echo $hdr;

  for( $id = 0; $id<55; $id++):
	$idNext  = 1+$id;	
	$items[$id] = ['ending_slot_' .$id => 'device_'.$idNext];
  endfor;  


  foreach($items as $id => $value):
    if( 0=== $id % 5):
    	echo  '<dl>'
			. '<dt>$div ==> ' .$id .'</dt>';
    endif;
    echo '<dd>'.print_r($value, true) .'</dd>';

    if( 0=== ++$id % 5):
    	echo '<dd> &nbsp; </dd></dl>';
    endif;
  endforeach;

echo '</body></html>';  

Output:

https://www.php.net/manual/en/function.array-chunk.php
^
That, plus a quick array_map, or intelligent implode, will take care of it all.

2 Likes

Sorry John_Betong, I’m trying to learn the most efficient way to do this so im going to do this from scratch using m_hutley method…
I used array_chunk() to split the results into groups of 5

echo '<pre>';print_r(array_chunk($racks, 5));echo '</pre>';

But am lost how to use array_map() to put each array into a separate div

1 Like

Well don’t be too surprised that the ‘efficient’ method is doing pretty much exactly what John did, in the background, just with command names.

array_map takes two* parameters. A function, and array(s) to send to that function. It applies the Function to each member of the array(s). (Lambda functions may be useful here.)

implode takes a string and an array, and reduces it to the concatenated string made by inserting the input string between each element of the array.

This is a simple display issue easily handled with basic CSS using the columns property. Adjust columns and data source to your needs.

<style>
ul {
    columns: 5;
    -webkit-columns: 5;
    -moz-columns: 5;
    list-style-type:none;
}
</style>
<ul>
<?php
$arr = range('A','Z');
foreach($arr as $v){
echo "<li>$v</li>";
}
?>
</ul>

It could be.

What is the end result (HTML) you want out of this?

[off-topic]

:shudder:

the final output be looking for is something like

<div class="col-4">
    <a href="show_rack?id=1">Rack #1</a>
    <a href="show_rack?id=2">Rack #2</a>
    <a href="show_rack?id=3">Rack #3</a>
    <a href="show_rack?id=4">Rack #4</a>
    <a href="show_rack?id=5">Rack #5</a>
</div>
<div class="col-4">
    <a href="show_rack?id=6">Rack #6</a>
    <a href="show_rack?id=7">Rack #7</a>
    <a href="show_rack?id=8">Rack #8</a>
    <a href="show_rack?id=9">Rack #9</a>
    <a href="show_rack?id=10">Rack #10</a>
</div>
<div class="col-4">
    <a href="show_rack?id=11">Rack #11</a>
    <a href="show_rack?id=12">Rack #12</a>
    <a href="show_rack?id=13">Rack #13</a>
    <a href="show_rack?id=4">Rack #4</a>
    <a href="show_rack?id=5">Rack #5</a>
</div>
...
...

and those divs to keep looping till the racks in the table are no more
Is it best if I create a function that creates those links

function createLink($id, $title) {
    echo '<a href="show_rack.php?id='.$id.'">'.$title.'</a>';
}
``` then run each array through it like

array_map(“createLink”, $racks);

which makes a new array in groups of 5, then...

implode(“
”,$racks);

as the next step (right?)

I kind of like the column property in the CSS though, can I use that instead?

It looks to me like semantically this should be a single continuous list, in which case the suggestion by @benanamen is correct.

Are the divs only to force a column layout, or is there some distinction between the column groups that sets them apart from one another?

If it is one, not five different lists, then you should be using that method.

ok,as far as security goes, can I do this

$rack_id = filter_var($_GET['id'], FILTER_VALIDATE_INT)

to make sure I always get an integer?

to make sure I always get an integer?

Yes… Exactly in this moment, exactly with this variable. But that is no way permanent solution.

NO!

Double NO!

We are talking about IDs obviously consisting of only numbers. An ID is not an integer, it is a number normally starting at 1 and going up. You need to understand what a valid integer is.

Take a look at the following array values that are valid integers that would pass the filter test. Obviously, these would not normally be valid id’s.

$values = array(-23, 0b11111111, 0x1A, 0b11111111);
foreach ($values as $value) {
    if (filter_var($value, FILTER_VALIDATE_INT)) {
        echo 'Variable is an integer<br>';
    } else {
        echo 'Variable is not integer<br>';
    }
}

So what is the way to check for valid ID numbers only? is_numeric? No. ctype_digit? Closer, but no since an “id” of zero will validate. So what then? The sure fire way to valid ID’s consisting only of numbers starting with a 1 or greater is with a regex.

$str = '10';
if (preg_match('/^[1-9][0-9]?$/', $str)) {
echo 'Valid';
} else {
echo 'Not Valid';
}

Try to use the automatically generated integers in the for next loop I gave in my example and there is no reason to introduce another function to test for integer validation.

Also can you print_r($results); from the following and it will reduce incorrect assumptions. Only a couple of results are required.

<?php
declare(strict_types=1);

// ...
$query = "SELECT beginning_slot, ending_slot, device FROM devices WHERE rack_id = ".$_GET['id']." AND display = 1";

$product = mysqli_query($conn, $query);
$results = array();
while($pro = mysqli_fetch_assoc($product)) {
    $results[] = $pro;
}

If that is all that is required then there is no need to complicate the issue with the results from a database query.

A simple for next loop from 0 to < 55 and use the modulus operator.

My philosophy about coding is to first get it to work, validate for extreme cases and afterwards (if time allowed) try to optimise.

What I used to do way back before I discovered prepared statements was to do a preg_replace on the ID.

$id = preg_replace('#[^0-9]#', '', $_GET[id]) ;

Which would just strip out anythingthing that was non-numeric.
Can’t say I ever had any problems while using that, but I always use prepared statements now for user variables.

The difference from what I posted is your regex is sanitizing bad data while the regex I posted is validating good data. Two different things. You really shouldn’t be changing user supplied data to make it “good data”. If it is bad, it should just fail validation.

Even after passing through the sanitizing you could still end up with an invalid ID format requiring even more code to validate the changed data. Your regex would allow for an ID starting with one or more leading zero’s which is not the norm for ID’s.

Take a look at your regex with bad data. It does strip everything but numbers but you could still be left with an id with one or more leading zeros.

$_GET['id'] = 'sakjh005x';
echo $id = preg_replace('#[^0-9]#', '', $_GET['id']) ;
1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.