dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
dbxShopPayPal.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\dbxShop;
3
5
6 private function config(): array {
7 $file = dirname(__DIR__) . '/cfg/payment.php';
8 $paypal = array();
9 if (!is_file($file)) {
10 $paypal = array();
11 } else {
12 $cfg = include $file;
13 $paypal = is_array($cfg) ? ($cfg['paypal'] ?? array()) : array();
14 }
15
16 if (function_exists('dbx')) {
17 $shopCfg = dbx()->get_config('dbxShop');
18 if (is_array($shopCfg)) {
19 $paypal = array_merge($paypal, array(
20 'enabled' => !empty($shopCfg['payment_paypal_enabled']),
21 'mode' => (string)($shopCfg['payment_paypal_mode'] ?? ($paypal['mode'] ?? 'sandbox')),
22 'client_id' => (string)($shopCfg['payment_paypal_client_id'] ?? ($paypal['client_id'] ?? '')),
23 'client_secret' => (string)($shopCfg['payment_paypal_client_secret'] ?? ($paypal['client_secret'] ?? '')),
24 'brand_name' => (string)($shopCfg['payment_paypal_brand_name'] ?? ($paypal['brand_name'] ?? 'dbXapp')),
25 'currency' => (string)($shopCfg['payment_paypal_currency'] ?? $shopCfg['default_currency'] ?? ($paypal['currency'] ?? 'EUR')),
26 ));
27 }
28 }
29
30 return $paypal;
31 }
32
33 public function isConfigured(): bool {
34 $cfg = $this->config();
35 return !empty($cfg['enabled'])
36 && trim((string)($cfg['client_id'] ?? '')) !== ''
37 && trim((string)($cfg['client_secret'] ?? '')) !== '';
38 }
39
40 public function mode(): string {
41 $cfg = $this->config();
42 return (string)($cfg['mode'] ?? 'sandbox') === 'live' ? 'live' : 'sandbox';
43 }
44
45 public function configHint(): string {
46 return 'PayPal ist vorbereitet. Aktivieren Sie PayPal unter Shop > Einstellungen und tragen Sie Client-ID und Secret ein.';
47 }
48
49 private function apiBase(): string {
50 $cfg = $this->config();
51 return (string)($cfg['mode'] ?? 'sandbox') === 'live'
52 ? 'https://api-m.paypal.com'
53 : 'https://api-m.sandbox.paypal.com';
54 }
55
56 private function request(string $method, string $path, array $headers = array(), ?array $payload = null, ?string $basicUser = null, ?string $basicPassword = null): array {
57 $ch = curl_init($this->apiBase() . $path);
58 $method = strtoupper($method);
59 $body = $payload !== null ? json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : null;
60 $httpHeaders = $headers;
61
62 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
63 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
64 curl_setopt($ch, CURLOPT_TIMEOUT, 25);
65 curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders);
66 if ($basicUser !== null) {
67 curl_setopt($ch, CURLOPT_USERPWD, $basicUser . ':' . (string)$basicPassword);
68 }
69 if ($body !== null) {
70 curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
71 }
72
73 $raw = curl_exec($ch);
74 $status = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
75 $err = curl_error($ch);
76 curl_close($ch);
77
78 if ($raw === false || $err !== '') {
79 throw new \RuntimeException('PayPal-Verbindung fehlgeschlagen: ' . $err);
80 }
81
82 $data = json_decode((string)$raw, true);
83 if (!is_array($data)) {
84 $data = array('raw' => (string)$raw);
85 }
86 if ($status < 200 || $status >= 300) {
87 $msg = $data['message'] ?? $data['name'] ?? ('HTTP ' . $status);
88 throw new \RuntimeException('PayPal-Fehler: ' . $msg);
89 }
90 return $data;
91 }
92
93 private function accessToken(): string {
94 $cfg = $this->config();
95 $clientId = trim((string)($cfg['client_id'] ?? ''));
96 $secret = trim((string)($cfg['client_secret'] ?? ''));
97 if ($clientId === '' || $secret === '') {
98 throw new \RuntimeException('PayPal-Zugangsdaten fehlen.');
99 }
100
101 $ch = curl_init($this->apiBase() . '/v1/oauth2/token');
102 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
103 curl_setopt($ch, CURLOPT_POST, true);
104 curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');
105 curl_setopt($ch, CURLOPT_USERPWD, $clientId . ':' . $secret);
106 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
107 'Accept: application/json',
108 'Accept-Language: de_DE',
109 'Content-Type: application/x-www-form-urlencoded',
110 ));
111 curl_setopt($ch, CURLOPT_TIMEOUT, 25);
112 $raw = curl_exec($ch);
113 $status = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
114 $err = curl_error($ch);
115 curl_close($ch);
116
117 if ($raw === false || $err !== '') {
118 throw new \RuntimeException('PayPal-Token konnte nicht geladen werden: ' . $err);
119 }
120 $data = json_decode((string)$raw, true);
121 if ($status < 200 || $status >= 300 || !is_array($data) || empty($data['access_token'])) {
122 throw new \RuntimeException('PayPal-Token wurde abgelehnt.');
123 }
124 return (string)$data['access_token'];
125 }
126
127 public function createOrder(array $order, string $returnUrl, string $cancelUrl): array {
128 $cfg = $this->config();
129 $token = $this->accessToken();
130 $currency = (string)($cfg['currency'] ?? $order['currency'] ?? 'EUR');
131 $amount = number_format((float)($order['total_gross'] ?? 0), 2, '.', '');
132
133 $payload = array(
134 'intent' => 'CAPTURE',
135 'purchase_units' => array(array(
136 'reference_id' => (string)($order['order_no'] ?? ''),
137 'description' => 'dbXapp Bestellung ' . (string)($order['order_no'] ?? ''),
138 'invoice_id' => (string)($order['order_no'] ?? ''),
139 'amount' => array(
140 'currency_code' => $currency,
141 'value' => $amount,
142 ),
143 )),
144 'payment_source' => array(
145 'paypal' => array(
146 'experience_context' => array(
147 'brand_name' => (string)($cfg['brand_name'] ?? 'dbXapp'),
148 'locale' => 'de-DE',
149 'shipping_preference' => 'NO_SHIPPING',
150 'user_action' => 'PAY_NOW',
151 'return_url' => $returnUrl,
152 'cancel_url' => $cancelUrl,
153 ),
154 ),
155 ),
156 );
157
158 return $this->request('POST', '/v2/checkout/orders', array(
159 'Content-Type: application/json',
160 'Authorization: Bearer ' . $token,
161 'Prefer: return=representation',
162 ), $payload);
163 }
164
165 public function capture(string $paypalOrderId): array {
166 $token = $this->accessToken();
167 return $this->request('POST', '/v2/checkout/orders/' . rawurlencode($paypalOrderId) . '/capture', array(
168 'Content-Type: application/json',
169 'Authorization: Bearer ' . $token,
170 'Prefer: return=representation',
171 ));
172 }
173
174 public function approvalUrl(array $paypalOrder): string {
175 foreach (($paypalOrder['links'] ?? array()) as $link) {
176 if (($link['rel'] ?? '') === 'approve' && !empty($link['href'])) {
177 return (string)$link['href'];
178 }
179 }
180 return '';
181 }
182
183 public function testConnection(): array {
184 if (!$this->isConfigured()) {
185 return array(
186 'ok' => false,
187 'mode' => $this->mode(),
188 'message' => 'PayPal ist nicht vollstaendig konfiguriert.',
189 );
190 }
191
192 try {
193 $token = $this->accessToken();
194 return array(
195 'ok' => $token !== '',
196 'mode' => $this->mode(),
197 'message' => $token !== ''
198 ? 'PayPal OAuth Token wurde erfolgreich geladen.'
199 : 'PayPal OAuth Token ist leer.',
200 );
201 } catch (\Throwable $e) {
202 return array(
203 'ok' => false,
204 'mode' => $this->mode(),
205 'message' => $e->getMessage(),
206 );
207 }
208 }
209}
210?>
$cfg
createOrder(array $order, string $returnUrl, string $cancelUrl)
capture(string $paypalOrderId)
if( $syncRequest)
Definition index.php:520
DBX schema administration.
foreach( $topics as $file=> $html)