Location: PHPKode > projects > Battle Cart > order/ipn.php
<?
/*
Copyright (C)2004 Jeff Holman, Downhill Battle, et al

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

include "config.inc.php";

//connect to server
$server = mysql_connect($host, $username, $password) or ipnfail($pp['txn_id'], "Database error: ".mysql_error(), $pp['item_number']);
	
//select database
$connection = mysql_select_db($database, $server) or ipnfail($pp['txn_id'], "Database error: ".mysql_error(), $pp['item_number']);

function ipnfail($txn_id,$reason,$item_number) {
	mail(BUSINESS,"IPN Process Failure",
	"There was an error processing an order.
	
	Transaction ID: $txn_id
	Item Number: $item_number
	Reason for failure: $reason
	
	(!) This order was not processed - you should check if it was a valid order,
	and if it was, process it by hand.");
	exit();
}

function mail_success($buyer,$item) {
	mail($buyer,SHOP_NAME." Order",$item,"From: ".SHOP_NAME." <".BUSINESS.">");
	exit();
}

// Create item "box" for updating quantity
function quantityBox($code, $quantity, $total, $current, $options = NULL) {
	$item = $current['items'][$code];
	if ($_GET['modify'] != $code) {
		$optcode = explode("-", $code);
		$i=0;
		if (sizeof($options[$optcode[0]]) > 0) {
			foreach (array_keys($options[$optcode[0]]) as $j) {
				$i++;
				$item .= "\n".$options[$optcode[0]][$j][$optcode[$i]];
			}
		}
	}
	$item .= "\n";
	$item .= $quantity." for $".num_to_dollar($total);
	return $item;
}

// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';

foreach ($_POST as $key => $value) {
	$pp[$key] = $value;
	$value = urlencode(stripslashes($value));
	$req .= "&$key=$value";
}

// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('www.paypal.com', 80, $errno, $errstr, 30);

if (!$fp) {
	ipnfail($pp['txn_id'], "PayPal didn't respond", $pp['item_number']); // HTTP ERROR
} else {
	fputs ($fp, $header . $req);
	while (!feof($fp)) $res = fgets ($fp, 1024);
	if ($res != "VERIFIED") exit(); //ipnfail($pp['txn_id'], "Payment was invalid", $pp['item_number']);
	if ($pp['receiver_email'] != BUSINESS) ipnfail($pp['txn_id'], "receiver_email was invalid (expected ".RECEIVER_EMAIL.")", $pp['item_number']);
	
	/* Here is where the payment has been validated as a payment to you.
	   You can include another script (which has exit() at the end) to
	   handle non-postal payments, such as a script that counts donations. */
	
	if (mysql_result(mysql_query("SELECT COUNT(*) FROM orders WHERE txn_id='".$pp['parent_txn_id']."'"),0)) {
		mysql_query("UPDATE orders SET payment_status='".$pp['payment_status']."',pending_reason='".$pp['pending_reason']."',reason_code='".$pp['reason_code']."' WHERE txn_id='".$pp['parent_txn_id']."'");
		exit();
	} else {
		if ($pp['item_name'] != ITEM_NAME && !$pp['parent_txn_id']) exit(); //ipnfail($pp['txn_id'], "item_name was invalid (expected ".ITEM_NAME.")", $pp['item_number']);
		if ($pp['quantity'] != 1 && !$pp['parent_txn_id']) exit(); //ipnfail($pp['txn_id'], "quantity was >1 (expected 1)", $pp['item_number']);
		if (strtotime($pp['payment_date']) < strtotime(START_DATE)) exit(); //ipnfail($pp['txn_id'], "payment_date was before valid start date", $pp['item_number']);
		if ($pp['txn_type'] < TXN_TYPE) exit(); //ipnfail($pp['txn_id'], "txn_type was invalid (expected ".TXN_TYPE.")", $pp['item_number']);
	}
}

require("inventory.inc.php");

$current['items'] = $types;
$current['pricing'] = $pricing;
$current['shipping'] = $shipping;

// Convert number to dollars
function num_to_dollar($num) {
	$num = "$num";
	$len = strlen($num);
	if ($num == round($num)) return "$num.00";
	else if ($num[$len-2] == ".") return "$num"."0";
	else return round($num,2);
}

$item = "";
$ap = 0;
$bp = explode(" ",substr(trim($pp['item_number']),0,sizeof($pp['item_number'])-2));
$cp = explode(" ",trim(strrev($pp['item_number'])),2);
if ($cp[0] == 1) $current['intl'] = 1;
else $current['intl'] = 0;
foreach ($bp as $ordercode) {
	$ap++;

	list($quantity,$code) = explode("-",strrev($ordercode),2);
	$code = strrev($code);
	$_POST['quantity'] = strrev($quantity);
	
	if (strstr($code,"-")) {
		$temp = explode("-",$code);
		$code = $temp[0];
		$i=0;
		foreach (array_keys($options[$code]) as $temp2) {
			$i++;
			$_POST[$temp2] = $temp[$i];
		}
	}
	
	$_POST['code'] = $code;
	
	// Check if item type has options, and if so, process it
	if (array_key_exists($code, $types2)) {
		$valid_options = 1;
		
		// Check that all options for the item type were posted and have valid values
		foreach(array_keys($options[$code]) as $i) {
			if (!array_key_exists(${$i} = $_POST[$i], $options[$code][$i])) {
				$valid_options = 0; break;
			}
		}
		
		// Add item w/ specific options to order
		if ($valid_options) {
			$newtype = $code;
			foreach(array_keys($options[$code]) as $i) {
				$newtype .= "-".${$i};
			}
			
			// Update session inventory with new item
			$current['items'][$newtype] = $types2[$code];
			$current['pricing'][$newtype] = $current['pricing'][$code];
			$current['shipping'][$newtype] = $current['shipping'][$code];
			
			// Create new item code based on item type and options
			$_POST['code'] = $newtype;
		}
	}
	
	// Process posted item and add to quantity in cart
	if (($code = $_POST['code']) && (($quantity = floor($_POST['quantity'])) >= 0) && array_key_exists($code, $current['items'])) {
		$current['order'][$code] = $quantity;
	}

	// Enable checkout for non javascript users
	
	$current['ppcode'] = "";
	$shippingTotal = 0;
	// Calculate number of items in each shipping category
	if (sizeof($shippingCategory) > 0) {
		foreach(array_keys($shippingCategory) as $i) {
			$categoryCount[$i] = 0;
		}
	}
	if (sizeof($current['order']) > 0) {
		foreach(array_keys($current['order']) as $typeCode) {
			if ($current['order'][$typeCode] > 0) {
				$typeQuantity = $current['order'][$typeCode];
				// echo $current['items'][$typeCode]." ".$current['order'][$typeCode]."<BR>";
				$typeTotal[$typeCode] = 0;
				$largestQuantity[$typeCode] = 0;
				foreach (array_reverse(array_keys($current['pricing'][$typeCode])) as $typePricing) {
					if ($nocustom[$typeCode] && $typeTotal[$typeCode] != ($typeTotal[$typeCode] += floor($typeQuantity/$typePricing)*$current['pricing'][$typeCode][$typePricing])) {
						$typeQuantity %= $typePricing;
					} else if (!$nocustom[$typeCode] && !$largestQuantity[$typeCode] && floor($typeQuantity/$typePricing)*$current['pricing'][$typeCode][$typePricing] >= 1) {
						$largestQuantity[$typeCode] = $typePricing;
						$typeTotal[$typeCode] = $current['order'][$typeCode]*($current['pricing'][$typeCode][$typePricing]/$largestQuantity[$typeCode]);
						$typeQuantity = 0;
					}
				}
				$current['order'][$typeCode] -= $typeQuantity;
				if ($current['order'][$typeCode] > 0) {
					if ($typeQuantity > 0 && $nocustom[$typeCode]) { 
						// Round down to the nearest increment if custom quantities aren't allowed for the item
						ipnfail($pp['txn_id'], "invalid quantity of ".$current['items'][$typeCode], $pp['item_number']);
					}
					if ($currentCategory = $current['shipping'][$typeCode]) {
						$categoryCount[$currentCategory] += $current['order'][$typeCode];
					}
					//echo "<h2>".$current['items'][$typeCode]."</h2>";
					$current['ppcode'] .= "$typeCode-".$current['order'][$typeCode]." ";
					if ($ap == sizeof($bp)) $item .= "\n\n------------------------------\n\n".quantityBox($typeCode, $current['order'][$typeCode], $typeTotal[$typeCode], $current, $options);
				} else {
					ipnfail($pp['txn_id'], "invalid quantity of ".$current['items'][$typeCode], $pp['item_number']);
				}
			}
		}
	}
}

// Calculate total shipping
foreach(array_keys($shippingCategory) as $i) {
	if ($current['intl']) {
		$shippingTotal += ($categoryCount[$i] * $shippingCategory[$i][2]);
	} else if ($categoryCount[$i] > 0) {
		$shippingTotal += ($shippingCategory[$i][0] + ($categoryCount[$i] - 1) * $shippingCategory[$i][1]);
	}
}
$current['ppcode'] = trim($current['ppcode']);

// Add up item totals
$total = 0;
if (sizeof($typeTotal) > 0) {
	foreach ($typeTotal as $itemTotal) {
		$total += $itemTotal;
	}
}

$grandTotal = $total + $shippingTotal;

$items = $item;
$item .= "\n\n------------------------------\n\nSubtotal: $".num_to_dollar($total)."\nShipping: $".num_to_dollar($shippingTotal)."\nGrand Total: $".num_to_dollar($grandTotal)."\n\nThank You,\n".SHOP_NAME." Staff";

if ($pp['payment_status'] == "Completed") $item = "Thanks for your order, ".$pp['first_name']." ".$pp['last_name']."!\n\nIt usually takes us about 1-2 weeks to ship orders out, though occasionally longer if we run out of a particular color / style combination.  If you haven't received your stuff in a couple weeks, feel free to email and check up on it.  (international orders will take longer to arrive, of course)\n\nHere's a summary of your order:".$item;
else $item = "Thanks for your order, ".$pp['first_name']." ".$pp['last_name']."!\n\nYour order has been received, but your payment is pending. This is most likely because you paid with an eCheck or internation currency. We will notify you when your payment has been accepted.\n\nHere's a summary of your order:".$item;

if (trim($current['ppcode']." ".$current['intl']) != trim($pp['item_number'])) ipnfail($pp['txn_id'], "input item number does not match verfied item number (expected ".$current['ppcode']." ".$current['intl'].")", $pp['item_number']);
if ($pp['settle_amount']) {
	if (round($grandTotal,2) != round($pp['settle_amount'],2)) ipnfail($pp['txn_id'], "calculated total does not match payment received (expected $grandTotal, got ".$pp['settle_amount'].$pp['settle_currency'].")", $pp['item_number']);
} else {
	if (round($grandTotal,2) != round($pp['mc_gross'],2)) ipnfail($pp['txn_id'], "calculated total does not match payment received (expected $grandTotal, got ".$pp['mc_gross'].$pp['mc_currency'].")", $pp['item_number']);
}
$pp['time'] = date("Y-m-d H:i:s", strtotime($row['payment_date']));
$databaseFields = array("txn_id","item_number","memo","payment_status","pending_reason","reason_code","payment_date","parent_txn_id","payment_type","mc_gross","mc_fee","mc_currency","settle_amount","first_name","last_name","address_name","address_street","address_city","address_state","address_zip","address_country","address_status","payer_email","payer_status","items","time");

$sql = "INSERT INTO orders (";
foreach ($databaseFields as $i) {
	$sql .= "$i, ";
}
$sql = substr($sql,0,strlen($sql)-2);
$sql .= ") VALUES (";
foreach ($databaseFields as $i) {
	$sql .= "'".$pp[$i]."', ";
}
$sql = substr($sql,0,strlen($sql)-2);
$sql .= ")";
	
//connect to server
$server = mysql_connect($host, $username, $password) or ipnfail($pp['txn_id'], "Database error: ".mysql_error(), $pp['item_number']);
	
//select database
$connection = mysql_select_db($database, $server) or ipnfail($pp['txn_id'], "Database error: ".mysql_error(), $pp['item_number']);

if (mysql_result(mysql_query("SELECT COUNT(*) FROM orders WHERE txn_id='$pp[txn_id]'"),0)) {
	mysql_query("DELETE FROM orders WHERE txn_id='$pp[txn_id]'") or ipnfail($pp['txn_id'], "error entering updated order in database", $pp['item_number']);
}
mysql_query($sql) or ipnfail($pp['txn_id'], "error entering order in database", $pp['item_number']);

mail_success($pp['first_name']." ".$pp['last_name']."<".$pp['payer_email'].">",$item);
?>
Return current item: Battle Cart