Skip to content

Instantly share code, notes, and snippets.

@BenRacicot
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenRacicot/9174899 to your computer and use it in GitHub Desktop.
Save BenRacicot/9174899 to your computer and use it in GitHub Desktop.
PayPal IPN Script that creates a post in 'Orders_
<?php
// Add this code to functions.php to create a custom table to store order data.
// ALTERNATE
// Use a CPT to create a post each time an order is made.
// require_once('order-post-type.php');
// ALTERNATE
// code to create custom table on theme activation
function create_orders_table_on_activate() {
// versioning for future db upgrades
$orders_db_version = "1.0";
global $orders_db_version;
add_option( "orders_db_version", $orders_db_version );
global $wpdb;
$table_name = $wpdb->prefix . "customer_orders";
//http://codex.wordpress.org/Creating_Tables_with_Plugins
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
first tinytext NOT NULL,
last tinytext NOT NULL,
email tinytext NOT NULL,
address tinytext NOT NULL,
zip VARCHAR(55) DEFAULT '' NOT NULL,
town tinytext NOT NULL,
product tinytext NOT NULL,
price tinytext NOT NULL,
userip tinytext NOT NULL,
UNIQUE KEY id (id)
);";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql ); // very picky! No unnessasary spaces, commas, dashes, underscroes etc in SQL
// Load in an example
$firstname = "Ben";
$lastname = "Racicot";
$dummy_email = "customer@gmail.com";
$dummy_address = "311 Their St.";
$dummy_zip = 02324;
$dummy_town = 'Boston';
$item_purchased = "Coach Bag";
$dummy_price = 500.00;
$dummyip = "192.168.1.1";
$table_name = $wpdb->prefix . "customer_orders";
$rows_affected = $wpdb->insert( $table_name,
array(
'time' => current_time('mysql'),
'first' => $firstname,
'last' => $lastname,
'email' => $dummy_email,
'address' => $dummy_address,
'zip' => $dummy_zip,
'town' => $dummy_town,
'product' => $domain_purchased,
'price' => $dummy_price,
'userip' => $dummyip,
)
);
}
add_action("after_switch_theme", "create_orders_table_on_activate");
// End code to execute on theme activation
// Standard html table solution
function scientifik_wp_orders() {
add_menu_page('Orders', 'Orders', 'administrator', 'scientifik_orders', 'include_orders_page', 'dashicons-networking');
}
function include_orders_page(){
// Create sortable tables within this file to display and sort your tables data
require_once('orders.php');
}
add_action('admin_menu', 'scientifik_wp_orders');
<?php
// Relevant Links
// https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/
// 2014 IPN scripts https://github.com/paypal/ipn-code-samples
// https://developer.paypal.com/webapps/developer/applications/ipn_simulator
// CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory.
// Especially useful if you encounter network errors or other intermittent problems with IPN (validation).
// Set this to 0 once you go live or don't require logging.
define("DEBUG", 1);
// Set to 0 once you're ready to go live
define("USE_SANDBOX", 1);
define("LOG_FILE", "./ipn.log");
// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Post IPN data back to PayPal to validate the IPN data is genuine
// Without this step anyone can fake IPN data
if(USE_SANDBOX == true) {
$paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
} else {
$paypal_url = "https://www.paypal.com/cgi-bin/webscr";
}
$ch = curl_init($paypal_url);
if ($ch == FALSE) {
return FALSE;
}
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
if(DEBUG == true) {
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
}
// CONFIG: Optional proxy configuration
//curl_setopt($ch, CURLOPT_PROXY, $proxy);
//curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
// Set TCP timeout to 30 seconds
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
// CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
// of the certificate as shown below. Ensure the file is readable by the webserver.
// This is mandatory for some environments.
//$cert = __DIR__ . "./cacert.pem";
//curl_setopt($ch, CURLOPT_CAINFO, $cert);
$res = curl_exec($ch);
if (curl_errno($ch) != 0) // cURL error
{
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE);
}
curl_close($ch);
exit;
} else {
// Log the entire HTTP response if debug is switched on.
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE);
error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE);
// Split response headers and payload
list($headers, $res) = explode("\r\n\r\n", $res, 2);
}
curl_close($ch);
}
// mail('myaddress@gmail.com', 'php mail func', 'ipntwo.php has run.');
// Inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// check whether the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your PayPal email
// check that payment_amount/payment_currency are correct
// process payment and mark item as paid.
// assign posted variables to local variables
//$item_name = $_POST['item_name'];
//$item_number = $_POST['item_number'];
//$payment_status = $_POST['payment_status'];
//$payment_amount = $_POST['mc_gross'];
//$payment_currency = $_POST['mc_currency'];
//$txn_id = $_POST['txn_id'];
//$receiver_email = $_POST['receiver_email'];
//$payer_email = $_POST['payer_email'];
// Test verification
// mail('myaddress@gmail.com', 'You\'ve made a PayPal sale!', 'verified');
// You should validate against these values.
$firstname = $_POST['first_name'];
$lastname = $_POST['last_name'];
$payeremail = $_POST['payer_email'];
$street = $_POST['address_street'];
$zip = $_POST['address_zip'];
$city = $_POST['address_city'];
$state = $_POST['address_state'];
$item = $_POST['item_name'];
$price = $_POST['payment_gross'];
$post_id = $_POST['item_number'];
$status = $_POST['payment_status'];
$receiver_email = $_POST['receiver_email'];
// Make sure we have access to WP functions namely WPDB
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-load.php');
global $wpdb; global $redux_options;
// Verify completed status
if ($status == 'Completed') {
// Just a test I used
//mail('myemail@gmail.com', 'IPN invalid message', 'The IPN returned Completed');
// OPTIONAL Remove BIN btn by updating its value to nothing.
update_post_meta($post_id, '_cmb_bin_amount', '', $price);
// Send a notifcation email to admin via WPMAIL
$email = $redux_options['payment_email'];
$subject = $redux_options['payment_subject'];
$headers = "From: $payeremail\r\n";
$message =
"Payment status verified as \'Completed\' from:\r\n".
"First: $firstname\r\n".
"Last: $lastname\r\n".
"Buyer Email: $payeremail\r\n".
"Address: $street\r\n".
"City: $city\r\n".
"State: $state\r\n".
"Zip: $zip\r\n".
"Domain: $item\r\n".
"Price: $price\r\n".
"Payment sent to $receiver_email\r\n".
"if $receiver_email is not your payment gateway\'s email address please investigate this transaction.\r\n".
"Always double check payment confirmation with your payment gateway before fulfilling any order.\r\n".
'BTW - congrats! You just sold an item.';
wp_mail( $email, $subject, $message, $headers, $attachments );
// Send a notifcation email to admin via PHP
mail('myaddress@gmail.com', 'php mail func', $message);
// Create an Order's post
// Fill in its meta data from the buyer
// Update a custom table's data.
// $table_name = $wpdb->prefix . "customer_orders";
// $wpdb->insert($table_name,
// array('firstname' => $firstname,
// 'lastname' => $lastname,
// 'email' => $payeremail,
// 'address' => $street,
// 'zip' => $zip,
// 'town' => $city,
// 'state' => $state,
// 'item' => $item,
// 'time' => current_time('mysql'),
// 'userip' => $_SERVER['REMOTE_ADDR'],
// 'price' => $price
// ),
// array('%s', // firstName
// '%s', // lastName
// '%s', // payerEmail
// '%s', // Street
// '%s', // zip
// '%s', // city
// '%s', // state
// '%s', // Item
// '%s', // Time
// '%s', // user ip
// '%s' // price
// )
// );
}
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
// Add business logic here which deals with invalid IPN messages
// Seems to trigger even if "COMPLETED"
mail('myaddress@gmail.com', 'IPN invalid message', 'The IPN returned invalid');
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
}
}
<?php
// This file makes sortable columns via HTML
// A better way would be to utilize native WordPress Tables.
// Use this -> http://wordpress.org/plugins/custom-list-table-example/
// Let me know how you integrated your DB table's data into it! ben@scientifik.com
function orders_page() { ?>
<div class="wrap">
<div id="icon-users" class="icon32"></div>
<h2>Orders</h2>
<p>Below is a list of all orders.</p>
<table class="widefat">
<thead>
<th><input type="checkbox"></input></th>
<th>#</th>
<th>First</th>
<th>Last</th>
<th>Email</th>
<th>Address</th>
<th>Product</th>
<th>Date</th>
<th>User ip</th>
<th>Price</th>
</thead>
<tbody>
<?php
global $wpdb;
$table_name = $wpdb->prefix . "customer_orders";
?>
<?php $orders = $wpdb->get_results("SELECT * FROM $table_name"); ?>
<?php if($orders) : ?>
<?php foreach($orders as $order) : ?>
<?php //$products = unserialize($order->domainpurchased); ?>
<tr>
<td><a href="" name="delete">delete</a></td>
<td><?php echo $order->id; ?></td>
<td><?php echo $order->first; ?></td>
<td><?php echo $order->last; ?></td>
<td><?php echo "<a href='mailto:$order->email' target='_blank'>$order->email</a>"; ?></td>
<td><?php echo $order->address; ?>,
<?php echo $order->zip; ?>,
<?php echo $order->town; ?>
</td>
<td><?php echo "<a href='http://".$order->product."' target='_blank'>$order->product</a>"; ?></td>
<td><?php echo $order->time; ?></td>
<td><?php echo $order->userip; ?></td>
<td><?php echo $order->price; ?></td>
<!-- <td> -->
<!-- <ul> -->
<?php
// for($i = 0; $i <= count($products); $i++) :
// echo '<li>'.$products[$i].'</li>';
// endfor;
?>
<!-- </ul> -->
<!-- </td> -->
</tr>
<?php endforeach; ?>
<?php else : ?>
<tr colspan="8">
<td>No orders yet.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php }
// Execute the function
orders_page();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment