Hello All,
I have a order form that is using a foreach loop with an array.

The loop displays correctly the first time it is displayed on the page, but when the totals are updated with the submit button the loop duplicates the second to last entry?
Here is a working example with errors noted.

And here is my page code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Foreach Loop Error</title>

  <link rel="stylesheet" type="text/css" href="wholesale_overall.css" />
</head>
<body>
<div id="container">

<?php
  echo '<h1>Foreach Loop Error</h1>';

require_once('connectvars.php');



$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); 

$items = array();

$query = mysqli_query( $dbc,"SELECT `ItemID`,`ItemName`,`ItemCat`,`ItemPrice`,`ItemAmount`,`ItemUnit` FROM `items` ORDER BY `ItemCat` ASC" );
while( list( $id,$name,$cat,$price,$amount,$unit ) = mysqli_fetch_array( $query ) ) {
	$items[$id] = array(
		'name'   => $name,
		'cat'    => $cat,
		'price'  => $price,
		'amount' => $amount,
		'unit'   => $unit,
		'id'     => $id
	);
}
	echo '<div id="form_box">';
	echo '<div id ="totalbox">';
if ( isset( $_POST['update'] ) ) {
    
	$total = 0;
	foreach( $_POST as $key => $value ) {
		list( ,$key ) = explode( '-',$key );
		$value = (int) $value;
		if ( isset( $items[$key] ) ) {
			$item =& $items[$key];
			$item['quantity'] = $value;
			$price = ( $item['price'] * $value );
			$tax_rate = 0.035;
			$item_tax = ($price * $tax_rate);
			$item_tax = number_format($item_tax, 2);
			if ($value != 0){
			echo "{$item['name']} / {$item['cat']} - \${$item['price']} x {$item['quantity']} = \${$price}<br />";
			}
			$total += $price;
			$tax += $item_tax;
			$grand_total = $tax + $total;
		}
	}
	echo "<p class=\"orderinfo\">Sub Total: \${$total}</p>";
	echo "<p class=\"orderinfo\">Tax: \${$tax}</p>";
	echo "<p class=\"orderinfo\">Grand Total: \${$grand_total}</p>";
	echo '<p  class="error">NOTE:Once the order has been submitted the last item in the loop is duplicated.  However if you enter a value in the last row and update the total again the correct price and product info is calculated for that row?</p>';
	
	
	
}

echo <<<HTML
	<form name="orderform" action="{$_SERVER['PHP_SELF']}" method="post">
HTML;
foreach( $items as $id => $item ) {
	if ( !isset( $item['quantity'] ) ) {
		$item['quantity'] = 0;
	}
	
	echo <<<HTML
		<div class="product_line">
			<div class="prod_name">{$item['name']} / {$item['cat']}</div>
			<div class="prod_price">\${$item['price']} ... per ... {$item['amount']} {$item['unit']}
				<label for="item-{$id}">Quantity:</label>
				<input type="text" name="item-{$id}" size="5" value="{$item['quantity']}" />
			</div>
		</div>

HTML;
}


?>

<br />
<input type="submit" name="update" value="Update Total" />

</form>
<a href="foreachlooperror.php">RESET FORM</a>
</div>
<?php
mysqli_close( $dbc );
?>
 </div> <!-- END OF CONTAINER DIV-->
</body>
</html>

Thanks for Looking!

Eric

zeusofolus,
Which foreach? Post only a section of source code where you got some problems.

I would think it would have to be in the foreach loop that runs when you click the submit button because when the page loads initially their is not a problem.

if ( isset( $_POST['update'] ) ) {
    
	$total = 0;
	foreach( $_POST as $key => $value ) {
		list( ,$key ) = explode( '-',$key );
		$value = (int) $value;
		if ( isset( $items[$key] ) ) {
			$item =& $items[$key];
			$item['quantity'] = $value;
			$price = ( $item['price'] * $value );
			$tax_rate = 0.035;
			$item_tax = ($price * $tax_rate);
			$item_tax = number_format($item_tax, 2);
			if ($value != 0){
			echo "{$item['name']} / {$item['cat']} - \${$item['price']} x {$item['quantity']} = \${$price}<br />";
			}
			$total += $price;
			$tax += $item_tax;
			$grand_total = $tax + $total;
		}
	}

If you want to narrow it down even further it has to do with this portion of the code

foreach( $_POST as $key => $value ) {
		list( ,$key ) = explode( '-',$key );
		$value = (int) $value;

Sorry it took me so long to reply. I have been busy.

Put:

echo '<pre>' . print_r( $_POST,true ) . '</pre>';

somewhere on the page to check to make sure the post data is correct.
Then put:

echo '<pre>' . print_r( $items,true ) . '</pre>';

towards the bottom of the code to make sure the items array is correct. I have a feeling that something is being overwritten and messing up the item array.

Keith,
Thanks again for looking at this ... I have experimented with the placement of the print code you posted and as far as I can tell the error occurres between when the submit button does the calculations and when the form is recreated by the initial foreach script.
If I place this at the end of the submit button code so to prevent the rest of the code from being run.

echo '<pre>' . print_r( $items,true ) . '</pre>';
exit()

then the printout shows all the correct data, but if I let the script run all the way back through the foreach loop show here

foreach( $items as $id => $item ) {
	if ( !isset( $item['quantity'] ) ) {
		$item['quantity'] = 0;
	}

then the data in the print out is wrong ... all but the products ID?

My understanding of how the code is processed is that all the code is run initially (with the exception of the code inside the if isset submit portion ) then when you click the submit button the code backs up and runs from that point thru the end of the script again.

So when the submit portion of the code has run the last item in the list is still set to the values

$item['name']} / {$item['cat']} - \${$item['price']} x {$item['quantity']} = \${$price}

so if you were to just

echo <<<HTML
		<div class="product_line">
			<div class="prod_name">{$item['name']} / {$item['cat']}</div>
			<div class="prod_price">\${$item['price']} ... per ... {$item['amount']} {$item['unit']}
				<label for="item-{$id}">Quantity:</label>
				<input type="text" name="item-{$id}" size="5" value="{$item['quantity']}" />
			</div>
		</div>

HTML;

Then you would get just the last entry of the form printed correctly. But somehow when the last part of the script is run before you echo the form

foreach( $items as $id => $item ) {
	if ( !isset( $item['quantity'] ) ) {
		$item['quantity'] = 0;
	}

The values of the last line are overwritten by the previous line ... almost as if the foreach loop did not know the values for that line so it just repeated the last known value and assigned them to the remaining ID in the database ... You seem to have a much better grasp on this than I do so I hope you might know a way we can force that last line of the loop to be remembered when the code echos the form with the (int) $values in it.

Thanks sorry to keep asking you about this but I have spent quite a few hours looking at this and need the help.

Eric

Try this:

foreach( $_POST as $key => $value ) {
		list( ,$key ) = explode( '-',$key );
		$value = (int) $value;
		if ( isset( $items[$key] ) ) {
			$items[$key]['quantity'] = $value;
			$price = ( $items[$key]['price'] * $value );
			$tax_rate = 0.035;
			$item_tax = ($price * $tax_rate);
			$item_tax = number_format($item_tax, 2);
			if ($value != 0){
			echo "{$items[$key]['name']} / {$items[$key]['cat']} - \${$items[$key]['price']} x {$items[$key]['quantity']} = \${$price}<br />";
			}
			$total += $price;
			$tax += $item_tax;
			$grand_total = $tax + $total;
		}
	}

I got rid of the reference I used, which could of been causing the problem. I am not sure if it will fix the problem, it might though.

I've read your code until here (as a learning excersise, lol) and if i understood you well:

list( ,$key ) = explode( '-',$key );

may be that's part of your problem: you have a comma at the left of $key, let me explain:

if you do something like

$links = array("www.hotmail.com", "mail.yahoo.com", "www.google.com");
list([B],[/B]$key) = $links;

means that:

$key = "mail.yahoo.com"

that is the second value of the array not the first one if that's what you intended.

Hope this helps.

Keith,
That solves the problem !!!
Thanks for helping me with this project ... (I think I should have tackled something a little more basic for my first php project would have saved me a few gray hairs) :)

Eric

This question has already been answered. Start a new discussion instead.