I'm trying to setup a simple Stripe payment on my Wordpress plugin. I've followed their documentation and they recommend using fetch API to get the server side paymentIntent response from a .php file like below.
fetch("/create-payment-intent.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(orderData)
})
However, my plugin is built using OOP and the code is within a class so I'm guessing if i point to this file directly it wouldn't work as it first needs to be first initialised. Is there a way of using fetch to call a method in a php class? Or is it better to use AJAX to handle the above?
Update
This is the code Stripe have in their documentation which i need to run in create-payment-intent.php. However, in my case i want to run the methods in a class so using fetch() woudln't work.
# vendor using composer
require_once('vendor/autoload.php');
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
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
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $json_obj->payment_method_id,
'amount' => 1099,
'currency' => 'usd',
'confirmation_method' => 'manual',
'confirm' => true,
]);
}
if (isset($json_obj->payment_intent_id)) {
$intent = \Stripe\PaymentIntent::retrieve(
$json_obj->payment_intent_id
);
$intent->confirm();
}
generateResponse($intent);
} catch (\Stripe\Exception\ApiErrorException $e) {
# Display error on client
echo json_encode([
'error' => $e->getMessage()
]);
}
function generateResponse($intent) {
# Note that if your API version is before 2019-02-11, 'requires_action'
# appears as 'requires_source_action'.
if ($intent->status == 'requires_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']);
}
}
Related
I've been trying to figure out this problem for 2 days already..
I want to implement Smart Payment Buttons from PayPal, literally followed every step of the explanation closely but still getting following error:
Error: JSON.parse: unexpected character at line 1 column 1 of the JSON data
My javascript for Button rendering:
paypal.Buttons({
createOrder: function() {
return fetch('vendor/paypal/paypal-checkout-sdk/samples/CaptureIntentExamples/CreateOrder.php', {
method: 'post',
headers: {
'content-type': 'application/json'
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID; // Use the same key name for order ID on the client and server
});
},
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.
alert('Transaction completed by ' + details.payer.name.given_name);
});
},
onError: function(err) {
alert(err);
}
}).render('#paypal-button-container');
My CreateOrder.php:
namespace Sample\CaptureIntentExamples;
require __DIR__ . '/../../../../autoload.php';
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
class CreateOrder
{
/**
* Setting up the JSON request body for creating the Order. The Intent in the
* request body should be set as "CAPTURE" for capture intent flow.
*
*/
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' => '220.00'
)
)
)
);
}
/**
* This is the sample function which can be sued to create an order. It uses the
* JSON body returned by buildRequestBody() to create an new Order.
*/
public static function createOrder($debug=false)
{
$request = new OrdersCreateRequest();
$request->headers["prefer"] = "return=representation";
$request->body = self::buildRequestBody();
$client = PayPalClient::client();
$response = $client->execute($request);
if ($debug)
{
print "Status Code: {$response->statusCode}\n";
print "Status: {$response->result->status}\n";
print "Order ID: {$response->result->id}\n";
print "Intent: {$response->result->intent}\n";
print "Links:\n";
foreach($response->result->links as $link)
{
print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n";
}
// To toggle printing the whole response body comment/uncomment below line
echo json_encode($response->result, JSON_PRETTY_PRINT), "\n";
}
return $response;
}
}
if (!count(debug_backtrace()))
{
CreateOrder::createOrder(true);
}
It's basicly all copied from the PayPal walkthough.
If I visit the CreateOrder.php directly it is creating an order and I can see the response without errors.
Status Code: 201 Status: CREATED [...]
What I did was deleting the part of the code which was printing out the response in txt format. This is why you were getting JSON syntax error.
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);
// To print the whole response body, uncomment the following line
echo json_encode($response->result, JSON_PRETTY_PRINT);
// 4. Return a successful response to the client.
return $response;
}
By the way, this answer is very helpful: https://stackoverflow.com/a/63019280/12208549
I am updating my Codeigniter framework from 2.2.6 to 3.0.6. It has broken the existing code that worked before. Specifically, I am getting the error "SyntaxError: JSON.parse: unexpected character at line 2 column 1 of the JSON data" inside the browser console. I have tried to look and see if this is a known issue when updating, but I have not seen anyone else experiencing this.
Here is the javascript that I am using:
$('#addServiceItem').on('change', function() {
var serviceID = $(this).val();
$.ajax({
url: '/ajax/get_service_details/' + serviceID,
}).done(function(data) {
if (data.status == 'success') {
addServiceItem(data.service);
} else {
alert(data.message);
}
});
});
Also, here is the function that is being called in the ajax url:
public function get_service_details($serviceID = 0)
{
if (!$this->input->is_ajax_request()) {
exit('No direct script access allowed');
}
if ($serviceID == 0) {
header('Content-type: application/json');
echo json_encode(array(
'status' => 'error',
'service' => null,
'message' => 'We could not find the service.'
));
}
$service = $this->services_model->get_service_details($serviceID);
header('Content-type: application/json');
echo json_encode(array(
'status' => 'success',
'service' => $service,
'message' => ''
));
}
As stated above, this code worked in the previous version of Codeigniter. As far as I can tell there is an issue with the Ajax call returning a value. In the javascript variable data stays undefined. I assume that there is a syntax standard that has changed.
If your $serviceID == 0, then you get error Headers already sent because inside IF you output content and do not terminate code, and outside of IF you again try to set header.
Change your code to this one:
public function get_service_details($serviceID = 0)
{
if (!$this->input->is_ajax_request()) {
exit('No direct script access allowed');
}
if ($serviceID == 0) {
header('Content-type: application/json');
echo json_encode(array(
'status' => 'error',
'service' => null,
'message' => 'We could not find the service.'
));
// Terminate function execution
return;
}
$service = $this->services_model->get_service_details($serviceID);
header('Content-type: application/json');
echo json_encode(array(
'status' => 'success',
'service' => $service,
'message' => ''
));
}
We would like to create/update a lead in Intercom via Javascript, we can do it through the PHP, but I have no idea how to do the same with Javascript, because we are using Unbounce landing page and when visitor fill out the form we would like send it to Intercom and create the lead for us.
We can use Zapier integration inside the Unbounce but passing the UTM parameters is not allowed, so we want to use the Intercom API/Javascript directly.
Below is the PHP script that we are using to create lead through WP Intercom API
Anyone how to do the same using Javascript? so I can put inside the Unbounce page script manager.
$client = new IntercomClient('xxxxxxxxxxxxx=', null);
try {
// First check if this already exists
$leads = $client->leads->getLeads(['email' => $post['email']]);
foreach ($leads->contacts as $lead) {
$id = $lead->id;
}
if(!$id) {
$id = '';
}
$client->leads->update([
"id" => $id,
"email" => $post['email'],
"name" => preg_replace("/[^a-zA-Z0-9\s]/", "", ucwords($post['first_name'])),
"last_request_at" => time(),
"last_seen_ip" => $_SERVER['REMOTE_ADDR'],
"utm_campaign" => $post['Utm_campaign],
"utm_content" => $post['Utm_content'],
"utm_medium" => $post['Utm_medium'],
"utm_source" => $post['Utm_source'],
"utm_term" => $post['Utm_term'],
'Form Message' => preg_replace("/[^a-zA-Z0-9\s]/", "", $post['description'])]
]);
} catch(ClientException $e) {
$response = $e->getResponse();
$statusCode = $response->getStatusCode();
if ($statusCode == '404') {
// Handle 404 error
return;
} else {
throw $e;
}
}
Stripe are soon to roll out their use of Strong Customer Authentication for payments with their platform. There's a fairly substantial section in their documentation about it.
https://stripe.com/docs/payments/payment-intents/quickstart#manual-confirmation-flow
The process has the following flow:
The vanilla PHP implementation is like so:
<?php
# vendor using composer
require_once('vendor/autoload.php');
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
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
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $json_obj->payment_method_id,
'amount' => 1099,
'currency' => 'gbp',
'confirmation_method' => 'manual',
'confirm' => true,
]);
}
if (isset($json_obj->payment_intent_id)) {
$intent = \Stripe\PaymentIntent::retrieve(
$json_obj->payment_intent_id
);
$intent->confirm();
}
generatePaymentResponse($intent);
} catch (\Stripe\Error\Base $e) {
# Display error on client
echo json_encode([
'error' => $e->getMessage()
]);
}
function generatePaymentResponse($intent) {
# Note that if your API version is before 2019-02-11, 'requires_action'
# appears as 'requires_source_action'.
if ($intent->status == 'requires_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']);
}
}
?>
The necessary JavaScript for its use with Stripe Elements looks like this:
var cardholderName = document.getElementById('cardholder-name');
var cardButton = document.getElementById('card-button');
cardButton.addEventListener('click', function(ev) {
stripe.createPaymentMethod('card', cardElement, {
billing_details: {name: cardholderName.value}
}).then(function(result) {
if (result.error) {
// Show error in payment form
} else {
// Otherwise send paymentMethod.id to your server (see Step 2)
fetch('/ajax/confirm_payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_method_id: result.paymentMethod.id })
}).then(function(result) {
// Handle server response (see Step 3)
result.json().then(function(json) {
handleServerResponse(json);
})
});
}
});
});
function handleServerResponse(response) {
if (response.error) {
// Show error from server on payment form
} else if (response.requires_action) {
// 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('/ajax/confirm_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
}
}
In my own project I'm using Laravel which is entirely based on the MVC architecture and it fairly nice to you when it comes to most things.
I have tried to refactor a little but I have a question.
Why would you use this line $json_str = file_get_contents('php://input'); over just trying to grab the posted variables from the Request object used in Laravel?
I also read the following article from the PHP Manual:
https://www.php.net/manual/en/wrappers.php.php
To be perfectly honest I've been away from procedural PHP so this has confused me to no end.
Why use 'php://input' over the POST superglobal - Stripe SCA example
The body is encoded as JSON. You can tell because the next line explicitly decodes it.
PHP doesn't understand application/json requests. It will only populate $_POST if the data is encoding using the application/x-www-form-urlencoded or multipart/form-data formats.
Why would you use this line $json_str = file_get_contents('php://input'); over just trying to grab the posted variables from the Request object used in Laravel?
If you were using Laravel, there's no reason to do that.
Since there is no sign of anything Laravel in the example you gave, it is presumably not written with the intention of introducing a dependency on Laravel.
I am trying to replicate the functionality to share a story on a Facebook wall similar to what this site has.
When you click on the share it should ask you to authenticate to facebook, if you are already authenticated it should show you the story to post to facebook.
I got the authentication part to work using the JavaScript SDK . I am not sure how to show the content to post to the wall.
Could anyone please provide an example.
Thanks!
<?php
# We require the library
require("facebook.php");
# Creating the facebook object
$facebook = new Facebook(array(
'appId' => 'YOUR_APP_ID',
'secret' => 'YOUR_APP_SECRET',
'cookie' => true
));
# Let's see if we have an active session
$session = $facebook->getSession();
if(!empty($session)) {
# Active session, let's try getting the user id (getUser()) and user info (api->('/me'))
try{
$uid = $facebook->getUser();
# let's check if the user has granted access to posting in the wall
$api_call = array(
'method' => 'users.hasAppPermission',
'uid' => $uid,
'ext_perm' => 'publish_stream'
);
$can_post = $facebook->api($api_call);
if($can_post){
# post it!
# $facebook->api('/'.$uid.'/feed', 'post', array('message' => 'Saying hello from my Facebook app!'));
# using all the arguments
$facebook->api('/'.$uid.'/feed', 'post', array(
'message' => 'The message',
'name' => 'The name',
'description' => 'The description',
'caption' => 'The caption',
'picture' => 'http://i.imgur.com/yx3q2.png',
'link' => 'http://net.tutsplus.com/'
));
echo 'Posted!';
} else {
die('Permissions required!');
}
} catch (Exception $e){}
} else {
# There's no active session, let's generate one
$login_url = $facebook->getLoginUrl();
header("Location: ".$login_url);
}
?>
http://developers.facebook.com/docs/reference/api/post/