93 lines
3.1 KiB
PHP
93 lines
3.1 KiB
PHP
<?php
|
|
|
|
class PayPalClient
|
|
{
|
|
private string $clientId;
|
|
private string $clientSecret;
|
|
private string $env; // sandbox|live
|
|
private string $baseApi;
|
|
|
|
public function __construct(array $config)
|
|
{
|
|
$this->clientId = $config['client_id'] ?? '';
|
|
$this->clientSecret = $config['client_secret'] ?? '';
|
|
$this->env = $config['env'] ?? 'sandbox';
|
|
$this->baseApi = $this->env === 'live'
|
|
? 'https://api-m.paypal.com'
|
|
: 'https://api-m.sandbox.paypal.com';
|
|
|
|
if (!$this->clientId || !$this->clientSecret) {
|
|
throw new RuntimeException('Missing PayPal client_id/client_secret in config.php');
|
|
}
|
|
}
|
|
|
|
public function getAccessToken(): string
|
|
{
|
|
$url = $this->baseApi . '/v1/oauth2/token';
|
|
$headers = [
|
|
'Accept: application/json',
|
|
'Accept-Language: en_US',
|
|
];
|
|
$body = 'grant_type=client_credentials';
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_HTTPHEADER => $headers,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => $body,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_USERPWD => $this->clientId . ':' . $this->clientSecret,
|
|
]);
|
|
$resp = curl_exec($ch);
|
|
if ($resp === false) {
|
|
throw new RuntimeException('OAuth token request failed: ' . curl_error($ch));
|
|
}
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
$data = json_decode($resp, true);
|
|
if ($code < 200 || $code >= 300 || !isset($data['access_token'])) {
|
|
throw new RuntimeException('OAuth token response error (' . $code . '): ' . $resp);
|
|
}
|
|
return $data['access_token'];
|
|
}
|
|
|
|
public function api(string $method, string $path, array $payload = null, array $headers = []): array
|
|
{
|
|
$url = $this->baseApi . $path;
|
|
$accessToken = $this->getAccessToken();
|
|
$defaultHeaders = [
|
|
'Content-Type: application/json',
|
|
'Authorization: Bearer ' . $accessToken,
|
|
];
|
|
$allHeaders = array_merge($defaultHeaders, $headers);
|
|
|
|
$ch = curl_init($url);
|
|
$opts = [
|
|
CURLOPT_HTTPHEADER => $allHeaders,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_CUSTOMREQUEST => strtoupper($method),
|
|
];
|
|
if ($payload !== null) {
|
|
$opts[CURLOPT_POSTFIELDS] = json_encode($payload);
|
|
}
|
|
curl_setopt_array($ch, $opts);
|
|
$resp = curl_exec($ch);
|
|
if ($resp === false) {
|
|
throw new RuntimeException('API request failed: ' . curl_error($ch));
|
|
}
|
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
$data = json_decode($resp, true);
|
|
if ($data === null && $resp !== '' && $resp !== 'null') {
|
|
// not JSON but body present
|
|
$data = ['raw' => $resp];
|
|
}
|
|
return ['status' => $code, 'body' => $data];
|
|
}
|
|
|
|
public function getBaseApi(): string
|
|
{
|
|
return $this->baseApi;
|
|
}
|
|
}
|