Skip to content

Instantly share code, notes, and snippets.

@vielhuber
Last active June 12, 2023 09:00
Show Gist options
  • Save vielhuber/ee2c25ba9205bf51472307808b8a0874 to your computer and use it in GitHub Desktop.
Save vielhuber/ee2c25ba9205bf51472307808b8a0874 to your computer and use it in GitHub Desktop.
paypal buttons api #php #js

links

caveats

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, minimum-scale=1" />
<title>PayPal Buttons</title>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="box">
<div class="paypal-button-container paypal-button-container--1"></div>
</div>
<div class="box">
<div class="paypal-button-container paypal-button-container--2"></div>
</div>
</body>
</html>
/* paypal styling */
.paypal-button-container {
font-size: 0;
}
.paypal-button-container .paypal-buttons:not(:last-child) {
margin-bottom: 10px;
}
/* not relevant */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.box {
width: 600px;
height: auto;
margin: 30px auto;
background-color: #f1f1f1;
padding: 20px;
max-width: 100%;
}
class PayPalButtons {
constructor(clientID) {
this.clientID = clientID;
}
async init(items, selector, style = null) {
if (!(items instanceof Array)) {
items = [items];
}
if (document.querySelector('[data-paypal-js]') === null) {
await new Promise((resolve, reject) => {
let script = document.createElement('script');
script.src = 'https://www.paypal.com/sdk/js?client-id=' + this.clientID + '&currency=EUR';
script.setAttribute('data-paypal-js', '');
script.onload = () => {
resolve();
};
document.head.appendChild(script);
});
}
let fundingSources = [];
fundingSources.push(paypal.FUNDING.PAYPAL);
fundingSources.push(paypal.FUNDING.SEPA);
if (items.reduce((a, c) => a + c.amount, 0) >= 1) {
fundingSources.push(paypal.FUNDING.GIROPAY);
fundingSources.push(paypal.FUNDING.SOFORT);
}
fundingSources.push(paypal.FUNDING.CARD);
for (let fundingSource of fundingSources) {
let args = {
fundingSource: fundingSource,
style: {
color: 'black',
shape: 'rect',
layout: 'horizontal'
},
createOrder: (data, actions) => {
let createOrderPayload = {
purchase_units: []
};
items.forEach((items__value, items__key) => {
createOrderPayload.purchase_units.push({
amount: {
value: items__value.amount,
currency_code: 'EUR',
breakdown: {
item_total: {
currency_code: 'EUR',
value: items__value.amount
}
}
},
items: [
{
unit_amount: {
currency_code: 'EUR',
value: items__value.amount
},
quantity: '1',
name: items__value.name,
description: 'idfka'
}
],
reference_id: items__key // required if multiple items are present
});
});
return actions.order.create(createOrderPayload);
},
onApprove: (data, actions) => {
return actions.order.capture().then(details => {
let payerName = details.payer.name.given_name;
console.log(details);
console.log('Transaction completed');
fetch('backend.php', {
method: 'POST',
body: JSON.stringify(details),
cache: 'no-cache',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
let data = response.json(),
status = response.status;
if (status == 200 || status == 304) {
return data;
}
return { success: false, message: status };
})
.catch(error => {
return { success: false, message: error };
})
.then(response => {
console.log([response.success, response.message, response.data]);
alert(response.public_message);
// remove buttons
document.querySelector(selector).remove();
});
});
},
onCancel: data => {
console.log(data);
},
onError: err => {
console.log(err);
}
};
if (style !== null) {
for (const [style__key, style__value] of Object.entries(style)) {
args.style[style__key] = style__value;
}
}
/* card payments open for whatever reason inline */
/* workaround this (https://github.com/paypal/paypal-checkout-components/issues/1521#issuecomment-821815565) */
if (fundingSource === paypal.FUNDING.CARD) {
args.onShippingChange = (data, actions) => {
return actions.resolve();
};
}
let paypalButtonsComponent = paypal.Buttons(args);
if (paypalButtonsComponent.isEligible()) {
paypalButtonsComponent.render(selector).catch(err => {
console.log('PayPal Buttons failed to render');
});
} else {
console.log('The funding source is ineligible');
}
}
}
}
window.addEventListener('load', async e => {
/* usage */
let clientID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
let p = new PayPalButtons(clientID);
await p.init(
{
name: 'Testproduct #1',
amount: 1.15
},
'.paypal-button-container--1',
{ shape: 'rect', color: 'black' }
);
await p.init(
[
{
name: 'Testproduct #1',
amount: 1.15
},
{
name: 'Testproduct #2',
amount: 2.2
}
],
'.paypal-button-container--2',
{ shape: 'pill', color: 'white' }
);
});
<?php
class PayPalApi
{
private $client_id;
private $client_secret;
private $api_url;
function __construct($client_id, $client_secret, $api_url)
{
$this->client_id = $client_id;
$this->client_secret = $client_secret;
$this->api_url = $api_url;
if (!$this->validate()) {
$this->error();
}
// send mail and/or do other stuff
/* ... */
/* $this->input('some_additional') */
/* ... */
$this->success();
}
private function validate()
{
$order_id = $this->input('id');
if ($order_id == '') {
return false;
}
// validate the payment server sided
$response = $this->curl(
url: $this->api_url . '/v1/oauth2/token',
method: 'POST',
data: ['grant_type' => 'client_credentials'],
basic_auth: [
$this->client_id => $this->client_secret
]
);
if (empty($response) || !property_exists($response->result, 'access_token')) {
return false;
}
$response = $this->curl(
url: $this->api_url . '/v2/checkout/orders/' . $order_id,
method: 'GET',
headers: ['Authorization' => 'Bearer ' . $response->result->access_token]
);
if (empty($response) || !property_exists($response->result, 'status')) {
return false;
}
if ($response->result->status !== 'COMPLETED') {
return false;
}
return true;
}
private function error()
{
$this->json_response([
'success' => false,
'message' => 'payment unsuccessful',
'public_message' => 'Bezahlung nicht erfolgreich'
]);
}
private function success()
{
$this->json_response([
'success' => true,
'message' => 'payment successful',
'public_message' => 'Bezahlung erfolgreich'
]);
}
private function input($key = null, $fallback = null)
{
$post = json_decode(file_get_contents('php://input'), true);
if ($key !== null && $key != '') {
if (isset($post) && !empty($post) && array_key_exists($key, $post)) {
return $post[$key];
}
} else {
if (isset($post) && !empty($post)) {
return $post;
}
}
if ($fallback !== null) {
return $fallback;
}
return null;
}
private function json_response($data, $code = 200)
{
http_response_code($code);
header('Content-Type: application/json');
echo json_encode($data);
die();
}
private function curl($url = '', $data = null, $method = null, $headers = null, $basic_auth = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
if (!empty($basic_auth)) {
curl_setopt(
$curl,
CURLOPT_USERPWD,
array_keys($basic_auth)[0] . ':' . $basic_auth[array_keys($basic_auth)[0]]
);
}
if (!empty($data) && (is_array($data) || is_object($data))) {
$data = http_build_query($data);
}
$curl_headers = [];
if (($method == 'POST' || $method === 'PUT') && !empty($data)) {
$curl_headers[] = 'Content-Type: application/x-www-form-urlencoded';
}
if (!empty($headers)) {
foreach ($headers as $headers__key => $headers__value) {
$curl_headers[] = $headers__key . ': ' . $headers__value;
}
}
if (empty($curl_headers)) {
curl_setopt($curl, CURLOPT_HEADER, false);
} else {
curl_setopt($curl, CURLOPT_HTTPHEADER, empty($curl_headers) ? false : $curl_headers);
}
if ($method == 'GET') {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
}
if ($method == 'POST') {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
$result = curl_exec($curl);
curl_close($curl);
$result = json_decode($result);
return (object) [
'result' => $result
];
}
}
new PayPalApi(
client_id: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
client_secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
api_url: 'https://api-m.paypal.com',
//api_url: 'https://api-m.sandbox.paypal.com'
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment