v1.0.0.0
StocketBase
- <?php
-
- declare(strict_types=1);
-
- require_once __DIR__ . '/../config.php';
- require_once __DIR__ . '/../site-front.php';
-
- final class StripeClient
- {
- private const API_BASE = 'https://api.stripe.com/v1';
-
- private string $secretKey;
-
- public function __construct(?string $secretKey = null)
- {
- $this->secretKey = $secretKey ?? (string) (SiteFront::settings()['payment_stripe_secret_key'] ?? '');
- }
-
- public function createCheckoutSession(
- array $lineItems,
- string $mode,
- string $successUrl,
- string $cancelUrl,
- ?string $customerEmail,
- array $metadata = [],
- ?string $couponId = null
- ): ?array {
- if ($this->secretKey === '') {
- error_log('StripeClient: cannot create checkout session, no secret key configured.');
-
- return null;
- }
-
- if (empty($lineItems)) {
- error_log('StripeClient: cannot create checkout session with no line items.');
-
- return null;
- }
-
- $items = [];
- foreach (array_values($lineItems) as $index => $item) {
- $priceData = [
- 'currency' => strtolower((string) ($item['currency'] ?? 'usd')),
- 'product_data' => [
- 'name' => (string) ($item['name'] ?? 'Item'),
- ],
- 'unit_amount' => max(0, (int) ($item['unit_amount_cents'] ?? 0)),
- ];
-
- $recurringInterval = $item['recurring_interval'] ?? null;
- if ($recurringInterval !== null && $recurringInterval !== '') {
- $priceData['recurring'] = ['interval' => (string) $recurringInterval];
- }
-
- $items[$index] = [
- 'price_data' => $priceData,
- 'quantity' => max(1, (int) ($item['quantity'] ?? 1)),
- ];
- }
-
- $formData = [
- 'mode' => $mode,
- 'success_url' => $successUrl,
- 'cancel_url' => $cancelUrl,
- 'line_items' => $items,
- ];
-
- if ($customerEmail !== null && $customerEmail !== '') {
- $formData['customer_email'] = $customerEmail;
- }
-
- foreach ($metadata as $key => $value) {
- $formData['metadata'][$key] = (string) $value;
- if ($mode === 'subscription') {
- $formData['subscription_data']['metadata'][$key] = (string) $value;
- }
- }
-
- if ($couponId !== null && $couponId !== '') {
- $formData['discounts'] = [['coupon' => $couponId]];
- }
-
- [$status, $body] = $this->post('/checkout/sessions', $formData);
-
- if ($status < 200 || $status >= 300 || !isset($body['url'])) {
- error_log('StripeClient: checkout session creation failed with HTTP ' . $status . ' — ' . (string) json_encode($body));
-
- return null;
- }
-
- return $body;
- }
-
- public function createOneTimeCoupon(int $amountOffCents, string $currency, string $name): ?string
- {
- if ($this->secretKey === '' || $amountOffCents <= 0) {
- return null;
- }
-
- [$status, $body] = $this->post('/coupons', [
- 'amount_off' => $amountOffCents,
- 'currency' => strtolower($currency),
- 'duration' => 'once',
- 'max_redemptions' => 1,
- 'name' => mb_substr($name, 0, 40),
- ]);
-
- if ($status < 200 || $status >= 300 || empty($body['id'])) {
- error_log('StripeClient: coupon creation failed with HTTP ' . $status . ' — ' . (string) json_encode($body));
-
- return null;
- }
-
- return (string) $body['id'];
- }
-
- public function createRefund(string $paymentIntentOrChargeId, ?int $amountCents = null): bool
- {
- if ($this->secretKey === '') {
- error_log('StripeClient: cannot create refund, no secret key configured.');
-
- return false;
- }
-
- $idField = str_starts_with($paymentIntentOrChargeId, 'ch_') ? 'charge' : 'payment_intent';
-
- $formData = [$idField => $paymentIntentOrChargeId];
- if ($amountCents !== null) {
- $formData['amount'] = max(0, $amountCents);
- }
-
- [$status, $body] = $this->post('/refunds', $formData);
-
- if ($status < 200 || $status >= 300) {
- error_log('StripeClient: refund failed with HTTP ' . $status . ' — ' . (string) json_encode($body));
-
- return false;
- }
-
- return true;
- }
-
- private function post(string $path, array $formData): array
- {
- $url = self::API_BASE . $path;
- $body = http_build_query($formData, '', '&', PHP_QUERY_RFC1738);
-
- if (!function_exists('curl_init')) {
- error_log('StripeClient: cURL extension is not available.');
-
- return [0, []];
- }
-
- $curl = curl_init($url);
- curl_setopt_array($curl, [
- CURLOPT_POST => true,
- CURLOPT_POSTFIELDS => $body,
- CURLOPT_HTTPHEADER => [
- 'Authorization: Bearer ' . $this->secretKey,
- 'Content-Type: application/x-www-form-urlencoded',
- ],
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_CONNECTTIMEOUT => 10,
- CURLOPT_TIMEOUT => 20,
- ]);
- $response = curl_exec($curl);
- $status = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
- $curlError = curl_error($curl);
- curl_close($curl);
-
- if ($response === false) {
- error_log('StripeClient: request failed — ' . $curlError);
-
- return [0, []];
- }
-
- $decoded = json_decode($response, true);
-
- return [$status, is_array($decoded) ? $decoded : []];
- }
- }
-