Adding discount code system to cart

Can I attach my cart.php file for you to get a better picture?

I need more info.

I need to know the inputs and outputs as well as see the code it follows through on how this gets to the error state.

What value does $cartTotal have when it holds a non numeric value?

I can not see the non numeric value. I will attach the file for your attention and your help will be appreciated.
I have never used any help sites before and this is the first time, so please forgive me if there are any typos etc.temp home page as I am still developing the site
I can not see where to attach the file, so please advice.

You can add anything into the cart and use a code like

test

in the “enter a discount code area”

copy it and paste it in.

It is saying new user can only put 2 links and one picture in the posts.

include "storeadmin/connect_to_mysql.php";  
$cartOutput = "";
$cartOutput2 = "";
$message1 = "";
$message2 = "";
$cartTotal = 0;
$pp_checkout_btn = '';
$product_id_array = '';
$itemsTotal = '';
//$discountamt = 0;

if (!isset($_SESSION["cart_array"]) || count($_SESSION["cart_array"]) < 1) {
	// when cart empty display just top bar and bar your cart is empty.
    
	$cartOutput2 .= '<div id="shoppingcrtb" style=""><p>Shopping Basket</p></div>    	
					<div class="cartemptybarb" style=""><h9>You have no items in your shopping basket</h9></div>
  					<!-- <div id="pageContent"> -->
  					<div style="margin:0 0 0 0px; text-align:left;"> 
  						<br /> 
					<div id="contshopping">
					<div class="contshoppingbar"><a href="http://www.magic-makeup.co.uk/indexN.php"><h9>Continue shopping</h9></a></div>					
					</div>	
  					<div id="shoppingcartmenu" style="display:none;"> 
  					<div id="shoppingcrtc" style=""><p>Shopping Basket</p></div>
					<div id="cartheading">
					<div class="cartproduct"><p>Product</p></div>
					<div class="cartunitprice"><p>Unit Price</p></div>	
					<div class="cartquantity"><p>Quantity</p></div>	   
					<div class="carttotal"><p>Total</p></div>
				   	<div class="cartremove"><p>Remove</p></div>	   
					</div>
					<div id="cartproduct">
				   	<div class="product">product</div>
				   	<div class="productdesc">productdesc</div>
					<div class="unitprice">unitprice</div>
					<div class="quantity">quantity</div>
					<div class="total">total</div>
					<div class="remove">remove</div> 
					</div>  ';
   
$message1 .= '<a href="cart.php?cmd=emptycart" style="display:none";>Click Here to Empty Your Shopping Cart</a>';
} else {
	// Start PayPal Checkout Button
	//$pp_checkout_btn .= '<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
	// input type="hidden" name="cmd" value="_xclick"
	//input type="hidden" name="business" value="[email protected]">';
	// input type="hidden" name="business" value="R8X2EVCQW9S82">';
	$pp_checkout_btn .= '<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post">
   <input type="hidden" name="cmd" value="_cart">
   <input type="hidden" name="upload" value="1">
   <input type="hidden" name="hosted_button_id" value="APJX39EMDU9VA">
   <input type="hidden" name="business" value="[email protected]">';
	// Start the For Each loop
	
	$i = 0; 
    foreach ($_SESSION["cart_array"] as $each_item) { 
		$item_id = $each_item['item_id'];
		$quantity = (int)$each_item['quantity'];
		$sql = mysqli_query($db, "SELECT * FROM products WHERE id='$item_id' LIMIT 1");
		while ($row = mysqli_fetch_array($sql)) {
			$Product_Name = $row["Product_Name"];
			$product_type = $row["product_type"];
			$List_Price = $row["List_Price"];
			$colour = $row["colour"];
			$top_message = $row["top_message"];
		}
		
		$pricetotal = $List_Price * (int)$each_item['quantity'];// removed int form $each_item[quantity]
		$cartTotal = $pricetotal + $cartTotal;// removed int form $cartTotal
		$itemsTotal = count($_SESSION["cart_array"]);
		 
		setlocale(LC_MONETARY, "en_GB");
        $List_Price = utf8_encode(money_format('%n', $List_Price));
		setlocale(LC_MONETARY, "en_GB");
        $pricetotal = utf8_encode(money_format('%n', $pricetotal));
		
			//Dynamic Checkout Btn Assembly
		$x = $i + 1;
		$pp_checkout_btn .= '<input type="hidden" name="item_name_' . $x . '" value="' . $Product_Name . '">
        <input type="hidden" name="amount_' . $x . '" value="' . $List_Price . '">		 
		<input type="hidden" name="quantity_' . $x . '" value="' . $each_item['quantity'] . '">';
		// Create the product array variable
		$product_id_array .= "$item_id-".$each_item['quantity'].","; 
		
		// ------------------ Dynamic table row assembly when something in the cart -------------------------- //		
			
		$cartOutput .= '<div id="cartproduct"> ';
		$cartOutput .= '<div class="product"><a href="indexN.php?id=' . $item_id . '"></a><br /><img src="shop/images/' . $item_id . '.jpg" alt="' . $Product_Name. '"/></div>';
		$cartOutput .= '<div class="productdesc">' .$product_type . ' - ' . $Product_Name . '</div>';
	//	$cartOutput .= '<div class="unitprice">&pound;' . $List_Price . '</div>';
		$cartOutput .= '<div class="unitprice">' . $List_Price . '</div>';
		$cartOutput .= '<div class="quantity_minus"><a href="cart.php?remove='. $item_id.'"><p>-</p></a></div>';
		$cartOutput .= '<div class="quantity"><p> '.$each_item['quantity'].'</p></div>';
		$cartOutput .= '<div class="quantity_plus"><a  href="cart.php?add='. $item_id.'"><p>+</p></a></div>';
		$cartOutput .= '<div class="total">' . $pricetotal . '</div>';
		$cartOutput .= '<div class="remove"></div><form action="cart.php" method="post"><input class="deleteBtn" name="deleteBtn' . $item_id . '" type="submit" value="X" /><input name="index_to_remove" type="hidden" value="' . $i . '" /></form>';
		$cartOutput .='</div> ';
		$i++; 
		} 
	setlocale(LC_MONETARY,"en_GB"); // causing problems
    $cartTotal = utf8_encode(money_format('%n',$cartTotal)); // causing problems	
	$cartTotal = "<div style='font-size:18px; color:#666; margin-top:12px;' align='right' class='carttotal' >Sub Total : ". $cartTotal ."</div>"; // had removed it
	
//	$discountamt ="<div style='font-size:18px; color:#666; margin-top:12px;' align='right' float:'left'>Discount : " .$discountamt."</div>";
//<div style='font-size:18px; color:#666; margin-top:12px;' align='right' class="carttotal">
   
  
  // </div>

	
    // Finish the Paypal Checkout Btn original button x-click-but01.gif 
	$pp_checkout_btn .= '<input type="hidden" name="custom" value="' . $product_id_array . '">
	<input type="hidden" name="notify_url" value="http://www.magic-makeup.co.uk/storescripts/my_ipn.php">
	<input type="hidden" name="return" value="http://www.magic-makeup.co.uk/checkout_complete.php">
	<input type="hidden" name="rm" value="2">
	<input type="hidden" name="cbt" value="Return to The Store">
	<input type="hidden" name="cancel_return" value="http://www.magic-makeup.co.uk/paypal_cancel.php">
	<input type="hidden" name="lc" value="GB">
	<input type="hidden" name="currency_code" value="GBP">
	<input type="image" src="http://www.magic-makeup.co.uk/images/checkout_with_paypal.gif" name="submit" alt="Make payments with PayPal - its fast, free and secure!">
	</form>';
}

////////////////////////////////
/*  
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="APJX39EMDU9VA">
<input type="image" src="http://www.magic-makeup.co.uk/images/paypal-checkout.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!">
<img alt="" border="0" src='/uploads/default/original/2X/5/56d45f8a17f5078a20af9962c992ca4678450765.gif' width="1" height="1">
</form>


 */

/////////////////////////
//
?>
<?php
 /////////////////////////////// Discount code ////////////////////////////////////////////// 
// include "storeadmin/connect_to_mysql.php"; 
 $discountcode = ""; 
 $discountamt = 0;
 $grossTotal = 0;
 $discount = 0;


//$number = $cartTotal;
if (isset($_POST["promocode"])){  
 $mycode = $_POST['promocode'];
 
 
 		$sql4 = mysqli_query($db, "SELECT * FROM promo_codes WHERE promo_codes.activate='1'");
	$productCount = mysqli_num_rows($sql4); // count the output amount
		if ($productCount > 0){
				while($row = mysqli_fetch_array($sql4)){ 
				 $id = $row["id"];			
				 $code = $row["code"];
				 $Discount = $row["Discount"];
				 $activate = $row["activate"];					

					if ($mycode == $code && $activate == 1){
						
							/////// notes to myself  ///////////
							// Subtotal = $cartTotal
							// $discount = $Discount ($row[Discount]) / 100
							// $discountamt = $cartTotal * $discount
							// $grossTotal = $cartTotal - $discountamt
					
							//working section 
							$Discount = $row["Discount"] /100;
							setlocale(LC_MONETARY, 'en_GB');
    						$Discount =  utf8_encode(money_format('%n', $Discount));
						echo $Discount;
							
							
							$discountamt = $cartTotal * $Discount;							
							setlocale(LC_MONETARY,"en_GB");
							$discountamt = utf8_encode(money_format('%n' , $discountamt));//%.2n							
						echo $discountamt;
						
							
							$grossTotal = $cartTotal - $discountamt;
							setlocale(LC_MONETARY,"en_GB");
							$grossTotal = utf8_encode(money_format('%n' , $grossTotal));//%.2
					echo $grossTotal;
							
							
						
							{
												
								}
			}// while					
		}// productcount
	} // if sql4
}// if isset

?>

That worked as a partial paste.

I have sent you the initial cart page with the outputs and the discount code. The PayPal checkout works without the discount code and i have not got to the testing stage to check if the discount is added to paypal.

make these changes and test it,

// $cartTotal = utf8_encode(money_format('%n',$cartTotal)); // causing problems	
	$cartTotal = "<div style='font-size:18px; color:#666; margin-top:12px;' align='right' class='carttotal' >Sub Total : ". $cartTotal ."</div>"; // had removed it

If it is in non numeric format, the money_format won’t work. You need to see what it is before you do that formatting.

I removed the money format before and the error still remained. The £ sign disappeared as expected.
The figures still remained as 10.99 and the error still persisted.

I have been playing with the money formats for the last 2 weeks and different errors occurred like parameter 2 expect to a float, string is given.

At some point a string is being introduced into that variable. You may need to print the value in the loop to see when it changes over.

The errors are because you are trying to use formatted numbers in math expressions.

Number/money formatting is for the humans reading the final output. The format characters being added result in non-numbers that are treated as zeros and cause the php errors.

You should do the math on the raw numerical values and only format the numbers when you output the final values on a web page.

Next, the SELECT query to find the discount amount from the discount code should NOT query for all the rows and loop over them. Add AND code = ? (using a prepared query) expression to the WHERE clause and use the discount amount if one is found. You will need to learn how to use a prepared query to do this, and it will be much simpler if you switch to the PDO database extension.

1 Like

Hi

Thank you for your help. The problem was as phdr suggested, the calculations were on formatted numbers and I have managed to get the calculations working. Unfortunately I can not get $cartTotal to format with the money format to display the £ symbol. Any help would be appreciated and thank you once again.

I was unable to reply yesterday as the phphelp group would not let me post as i had exceeded my limit as a new user.

You would need to post the current code, from the point where $cartTotal is being produced through to the point where it is being displayed.

Some points about the previously posted code -

  1. If you change the cart definition, so that the item_id is the cart’s array index, all the code dealing with the cart, add, update, delete, and display, will be simpler.
  2. The display cart code should NOT run the SELECT query inside of a loop. You should get all the item ids from the cart at one time, use one query to get all the item details, then loop over the result from this one query to display the contents of the cart.
  3. If you did have a good reason to run a query inside of a loop, you would use a prepared query, prepared before the start of the loop, then just supply each set of input data value(s) when the query gets executed inside of the loop.
  4. Since the code to display the cart is using the item_id(s) in the query, this could be open to sql injection, which would allow anyone to access any of your database tables, such as getting all your user’s email addresses and hashed passwords. You need to use a prepared query anytime you supply external/unknown data values to a query.
  5. You are using a loop to retrieve a single row from a query. Any time you have a query that will at most match one row, just fetch the data without using a loop.
  6. You are repeating the setlocale() statement. This should be done once, in a common ‘initialization’ section of code, near that top of your file.
  7. You are copying variables to other variables without any purpose. Just use the original variables.

The above suggestions will greatly simplify the code and add security to the sql query(ies).

Thank you very much for all your help. Every thing works well now although I need to take measures to avoid any sql injections.

I am still using the original code with the modifications to the money format and will modify it now as the cart is working.

As i have not worked with prepared queries before, I will have to learn that part of PHP and will take your advice. First I have to learn how to go about with the new concept.

When you switch to use prepared queries, you need to switch from the mysqli extension to the PDO extension. The mysqli extension takes more statements and the programming interface is completely different between prepared and non-prepared queries. The PDO extension takes less statements and you can deal with the result from prepared and non-prepared queries the same way.

I was wondering if you could give me an example from your point raised in particular number 2 with this code so that I can understand better.

<?php /////////////////////////////// Discount code ////////////////////////////////////////////// // include "storeadmin/connect_to_mysql.php"; $discountcode = ""; $discountamt = 0; $grossTotal = 0; $discount = 0; if (isset($_POST["promocode"])){ $mycode = $_POST['promocode']; $sql4 = mysqli_query($db, "SELECT code, Discount, activate FROM promo_codes WHERE promo_codes.activate='1'"); $productCount = mysqli_num_rows($sql4); // count the output amount if ($productCount > 0){ while($row = mysqli_fetch_array($sql4)){ $code = $row["code"]; $Discount = $row["Discount"]; $activate = $row["activate"]; if ($mycode == $code && $activate == 1){ $Discount = $row["Discount"]/100 ; $discountamt = $cartTotal * $Discount; $grossTotal = $cartTotal - $discountamt; { } }// while }// productcount } // if sql4 }// if isset ?>

It would be appreciated for my learning curve. Thank You

There’s a current thread that shows how to use PDO and a prepared query for an INSERT query - Issues inserting data into MYSQL table via PHP file! help!

The following is typical connection code. I recommend using variables for the connection parameters so that you can reuse the code just by changing the values, not by editing the actual code.

$DB_HOST = ''; // db host name or ip address
$DB_USER = ''; // db username
$DB_PASS = ''; // db password
$DB_NAME = ''; // db name
$DB_ENCODING = 'utf8'; // db character encoding

$pdo = new pdo("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=$DB_ENCODING",$DB_USER,$DB_PASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the error mode to exceptions
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); // run real prepared queries
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); // set default fetch mode to assoc

The above code would be put into an external .php file and ‘required’ when needed.

To use a non-prepared query, you just use the PDO query() method, which returns a PDOStatement object. You would use PDOStatement methods to operate on the result of the query. Information about these can be found in the php.net documentation.

For a prepared query, you are removing the php variable(s), any single-quotes around the variables, any concatenation dots, and any {} that are in the sql query statement and replacing each with just a ? place-holder. The variable(s) that just got removed are supplied as an array to the execute() method call. You would use PDOStatement methods to operate on the result of the query, the same as for a non-prepared query.

For the discount query, as already stated, it should use a prepared query to find the discount, rather than to loop over all the rows of data. The code above would look like -

/////////////////////////////// Discount code ////////////////////////////////////////////// 

// include "storeadmin/connect_to_mysql.php"; 

require 'pdo_connection.php'; // require the code that makes the database connection using the PDO extension.
// note: if this code is being added to the existing cart display code, there's already a database connection. don't make more connections.

// $discountcode = ""; // this is not used.
$discountamt = 0;
$grossTotal = 0; // note: the $grossTotal should initially be set to the $cartTotal, so that if the following logic is all false, the $grossTotal will be the correct value, without needing more logic to calculate it.
// $discount = 0; // this is not the same letter-case as $Discount in the following code and is probably not used outside of the following code.

// if there's a promocode, it exists and is active, retrieve the corresponding discount and set/calculate the $discountamt and $grossTotal
if(!empty($_POST["promocode"]))
{
	$sql = "SELECT Discount FROM promo_codes WHERE activate = 1 AND code = ?";
	$stmt = $pdo->prepare($sql);
	$stmt->execute([$_POST["promocode"]]);
	// attempt to fetch the row and detect if there was a row
	if($row = $stmt->fetch())
	{
		// there is a row, the code was found and it is active
		$Discount = $row["Discount"]/100 ;
		$discountamt = $cartTotal * $Discount;
		$grossTotal = $cartTotal - $discountamt;
	} else {
		// there is not a row, the code wasn't found or is not active
		// if you want to display distinct messages for each of these possibilities, you would remove the activate = 1 from the sql query and change this logic accordingly
		// set up any user message here... or just do nothing, in which case, remove the else {} branch entirely.
	}
}

// at this point, $discountamt and $grossTotal are either the initial values or the values set/modified by the promocode logic.

Thank you very much for the modified code and tips , I will look forward to implementing the new concept and will be interested in the results and challenges.
I came across a problem with my current system and with the new concept may help.
The problem is… as the discount PHP block is implemented after the main Cart, to implement the discount to paypal button is challenging. If I insert the block before the cart, and as the calculations of the carttotals and each item price etc are not recognised as they don’t exist and are calculated in the code proceeding the discount PHP code.
I hope it makes sense

Kind Regards

Auriff

Sponsor our Newsletter | Privacy Policy | Terms of Service