Stripe Checkout PHP API getting 500 Internal Server Error - php

Here is my situation, i'm implementing Custom Stripe Checkout with Stripe PHP Api.
I have requested a post Method using jquery like this one >
var handler = StripeCheckout.configure({
key: 'pk_test_yGQM97VuEUdttuOOFQcyaPHW',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function (token) {
// You can access the token ID with `token.id`.
// Get the token ID to your server-side code for use.
$.post(
'charge.php',
{
sT: token.id,
sE: token.email
}, function (data) {
console.log(data);
}
);
}
});
var thePayment = document.getElementById('pay-amount');
if (thePayment) {
thePayment.addEventListener('click', function (e) {
var desc = $('#pay-amount').attr('data-desc');
var amount = Number($('#pay-amount').attr('data-amount'));
var email = $('#pay-amount').attr('data-email');
// Open Checkout with further options:
handler.open({
name: 'Test',
description: desc,
amount: amount,
email: email,
allowRememberMe: false
});
e.preventDefault();
});
}
// Close Checkout on page navigation:
window.addEventListener('popstate', function () {
handler.close();
});
And the PHP side is just like this one >
require_once('html/includes/vendor/autoload.php');
$stripe = array(
"secret_key" => "sk_test_nJxSc9Yw716tLBWTa9HHMxhj",
"publishable_key" => "pk_test_yGQM97VuEUdttuOOFQcyaPHW"
);
$charge_reply = array();
\Stripe\Stripe::setApiKey($stripe['secret_key']);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$token = $_POST['sT'];
$email = $_POST['sE'];
$customer = \Stripe\Customer::create(array(
'email' => $email,
'source' => $token
));
$charge = \Stripe\Charge::create(array(
"amount" => 1000,
"currency" => "usd",
"source" => $customer->id,
"email" => $email,
"description" => "Example charge"
));
$charge_reply[] = [
'token' => $token,
'email' => $email
];
sendJson($charge_reply);
return;
}
I have also enabled the curl,json,mbstring in php. But the function that accepts after requesting a post method to the charge.php, prints POST http://example.com/charge.php 500 (Internal Server Error) in the console log.
So is there any way i can fix this?

500 (Internal Server Error) is something wrong in your code which means their is a fatal error.
To find the error you should use below code in your top of the page.
ini_set('display_errors',1);
error_reporting(E_ALL);
It will return the exact error so can fix it.
Note: Do not use it in production environment this for your local development.

Related

Stripe avoid paymentintent with status 'Incomplete'

I am using Stripe's 'Payment' element for creating paymentintent and card charges, Using PHP, HTML & JS.
https://stripe.com/docs/payments/payment-element
a) As soon as i load the payment page, Stripe generates a paymentintent with status 'Incomplete'.
b) After i enter Credit Card details and hit 'pay', Stripe again issues a second paymentintent with status accordingly (say 'Succeeded')
The result is, that my Dashboard is now full of unnecessary records
This is, because i initialize the $paymentIntent = \Stripe\PaymentIntent::create as soon as the page loads.
I understand that this is Stripe default behaviour, because at that moment, no payment_method is attached yet.
My question is: How is this resolved best, to avoid such 'Incomplete' records?
Maybe attach an object and fire the paymentintent creation only when
that object is present?
Or onclick of the 'pay' button..awaiting paymentintent, confirm presence and then submit the form?
Or retrieve that 1st paymentintent, store it and then update with
form submission?
create.php
header('Content-Type: application/json');
try {
// retrieve JSON from POST body
$jsonStr = file_get_contents('php://input');
$jsonObj = json_decode($jsonStr);
// Create a PaymentIntent with amount and currency
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => 1000,
'currency' => 'eur',
'receipt_email' => 'whatever#mail.com',
'automatic_payment_methods' => ['enabled' => true,],
'description' => 'Reservation Dimi123 / Name: John Doe',
'metadata' => ['order_id' => '12345']
]);
$output = [
'clientSecret' => $paymentIntent->client_secret,
];
echo json_encode($output);
} catch (Error $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
script.js
const stripe = Stripe("pk_test_..");
let elements;
initialize();
checkStatus();
document
.querySelector("#payment-form")
.addEventListener("submit", handleSubmit);
// Fetches a payment intent and captures the client secret
async function initialize() {
const { clientSecret } = await fetch("../create.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
}).then((r) => r.json());
elements = stripe.elements({ clientSecret });
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
}
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: "https://localhost/stripe/prebuilt-checkout-custom-flow/public/checkout.html",
},
});
if (error.type === "card_error" || error.type === "validation_error") {
showMessage(error.message);
} else {
showMessage("An unexpected error occurred.");
}
setLoading(false);
}
How to Avoid Incomplete Payment Intents? You don't.
his is how the system is designed to function since you need the client_secret from the Payment Intent (or Setup Intent) to render the Payment Element. There is no negative impact to your account.
You should feel comfortable ignoring them. You can adjust the filters in your Payments tab to not see them. They aren't a great metric of individual customers coming to your payment interface and navigating away since any user refreshing their browser would trigger a new one.

How can I set amount field to PayPal SDK

I am working on PayPal express and want to send the amount field value to the server file (payment.php)
from the client-side script and also want to gets its value to the server-side file.
Here is client-side script
<script src="https://www.paypal.com/sdk/js?client-id=<client-id>"></script>
<script>
paypal.Buttons({
createOrder: function() {
return fetch('payment.php', {
method: 'post',
headers: {
'content-type': 'application/json'
},
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.id;
});
},
onApprove: function(data, actions) {
// This function captures the funds from the transaction.
return actions.order.capture().then(function(details) {
// This function shows a transaction success message to your buyer.
window.location = "paypal-transaction-complete.php?&orderID="+data.orderID;
});
}
}).render('#paypal-button-container');
</script>
<div id="paypal-button-container"></div>
Here is the payment.php where I want to get the amount field value
<?php
namespace Sample\CaptureIntentExamples;
require __DIR__ . '/vendor/autoload.php';
//1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
require 'paypal-client.php';
class CreateOrder
{
public static function createOrder($debug=false)
{
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = self::buildRequestBody();
// 3. Call PayPal to set up a transaction
$client = PayPalClient::client();
$response = $client->execute($request);
echo json_encode($response->result, JSON_PRETTY_PRINT);
return $response;
}
private static function buildRequestBody()
{
return array(
'intent' => 'CAPTURE',
'application_context' =>
array(
'return_url' => 'https://example.com/return',
'cancel_url' => 'https://example.com/cancel'
),
'purchase_units' =>
array(
0 =>
array(
'amount' =>
array(
'currency_code' => 'USD',
'value' => '20.00'
)
)
)
);
}
}
if (!count(debug_backtrace()))
{
CreateOrder::createOrder(true);
}
?>
Please let me know how can I do that? Thanks!
With PHP the simplest way is going to be to use a GET string.
return fetch('payment.php?amount=' + document.getElementById('amount').value , {
^ You might want to validate or sanitize that input or URL encode the value, but for the most part it should work.
array(
'currency_code' => 'USD',
'value' => $_GET['amount']
)
It's not modern but that's PHP for you, parsing JSON is probably overkill.
You shouldn't be using actions.order.capture() when creating on the server, I'd be surprised if that even works. Implement a capture order route on your server, and use this JS sample that has proper error handling: https://developer.paypal.com/demo/checkout/#/pattern/server

How to fix the 3D secure confirm Payment on client side or on server side in Stripe Payment Intent?

I'm integrating Stripe Payment Intent API and it's working well where 3D secure is not required, 3D secure authorization is popping up but I think I'm missing return_url to confirm the payment.
Where do I need to mention return_url for 3D Secure in PaymentIntent?
I've tried multiple times but got stuck on 3D Secure Authorize. It returns an error in the object.
I've mentioned the code of view and controller below.
Thanks in Advance
Client Side Code:
form.addEventListener('submit', function(event) {
event.preventDefault();
$('#card-button').html('<i class="fa fa-circle-o-notch fa-spin" style="font-size:24px"></i>');
var fname = $('#firstname2').val();
var lname = $('#lastname2').val();
var cardholderName = fname + " " + lname;
var cardButton = document.getElementById('card-button');
var form_data = $("#payment-form").serialize();
cardButton.addEventListener('click', function(ev) {
stripe.createPaymentMethod('card', cardElement, {
billing_details: {name: cardholderName}
}).then(function(result) {
if (result.error) {
// Show error in payment form
} else {
console.log(result);
// Otherwise send paymentMethod.id to your server (see Step 2)
fetch('<?php echo base_url(); ?>payment/stripe_test/process_payment',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_method_id: result.paymentMethod.id, customer_detail: form_data})
}).then(function(result) {
// Handle server response (see Step 3)
result.json().then(function(result) {
console.log("Response" + result);
handleServerResponse(result);
});
});
}
});
});
}
function handleServerResponse(response) {
if (response.error) {
// Show error from server on payment form
} else if (response.requires_action) {
var action = response.next_action;
if (action && action.type === 'redirect_to_url') {
window.location = action.redirect_to_url.url;
}
// Use Stripe.js to handle required card action
stripe.handleCardAction(
response.payment_intent_client_secret
).then(function(result) {
if (result.error) {
// Show error in payment form
} else {
// The card action has been handled
// The PaymentIntent can be confirmed again on the server
fetch('<?php echo base_url(); ?>payment/stripe_test/process_payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_intent_id: result.paymentIntent.id })
}).then(function(confirmResult) {
return confirmResult.json();
}).then(handleServerResponse);
}
});
} else {
// Show success message
console.log("3D" + response);
}
}
CodeIgniter Controller:
//PaymentIntent Function
function process_payment() {
require_once (APPPATH."third_party/stripe/init.php");
$key = "STRIPE_KEY_HERE";
header('Content-Type: application/json');
# retrieve json from POST body
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$intent = null;
try {
if (isset($json_obj->payment_method_id)) {
# Create the PaymentIntent
//STRIPE PAYMENT INTENT
\Stripe\Stripe::setApiKey($key);
// Create a Customer:
$customer = \Stripe\Customer::create([
'email' => 'client#gmail.com',
]);
// Attach payment method to the customer:
$customer_detail = $json_obj->customer_detail;
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $json_obj->payment_method_id,
'amount' => 1099,
'currency' => 'GBP',
'confirmation_method' => 'manual',
"customer" => $customer->id,
'confirm' => true,
]);
}
if (isset($json_obj->payment_intent_id)) {
$intent = \Stripe\PaymentIntent::retrieve(
$json_obj->payment_intent_id
);
$intent->confirm();
}
$this->generatePaymentResponse($intent);
} catch (\Stripe\Error\Base $e) {
# Display error on client
echo json_encode([
'error' => $e->getMessage()
]);
}
}
generatePaymentResponse Function:
function generatePaymentResponse($intent) {
if ($intent->status == 'requires_source_action' &&
$intent->next_action->type == 'use_stripe_sdk') {
# Tell the client to handle the action
echo json_encode([
'requires_action' => true,
'payment_intent_client_secret' => $intent->client_secret
]);
} else if ($intent->status == 'succeeded') {
# The payment didn’t need any additional actions and completed!
# Handle post-payment fulfillment
echo json_encode([
"success" => true
]);
} else {
# Invalid status
http_response_code(500);
echo json_encode(['error' => 'Invalid PaymentIntent status']);
}
}
As mentioned in comments, you don't need to specify return_url, because in your case Stripe will use Popup for 3DS confirmation, not redirecting.
You missed two things in your code:
1. In function generatePaymentResponse add condition for $intent->status === 'requires_action'.
2. On Payment Intent confirmation ($intent->confirm();) you missed to set api key (\Stripe\Stripe::setApiKey($key);)
I have tested your code and it works with mentioned modifications.
Stripe updated the API and few statuses were renamed so the major reason was that I was using requires_source_action as status so replaced it with requires_action.
Stripe Update - 2019-02-11
Some PaymentIntent statuses have been renamed
requires_source is now requires_payment_method
requires_source_action is now requires_action
All other statuses are unchanged
save_source_to_customer has been renamed to save_payment_method.
allowed_source_types has been renamed to payment_method_types.
The next_source_action property on PaymentIntent has been renamed to next_action, and the authorize_with_url within has been renamed to redirect_to_url.
You can find Stripe Api upgrades here: https://stripe.com/docs/upgrades#api-versions.

Stripe but won´t charge using Ajax to post token

I have the following fairly basic implementation of Stripe. It successfully creates a new customer but it won´t charge and return the "SUCCESS ERROR" message in the console. The token seems to be created correctly so my guess is i am missing something in the charge.php.
NOTE: I have not used composer to install stripe but load the init.php in config.php (could that be the problem?). Also is the neccessary even though i use ajax?(removing it won´t solve the problem though)
Index.php
<?php require_once('stripe/config.php'); ?>
<form action="charge.php" method="post">
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton">Purchase</button>
<script>
var handler = StripeCheckout.configure({
key: 'pk_test_*******************',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
console.log(token)
$.ajax({
url: 'stripe/charge.php',
type: 'post',
data: {tokenid: token.id, email: token.email},
success: function(data) {
if (data == 'success') {
console.log("Card successfully charged!");
}
else {
console.log("Success Error!");
}
},
error: function(data) {
console.log("Ajax Error!");
console.log(data);
}
}); // end ajax call
}
});
$('#customButton').on('click', function(e) {
// Open Checkout with further options
handler.open({
name: 'shipping free',
description: '2 widgets',
amount: 2000
});
e.preventDefault();
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
</script>
</form>
CONFIG.PHP
<?php require_once('init.php');
$stripe = array(
secret_key => 'sk_test_************************',
publishable_key => 'pk_test_************************'
);
Stripe::setApiKey($stripe['secret_key']);
?>
CHARGE.PHP
<?php require_once('/config.php');
$tokenid = $_POST['tokenid'];
$email = $_POST['email'];
$customer = \Stripe\Customer::create(array(
'email' => $email,
'card' => $tokenid
));
$charge = \Stripe\Charge::create(array(
'email' => $email,
'card' => $tokenid
'amount' => 5000,
'currency' => 'usd',
));
echo '<h1>Successfully charged $50.00!</h1>';
?>
In this line, 'card' => $tokenid. you are missing comma(,).
Add comma in that line.
$charge = \Stripe\Charge::create(array(
'email' => $email,
'card' => $tokenid,
'amount' => 5000,
'currency' => 'usd',
));

Stripe Checkout - Create a Variable Charge

I was previously charging users a fixed amount, say, "$20," but I wanted to create a donation box that would accept variables. I understand that there is "StripeCheckout.open," but does anyone know how it would look?
That being said, I am currently using the code below to charge a user a fixed amount, though I'm desperate to find out how to set a variable amount that can be charged.
<?php
require_once('config.php');
$token = $_POST['stripeToken'];
$customer = Stripe_Customer::create(array(
'email' => 'customer#example.com',
'card' => $token
));
$charge = Stripe_Charge::create(array(
'customer' => $customer->id,
'amount' => variable,
'currency' => 'cad'
));
?>
Ok, you probably should use V2 instead of V1, and what you want to do is something like this:
$('#sendPledgeBtn').click(function(){
var token = function(res){
var $input = $('<input type=hidden name=stripeToken />').val(res.id);
var tokenId = $input.val();
var email = res.email;
setTimeout(function(){
$.ajax({
url:'make-payment.php',
cache: false,
data:{ email : email, token:tokenId },
type:'POST'
})
.done(function(data){
// If Payment Success
$('#sendPledgeBtn').html('Thank You').addClass('disabled');
})
.error(function(){
$('#sendPledgeBtn').html('Error, Unable to Process Payment').addClass('disabled');
});
},500);
$('form:first-child').append($input).submit();
};
StripeCheckout.open({
key: 'pk_live_XXXXXXXXX', // Your Key
address: false,
amount: $('#amount').val(),
currency: 'usd',
name: 'Canted Pictures',
description: 'Donation',
panelLabel: 'Checkout',
token: token
});
return false;
});

Categories