Skip to content

Instantly share code, notes, and snippets.

@Znote
Last active June 11, 2023 03:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Znote/515e96a0de55ba44998fe88053033964 to your computer and use it in GitHub Desktop.
Save Znote/515e96a0de55ba44998fe88053033964 to your computer and use it in GitHub Desktop.
Znote AAC Paypal REST API prototype
<?php require_once 'engine/init.php';
protect_page();
// Import from config:
$pagseguro = $config['pagseguro'];
$paypal = $config['paypal'];
$prices = $config['paypal_prices'];
// Begin processing paypal transaction request
if (empty($_POST) === false) {
$price = intval($_POST['amount']);
if(is_int($price) && $price > 0 && in_array($price, array_keys($prices))) {
$points = $prices[$price];
if ($paypal['debug']) data_dump($_REQUEST, false, "Request");
// Init curl
$ch = curl_init();
// Get token
curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/oauth2/token");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $paypal['client_id'].":".$paypal['secret_id']);
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
$result = curl_exec($ch);
$token_json = json_decode($result);
$token = $token_json->access_token;
if ($paypal['debug']) data_dump($token_json, false, "Payment token");
$profile_id = mysql_select_single("SELECT `value` FROM `znote_global_storage` WHERE `key`='paypal_profile_id' LIMIT 1;");
if ($profile_id === false) {
// Prepare profile data
$buyer_profile = array(
"name" => "paypalProfile",
"temporary" => false,
"input_fields" => array(
"no_shipping" => 1,
"address_override" => 1
)
);
// Send profile create request
curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/payment-experience/web-profiles");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $paypal['client_id'].":".$paypal['secret_id']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($buyer_profile));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer ".$token."",
"Content-Type: application/json"
));
$profile_return = json_decode(curl_exec($ch));
//{"id":"XP-4KHA-UYPT-QNCF-7JYC","name":"webProfile","temporary":false,"input_fields":{"no_shipping":1,"address_override":1}}
if ($paypal['debug']) data_dump($profile_return, false, "Profile return data");
$profile_id = (isset($profile_return->id)) ? $profile_return->id : false;
if ($profile_id !== false) {
mysql_insert("INSERT INTO `znote_global_storage` (`key`, `value`) VALUES ('paypal_profile_id', '$profile_id');");
}
} else {
$profile_id = $profile_id['value'];
}
// Prepare payment data
$currency = $paypal['currency'];
$payment = array(
"intent" => "sale",
"payer" => array(
"payment_method" => "paypal"
),
"transactions" => array(
array(
"amount" => array(
"currency" => $currency,
"total" => $price
),
"description" => "Shop points on ". $config['site_title'],
"item_list" => array(
"items" => array(
array(
"quantity" => "1",
"name" => $prices[$price]." shop points.",
"price" => $price,
"currency" => $currency
)
)
)
)
),
"experience_profile_id" => $profile_id,
"redirect_urls" => array(
"return_url" => $paypal['process'],
"cancel_url" => $paypal['failed'],
)
);
if ($paypal['debug']) data_dump($payment, false, "Payment data");
// Send payment request
curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/payments/payment");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $paypal['client_id'].":".$paypal['secret_id']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payment));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer ".$token."",
"Content-Type: application/json"
));
$result = curl_exec($ch);
$payment_link = json_decode($result);
// Close curl
curl_close($ch);
// Send user to paypal to process payment
if (isset($payment_link->links[1]->href)) {
// Log the start of the payment process
// Account ID, payment ID, price, redirect, execute, status
$account_id = (int)$session_user_id;
$payment_id = $payment_link->id;
$payment_state = $payment_link->state;
$time_created = $payment_link->create_time;
mysql_insert("INSERT INTO `znote_paypal` (`account_id`,`payment_id`,`payment_state`,`price`,`currency`,`points`, `time_created`) VALUES ('{$account_id}','{$payment_id}','{$payment_state}','{$price}','{$currency}','{$points}','{$time_created}');");
if ($paypal['debug']) {
data_dump($payment_link, false, "Payment link success");
echo "<p><a target='_BLANK' href='".$payment_link->links[1]->href."'>Click here to proceed to paypal</a></p>";
} else {
header("Location: ".$payment_link->links[1]->href);
exit();
}
} else {
data_dump($payment_link, false, "Payment link ERROR");
}
} else {
data_dump($_REQUEST, false, "Invalid post data.");
}
}
// Render html
include 'layout/overall/header.php';
// PayPal
if ($paypal['enabled']):
?>
<h1>Buy Points</h1>
<h2>Buy points using Paypal:</h2>
<table id="buypointsTable" class="table table-striped table-hover">
<tr class="yellow">
<th>Price:</th>
<th>Points:</th>
<?php if ($paypal['showBonus']) echo "<th>Bonus:</th>"; ?>
<th>Action:</th>
</tr>
<?php
foreach ($prices as $price => $points):
$discount = calculate_discount(($paypal['points_per_currency'] * $price), $points);
?>
<tr class="special">
<td><?php echo $price; ?>(<?php echo $paypal['currency']; ?>)</td>
<td><?php echo $points; ?></td>
<?php if ($paypal['showBonus']) echo '<td>'. $discount .' bonus</td>'; ?>
<td>
<form action="" method="POST">
<input type="hidden" name="amount" value="<?php echo $price; ?>">
<input type="submit" value=" PURCHASE ">
</form>
</td>
</tr>
<?php
endforeach;
?>
</table>
<?php
endif;
// PagseGuro
if ($config['pagseguro']['enabled'] == true):
?>
<h2>Buy points using Pagseguro:</h2>
<form target="pagseguro" action="https://<?=$pagseguro['urls']['www']?>/checkout/checkout.jhtml" method="post">
<input type="hidden" name="email_cobranca" value="<?=$pagseguro['email']?>">
<input type="hidden" name="tipo" value="CP">
<input type="hidden" name="moeda" value="<?=$pagseguro['currency']?>">
<input type="hidden" name="ref_transacao" value="<?php echo (int)$session_user_id; ?>">
<input type="hidden" name="item_id_1" value="1">
<input type="hidden" name="item_descr_1" value="<?=$pagseguro['product_name']?>">
<input type="number" name="item_quant_1" min="1" step="4" value="1">
<input type="hidden" name="item_peso_1" value="0">
<input type="hidden" name="item_valor_1" value="<?=$pagseguro['price']?>">
<input type="submit" value=" PURCHASE ">
</form>
<br>
<?php
endif;
// PayGol
if ($config['paygol']['enabled'] == true):
$paygol = $config['paygol'];
?>
<!-- PayGol Form using Post method -->
<h2>Buy points using Paygol:</h2>
<p><?php echo $paygol['price'] ." ". $paygol['currency'] ."~ for ". $paygol['points'] ." points:"; ?></p>
<form name="pg_frm" method="post" action="http://www.paygol.com/micropayment/paynow" >
<input type="hidden" name="pg_serviceid" value="<?php echo $paygol['serviceID']; ?>">
<input type="hidden" name="pg_currency" value="<?php echo $paygol['currency']; ?>">
<input type="hidden" name="pg_name" value="<?php echo $paygol['name']; ?>">
<input type="hidden" name="pg_custom" value="<?php echo $session_user_id; ?>">
<input type="hidden" name="pg_price" value="<?php echo $paygol['price']; ?>">
<input type="hidden" name="pg_return_url" value="<?php echo $paygol['returnURL']; ?>">
<input type="hidden" name="pg_cancel_url" value="<?php echo $paygol['cancelURL']; ?>">
<input type="image" name="pg_button" src="http://www.paygol.com/micropayment/img/buttons/150/black_en_pbm.png" border="0" alt="Make payments with PayGol: the easiest way!" title="Make payments with PayGol: the easiest way!">
</form>
<?php
endif;
if (!$config['paypal']['enabled'] && !$config['paygol']['enabled'] && !$config['pagseguro']['enabled']):
?>
<h1>Buy Points system disabled.</h1>
<p>Sorry, this functionality is disabled.</p>
<?php
endif;
include 'layout/overall/footer.php';
?>
<?php
$config['paypal'] = array(
'enabled' => true,
'debug' => false, // Enable debug info to view what is going on and figure out errors
'email' => 'ask@me.com',
'client_id' => 'client id from paypal developer center',
'secret_id' => 'secret id from paypal developer center',
'currency' => 'USD',
'points_per_currency' => 10, // 1 currency = ? points? [ONLY used to calculate bonuses]
'success' => "http://".$_SERVER['HTTP_HOST']."/success.php",
'failed' => "http://".$_SERVER['HTTP_HOST']."/failed.php",
'process' => "http://".$_SERVER['HTTP_HOST']."/paypal_process.php",
'showBonus' => true
);
?>
<?php require_once 'engine/init.php';
protect_page();
$paypal = $config['paypal'];
$payment_id = (isset($_REQUEST['paymentId'])) ? getValue($_REQUEST['paymentId']) : false;
$payer_id = (isset($_REQUEST['PayerID'])) ? getValue($_REQUEST['PayerID']) : false;
if ($payment_id === false || $payer_id === false) {
die("Invalid data, missing payment_id or payer_id");
}
// Do local verification on payment and payer ID before we ask paypal about it
$exist = mysql_select_single("SELECT `id` FROM `znote_paypal` WHERE `payment_id`='{$payment_id}' LIMIT 1;");
if (!$exist) {
die("This transaction is not found in our database.");
}
if ($paypal['debug']) data_dump($_REQUEST, false, "Request data");
if ($paypal['debug']) data_dump($user_data, false, "User Data");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/oauth2/token");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $paypal['client_id'].":".$paypal['secret_id']);
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
$result = curl_exec($ch);
$token_json = json_decode($result);
$token = $token_json->access_token;
if ($paypal['debug']) data_dump($token_json, false, "Token info");
// Execute the payment
$payment = array(
"payer_id" => $payer_id
);
curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/payments/payment/".$payment_id."/execute/");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $paypal['client_id'].":".$paypal['secret_id']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payment));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer $token",
"Content-Type: application/json"
));
$result = curl_exec($ch);
$payment_info = json_decode($result);
curl_close($ch);
if ($paypal['debug']) data_dump($payment_info, false, "payment info");
///////////////////////
// Validate response //
///////////////////////
$errors = array();
// Already done payment?
if (isset($payment_info->name) && $payment_info->name === "PAYMENT_ALREADY_DONE") {
include 'layout/overall/header.php';
?>
<h1>Transaction already done</h1>
<p>Transaction has been done already for this order.</p>
<?php
include 'layout/overall/footer.php';
exit();
}
////////
// Payment ID
$paymentId = (isset($payment_info->id)) ? $payment_info->id : false;
if (!$paymentId) {
$errors[] = "Failed to load payment ID";
}
////////
// Load transaction from SQL
$db_entry = ($paymentId !== false)
? mysql_select_single("SELECT `id`, `account_id`, `payment_id`, `payment_state`, `points`, `transaction_state`, `payer_id`, `email` FROM `znote_paypal` WHERE `payment_id`='{$paymentId}' LIMIT 1;")
: false;
if (!$db_entry) {
$errors[] = "Failed to load the transaction from the database.";
} else {
if ($paymentId !== false) mysql_update("UPDATE `znote_paypal` SET `payer_id`='{$payer_id}' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
////////
// Payment time
$time_updated = (isset($payment_info->create_time)) ? $payment_info->create_time : false;
if (!$time_updated) {
$errors[] = "Failed to processing timestamp";
if ($paymentId !== false) mysql_update("UPDATE `znote_paypal` SET `time_updated`='Missing' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
} else {
if ($paymentId !== false) mysql_update("UPDATE `znote_paypal` SET `time_updated`='{$time_updated}' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
////////
// Payment state
$paymentState = (isset($payment_info->state)) ? $payment_info->state : false;
if (!$paymentState) {
$errors[] = "Failed to load payment state";
} elseif ($paymentState != "approved") {
$errors[] = "Payment state is not approved, but {$paymentState}.";
if ($paymentId !== false) mysql_update("UPDATE `znote_paypal` SET `payment_state`='{$paymentState}' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
////////
// Transaction state
$transactionState = (isset($payment_info->transactions[0]->related_resources[0]->sale->state))
? $payment_info->transactions[0]->related_resources[0]->sale->state
: false;
if (!$transactionState) {
$errors[] = "Failed to load Transaction state";
} elseif ($transactionState != "completed") {
$errors[] = "Transaction state is not completed, but {$transactionState}.";
if ($paymentId !== false) mysql_update("UPDATE `znote_paypal` SET `transaction_state`='{$transactionState}' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
////////
// Paypal Email
$paypalEmail = (isset($payment_info->payer->payer_info->email)) ? $payment_info->payer->payer_info->email : false;
if (!$paypalEmail) {
$errors[] = "Failed to load payer email address";
} else {
if ($paymentId !== false) mysql_update("UPDATE `znote_paypal` SET `email`='{$paypalEmail}' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
////////
// Paypal verified
$paypalVerified = (isset($payment_info->payer->status)) ? $payment_info->payer->status : false;
if (!$paypalVerified) {
$errors[] = "Failed to load payer status";
} elseif ($paypalVerified != "VERIFIED") {
$errors[] = "Paypal account is not verified, and thus considered untrusted.";
if ($paymentId !== false)
mysql_update("UPDATE `znote_paypal` SET `transaction_state`='{$transactionState} (untrusted)' WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
////////
// Price
$prices = $config['paypal_prices'];
$price = (isset($payment_info->transactions[0]->amount->total))
? $payment_info->transactions[0]->amount->total
: false;
if (!$price) {
$errors[] = "Failed to load Transaction price";
} elseif (!in_array($price, array_keys($prices))) {
if (!in_array((int)$price, array_keys($prices))) {
$errors[] = "Price {$price} mismatch paypal_prices shop configuration.";
} else {
$price = (int)$price;
}
}
////////
// Currency
$currency = (isset($payment_info->transactions[0]->amount->currency))
? $payment_info->transactions[0]->amount->currency
: false;
if (!$currency) {
$errors[] = "Failed to load Transaction currency";
} elseif ($currency !== $paypal['currency']) {
$errors[] = "Currency {$currency} mismatch paypal shop configuration (".$paypal['currency'].").";
}
if (!empty($errors)) {
foreach ($errors as $number => $error) {
echo '<p style="font-weight: bold; color: red;">Error '.$number.': '.$error.'</p>';
}
data_dump($payment_info, false, "Response dump:");
} else {
// Figure out which fields we need to update
$update = array();
if ($db_entry['payment_state'] !== $paymentState) $update['payment_state'] = $paymentState;
if ($db_entry['transaction_state'] !== $transactionState) $update['transaction_state'] = $transactionState;
if ($db_entry['price'] != $price) $update['price'] = $price;
if ($db_entry['currency'] !== $currency) $update['currency'] = $currency;
if ($db_entry['payer_id'] !== $payer_id) $update['payer_id'] = $payer_id;
if ($db_entry['email'] !== $paypalEmail) $update['email'] = $paypalEmail;
if (!empty($update)) {
$setString = array();
foreach ($update as $column => $value) {
$setString[] = "`{$column}`='{$value}'";
}
$setString = implode(',', $setString);
mysql_update("UPDATE `znote_paypal` SET $setString WHERE `payment_id`='{$paymentId}' LIMIT 1;");
}
include 'layout/overall/header.php';
// Add points to the account
if ($db_entry['transaction_state'] !== "completed" && $transactionState === "completed") {
$new_points = $db_entry['points'];
$account_id = $db_entry['account_id'];
// Fetch points
$account = mysql_select_single("SELECT `points` FROM `znote_accounts` WHERE `account_id`='{$account_id}' LIMIT 1;");
// Calculate new points
$new_points = $account['points'] + $new_points;
// Update new points
mysql_update("UPDATE `znote_accounts` SET `points`='{$new_points}' WHERE `account_id`='{$account_id}' LIMIT 1;");
?>
<h1>Success</h1>
<p>You now have <?php echo $new_points; ?> shop points.</p>
<?php
} else {
?>
<h1>Processing error</h1>
<p>This payment is already processed. You should already have gotten the points.</p>
<p>Failed operation: <?php echo $db_entry['transaction_state']; ?> !== completed && <?php echo $transactionState; ?> === completed</p>
<?php
}
include 'layout/overall/footer.php';
}
<?php require_once 'engine/init.php';
protect_page();
include 'layout/overall/header.php';
$session_user_id = (int)$session_user_id;
$paypal_transactions = mysql_select_multi("SELECT `account_id`, `payment_state`, `transaction_state`, `price`, `currency`, `points`, `email`, `time_created`, `time_updated` FROM `znote_paypal` WHERE `account_id`='{$session_user_id}';");
// data_dump($paypal_transactions, false, "data");
?>
<h1>Shop history</h1>
<p>This is an overview of your shopping history with us.</p>
<h2>Paypal transactions</h2>
<table class="table tbl-hover">
<tbody>
<tr class="yellow">
<td>Created</td>
<td>Payment</td>
<td>Transaction</td>
<td>Price</td>
<td>Email</td>
<td>Updated</td>
</tr>
<?php
foreach ($paypal_transactions as $transaction):
$state = ($transaction['transaction_state'] !== null) ? $transaction['transaction_state'] : 'waiting for user';
$email = ($transaction['email'] !== null) ? $transaction['email'] : 'Unknown';
?>
<tr>
<td><?php echo getClock(strtotime($transaction['time_created']), true); ?></td>
<td><?php echo $transaction['payment_state']; ?></td>
<td><?php echo $state; ?></td>
<td><?php echo $transaction['points']." points for ".$transaction['price']." ".$transaction['currency']; ?></td>
<td><?php echo $email; ?></td>
<td><?php echo getClock(strtotime($transaction['time_updated']), true); ?></td>
</tr>
<?php
endforeach;
?>
</tbody>
</table>
<?php include 'layout/overall/footer.php'; ?>
CREATE TABLE IF NOT EXISTS `znote_paypal` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int(11) NOT NULL,
`payment_id` varchar(100) NOT NULL,
`payment_state` varchar(50) NOT NULL,
`price` int(11) NOT NULL,
`currency` varchar(10) NOT NULL,
`points` int(11) NOT NULL,
`transaction_state` varchar(50) DEFAULT NULL,
`payer_id` varchar(50) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`time_created` varchar(30) DEFAULT NULL,
`time_updated` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment