Problem with while loop

I have a little panel on the site’s home page which should show news items recently submitted. If there are no news items, the panel is not shown. There is a form which sends an item to a DB table. This works, I have checked the DB, so no problem there.
Back on the home page, the panel is only showing one news item (there are two) and I am sure the problem lies with my while loop:

<?php
include('navbar.html');
include('joinin.inc.php');
$conn = dbconnect('query');
	$sql = 'select * from news order by newsdate limit 3';
	$res = $conn->query($sql);
	$row = mysqli_fetch_assoc($res);
	$thehead = $row['heading'];
	$thetext = $row['newsitem'];
	$numrows = $res->num_rows;
	$style = "";
if ($numrows==0){$style = " style='display:none;'";}	
//ensures if the count is zero the panel is not shown
?>

//simple html here, no PHP

//the panel
<div style="position:absolute ; left:80% ; top:100px ; width:18% ; height:auto ;  color:white" <?php echo $style;?>>
	<h2 style="color:red">Latest News</h2>
	<?php
	while($row = $res->fetch_assoc())
	{?>
	<h3 style="color:darkseagreen;"><?php echo ucwords($thehead);?></h3>
<span style="font-size:90%;line-height:1.4;padding:0 20px 10px 0 ; margin-top:-12px; display:inline-block">
<?php echo $thetext;}?></span><br/>
</div>
//end of panel

I have run this through a PHP checker and it finds no errors.

This code is out of order and makes no sense. Long before it gets to the while() loop, it’s fetching a row of data, (needlessly) assigning two variables to other variables, then checking if there were any rows of data. The while() loop code isn’t doing anything with the data it fetches, so it would reuse the data from the first fetch statement every pass through the loop. The loop ends at the wrong point and is only outputting the closing span tag and br tag after the end of the loop.

I recommend that you separate the database specific code, that knows how to query for and fetch the data, from the presentation code, that knows how to produce the output from the data. This removes the php business logic from the html document. The code for any page should be laid out in this general order -

  1. initialization
  2. post method form processing
  3. get method business logic - get/produce data needed to display the page
  4. html document

Some other points for the posted code -

  1. Use ‘require’ for things your code must have.
  2. Include/require are not functions. The () around the path/filename don’t do anything and should be left out.
  3. If a query doesn’t match any data, you should output a message stating so, instead of outputting nothing.
  4. The html markup is broken, both for the case of no data being displayed and there being data. You need to validate the resulting web page at validator.w3.org
  5. If you use php’s short-open-print tag <?= and leave out the closing ; right before a closing php tag, you can echo values in the html document using simple syntax like `<?=$var?>`
  6. Don’t copy variables to other variables for nothing. Just use the original variable that data is in.
  7. Don’t use multiple names for the same piece of data.
  8. You need to list out the columns you are SELECTing in a query.
  9. You need to apply htmlentities() to any dynamic value being output in a html context to prevent any html entity from being able to break the html markup.

Once you do these things, you should end up with code that looks like this -

<?php
// 1. initialization

require 'joinin.inc.php';
$conn = dbconnect('query');

// 2. post method form processing
// 3. get method business logic - get/produce data needed to display the page

$sql = 'select heading, newsitem from news order by newsdate limit 3';
$res = $conn->query($sql);

// fetch all the data from the query into an appropriately named variable
$news_data = [];
while($row = $res->fetch_assoc())
{
	$news_data[] = $row;
}
// you can examine $news_data here to make sure it contains what you expect
	
// 4. html document
require 'navbar.html';

if(empty($news_data))
{
	// produce the output you want when there is no data to display
	
}
else
{
	// produce the output when there is data to display
	?>
	<div style="position:absolute ; left:80% ; top:100px ; width:18% ; height:auto ;  color:white">
	<h2 style="color:red">Latest News</h2>
	<?php
	foreach($news_data as $row)
	{
		// apply htmlentities() to all elements in $row
		$row = array_map('htmlentities',$row);
		?>
		<h3 style="color:darkseagreen;"><?=ucwords($row['heading'])?></h3>
		<span style="font-size:90%;line-height:1.4;padding:0 20px 10px 0 ; margin-top:-12px; display:inline-block"><?=$row['newsitem']?></span><br>
	<?php
	}
	?>
	</div>
<?php
}
?>

Huge thanks for all this, sometimes you make me feel like the boy in the corner of the classroom with the pointy hat on (in a good way!)
As this particular thing isn’t urgent I shall leave until after the holiday - in which connection I wish you, my helpful friend, a happy xmas!
Mike

OK, having taken your advice I delineated the code blocks in better, discrete ways, simplified, verified, structured the html / php and voila! Everything works properly now.
So many thanks for your patience and guidance. Happy new year!

Sponsor our Newsletter | Privacy Policy | Terms of Service