Reputation: 45
I've got problem with Checkout Session method in Stripe API. When I hardcode values for price and quantity, Stripe will allow me to use multiple items in checkout, but when I try to load those values dynamically, it only lists first product in cart. Here is example of hardcoded values:
$product = \Stripe\Product::create([
'name' => "{$row['product_title']}",
'images' => [
"https://moto-d.net/wp-content/uploads/2018/01/webshop.jpg"
]
]);
$price_100 = $row['product_price'] * 100;
$price = \Stripe\Price::create([
'product' => "{$product['id']}",
'unit_amount' => "{$price_100}",
'currency' => 'eur'
]);
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price' => 'price_1H1qQRAvwpgnxaFsFErrYUQs',
'quantity' => 1
], [
'price' => 'price_1H1qQSAvwpgnxaFsXR3XO8Sg',
'quantity' => 1
], [
'price' => 'price_1H1qQTAvwpgnxaFsfAAn8FMI',
'quantity' => 1
], [
'price' => 'price_1H1qQUAvwpgnxaFsX9KRfDPE',
'quantity' => 1
]],
'mode' => 'payment',
'success_url' => "http://localhost/e-com-master/public/thank_you.php",
'cancel_url' => "http://localhost/e-com-master/public/index.php",
]);
}
}
}
return $session['id'];
With this code, it works perfectly. But, problems are here (I am using array for storing theese values):
$line_items_array = array(
"price" => $price['id'],
"quantity" => $value
);
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [$line_items_array],
'mode' => 'payment',
'success_url' => "http://localhost/e-com-master/public/thank_you.php",
'cancel_url' => "http://localhost/e-com-master/public/index.php",
]);
Could anyone notice mistake I am making? I suppose that I am not pushing values in array in appropriate way.
Upvotes: 1
Views: 3741
Reputation: 31
Edited: I did some tests using the Stripe PHP library and their example code. I think your error is that you left the brackets in:
'line_items' => [$line_items_array],
It should look like this instead.
'line_items' => $line_items_array,
The readymade array for the line_items parameter should be a numeric index, with a nested multidimensional associative array.
//Here is a functional example that returns a successful checkout session:
<pre>
<?php
$currency = 'eur';
$products = array (
array (
'unit_amount' => 1000,
'name' => 'product 1',
'images' => 'https://i.imgur.com/EHyR2nP.png',
'quantity' => '1'
),
array (
'unit_amount' => 2000,
'name' => 'product 2',
'images' => 'https://i.imgur.com/EHyR2nP.png',
'quantity' => '2'
),
);
foreach ($products as $product) {
$line_items_array[] = array(
'price_data' => array(
'currency' => $currency,
'unit_amount' => $product['unit_amount'],
'product_data' => array(
'name' => $product['name'],
'images' => array($product['images']),
),
),
'quantity' => $product['quantity'],
);
}
print_r ($line_items_array);
?>
</pre>
//the output
Array
(
[0] => Array
(
[price_data] => Array
(
[currency] => eur
[unit_amount] => 1000
[product_data] => Array
(
[name] => product 1
[images] => Array
(
[0] => https://i.imgur.com/EHyR2nP.png
)
)
)
[quantity] => 1
)
[1] => Array
(
[price_data] => Array
(
[currency] => eur
[unit_amount] => 2000
[product_data] => Array
(
[name] => product 2
[images] => Array
(
[0] => https://i.imgur.com/EHyR2nP.png
)
)
)
[quantity] => 2
)
)
Upvotes: 0
Reputation: 11
I just ran into this a few weeks ago. Stripe Support wasn't interested in helping.
Overview:
line_items
you want via your frontend code.product
, quantity
, etc.JSON.stringify()
) to the backend PHP.line_items
key of \Stripe\Checkout\Session::create()
.It's pretty straight forward, but was tricky to get right because I wasn't used to PHP.
These were really helpful to me, as a PHP novice:
I'm including everything for your create-checkout-session.php
file. Not just the foreach()
.
<?php
/* Standard Stripe API stuff */
require 'vendor/autoload.php';
\Stripe\Stripe::setApiKey("STRIPE_LIVE_SECRET_KEY_HERE");
header('Content-Type: application/json');
$YOUR_DOMAIN = 'http://localhost:4242';
/* Read in the JSON sent via the frontend */
$json_str = file_get_contents('php://input');
/*
* Convert to PHP object
* - NOT setting `json_decode($json_str, TRUE)` because having the data decoded into an *object* seems to work well. Also, Stripe's own sample code, for custom flows, does not set to `TRUE`.
* - https://www.php.net/manual/en/function.json-decode.php
*/
$data = json_decode($json_str);
/* Create array to accept multiple `line_item` objects */
$lineItemsArray = [];
/*
* [OPTIONAL] Create array to combine multiple keys from each`line_item` into a single one for `payment_intent_data.description`
* - Only required if you want to pass along this type of description that's either provided by the user or by your frontend logic.
* - IOW: It was useful to me, but it might not be to you.
*/
$descriptionInternal = [];
/* Convert the incoming JSON key/values into a PHP array() that the Stripe API will accept below in `\Stripe\Checkout\Session::create()` */
foreach($data as $key => $value) {
/*
* Swap frontend `price` for backend Stripe `price id`
* - If you have Products/Prices that you created in the Stripe Dashboard, you might want to keep those Ids secret (although I don't know if that matters).
* - So you'll need to convert whatever you define them as on the frontend (public), to the Stripe PriceId equivalents (private).
* - This switch statement does that.
*/
switch ($value->price) {
case 50:
$value->price = "price_1Iaxxxxxxx";
break;
case 100:
$value->price = "price_1Ibxxxxxxx";
break;
case 150:
$value->price = "price_1Icxxxxxxx";
break;
default:
$value->price = "price_1Iaxxxxxxx";
}
/* `array_push` this object shape, for each `line_item` entry, into the array created outside of this `foreach()` loop. */
array_push($lineItemsArray,
[
"price" => $value->price,
"quantity" => $value->quantity,
"customerName" => $value->customer_name,
"recipientName" => $value->recipient_name,
"description" => $value->description /* Customer facing on the Stripe "Pay" page */
/*
* Add whatever else you want to include, with each `line_item`, here.
* - Stripe API allows:
* - https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-line_items
*/
]);
/*
* [OPTIONAL] `array_push` some or all of the `line_item` key values in a combined form.
* - Handy (in some cases) if you want to see a quick readout of the entire purchase in your Stripe Dashboard "Purchases" listing (i.e.: Saves you from having click into it to see the details).
* - Or you could construct this via your frontend code and pass it as a string.
* - But I'm including this here, in case you want to do it, or something like it, in in PHP.
* - Example final result: "[Axl: 3 Guns N' Roses for Duff] [Slash: 6 Guns N' Roses for Izzy]"
*/
array_push(
$descriptionInternal,
("[" . $value->customerName . ": " . $value->quantity . " Guns N' Roses for " . $value->recipientName) . "]");
}
/* [OPTIONAL] `payment_intent_data.description` takes a string, not an array. */
$descriptionInternal = implode(" ", $descriptionInternal);
/* https://stripe.com/docs/api/checkout/sessions/create */
$checkout_session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
/* Takes in the array from above */
'line_items' => $lineItemsArray,
/* [OPTIONAL] Single `payment_intent_data.description` */
'payment_intent_data' => [
'description' => $descriptionInternal, /* This version of "Description" is displayed in the Dashboard and on Customer email receipts. */
],
'mode' => 'payment',
'success_url' => $YOUR_DOMAIN . '/success.html',
'cancel_url' => $YOUR_DOMAIN . '/cancel.html',
]);
echo json_encode(['id' => $checkout_session->id]);
Upvotes: 1
Reputation: 1
Probably a bit late to reply now, but anyway after much testing and trial and error here is what worked for me.
I found that passing the array list was a major pain, so I had to reassemble the array once I recieved it from input as json, before passing it to Stripe Create, which even then, only seemed to work properly when I used eval on the array when passing it. Mainly posting this to help anyone avoid the pain I went through :), I am sure there are way better ways to do it, but I could find no examples anywhere at the time and this has been working fine now for almost a year so I haven't looked to improve or modify as yet.
<?php
header("Content-Type: application/json");
require_once('stripe/vendor/autoload.php');
// Set your secret key. Remember to switch to your live secret key in production!
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey('whateveryouroneis');
// grab the json data from the cart, sent via php input
$data = (array) json_decode(file_get_contents("php://input"), TRUE);
//get the current webpage URL
$returnToPage = $_COOKIE["whateveryoursis"];
/**
* recursive read though what we recieved, try to get it to pass by rebuilding it
*/
function displayArrayRecursively($arr) {
if ($arr) {
foreach ($arr as $key => $value) {
if (is_array($value)) {
$arrs .= displayArrayRecursively($value);
} else {
// Output
if ( $key == 'name' ) {
$arrs .= " [ \"$key\" => '$value', \n";
}
elseif ( $key == 'quantity' ) {
$arrs .= " \"$key\" => $value , ], \n";
}
elseif ( in_array($key, ['description','currency'], true )) {
$arrs .= " \"$key\" => '$value', \n";
}
elseif ( $key == 'amount' ) {
$arrs .= " \"$key\" => " . $value * 100 . ", \n";
}
else {
$arrs .= " \"$key\" => ['$value'], \n";
}
}
}
}
return $arrs;
}
$line_items_str = displayArrayRecursively($data);
$createSession_str = (
"'payment_method_types' => ['card']," .
"'success_url' => '" . $returnToPage . "?success=1'," .
"'cancel_url' => '" . $returnToPage . "'," .
"'shipping_address_collection' => [" .
"'allowed_countries' => ['GB'], ]," .
"'line_items' => [" . $line_items_str . " ], ");
// create the checkout session on Stripe
eval ( $session = "\$session = \Stripe\Checkout\Session::create( [ " .
$createSession_str . " ] );" );
$stripeSession = array($session);
// test while working on it :-
// var_dump($stripeSession);
$sessId = ($stripeSession[0]['id']);
echo $sessId;
Upvotes: 0
Reputation: 11
$line_items_array = array(
'price' => "{$price['id']}",
'quantity' => "{$value}"
);
and
'line_items' => [[$line_items_array]],
Upvotes: 1