Files
erp_naurua/modules/erp/import-integration/shopify-api.php
T

133 lines
4.4 KiB
PHP

<?php
declare(strict_types=1);
function shopify_api_request_json(string $url, string $method, array $headers, string $body, int $timeoutSeconds = 20): array
{
$headerLines = [];
foreach ($headers as $name => $value) {
if ($name !== '' && $value !== '') {
$headerLines[] = $name . ': ' . $value;
}
}
$context = stream_context_create([
'http' => [
'method' => $method,
'header' => implode("\r\n", $headerLines),
'content' => $body,
'timeout' => $timeoutSeconds,
'ignore_errors' => true,
],
]);
$responseBody = @file_get_contents($url, false, $context);
$responseHeaders = $http_response_header ?? [];
$status = 0;
if (isset($responseHeaders[0]) && preg_match('#HTTP/\S+\s+(\d{3})#', $responseHeaders[0], $matches) === 1) {
$status = (int) $matches[1];
}
if ($responseBody === false || $responseBody === '') {
throw new RuntimeException('Shopify API returned an empty response');
}
try {
$decoded = json_decode($responseBody, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw new RuntimeException('Shopify API returned invalid JSON', 0, $exception);
}
if (!is_array($decoded)) {
throw new RuntimeException('Shopify API returned a non-object JSON response');
}
return ['status' => $status, 'body' => $decoded];
}
function shopify_api_credentials(array $env): array
{
$shop = trim(env_value('SHOPIFY_SHOP', $env));
$clientId = trim(env_value('SHOPIFY_CLIENT_ID', $env));
$clientSecret = trim(env_value('SHOPIFY_CLIENT_SECRET', $env));
$apiVersion = trim(env_value('SHOPIFY_API_VERSION', $env));
if ($shop === '' || $clientId === '' || $clientSecret === '' || $apiVersion === '') {
throw new RuntimeException('Incomplete Shopify API configuration');
}
if (!preg_match('/^[a-z0-9][a-z0-9-]*\.myshopify\.com$/', $shop)) {
throw new RuntimeException('Invalid Shopify shop domain');
}
if (!preg_match('/^\d{4}-\d{2}$/', $apiVersion)) {
throw new RuntimeException('Invalid Shopify API version');
}
return [
'shop' => $shop,
'client_id' => $clientId,
'client_secret' => $clientSecret,
'api_version' => $apiVersion,
];
}
function shopify_api_access_token(array $env): string
{
$credentials = shopify_api_credentials($env);
$body = http_build_query([
'grant_type' => 'client_credentials',
'client_id' => $credentials['client_id'],
'client_secret' => $credentials['client_secret'],
], '', '&', PHP_QUERY_RFC3986);
$response = shopify_api_request_json(
'https://' . $credentials['shop'] . '/admin/oauth/access_token',
'POST',
['Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json'],
$body
);
if ($response['status'] < 200 || $response['status'] >= 300) {
throw new RuntimeException('Shopify access-token request failed');
}
$token = trim((string) ($response['body']['access_token'] ?? ''));
if ($token === '') {
throw new RuntimeException('Shopify access-token response did not contain a token');
}
return $token;
}
function shopify_graphql_query(array $env, string $query, array $variables = []): array
{
if (trim($query) === '') {
throw new InvalidArgumentException('Shopify GraphQL query must not be empty');
}
$credentials = shopify_api_credentials($env);
$token = shopify_api_access_token($env);
$request = ['query' => $query];
if ($variables !== []) {
$request['variables'] = $variables;
}
$body = json_encode($request, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
$response = shopify_api_request_json(
'https://' . $credentials['shop'] . '/admin/api/' . $credentials['api_version'] . '/graphql.json',
'POST',
['Content-Type' => 'application/json', 'Accept' => 'application/json', 'X-Shopify-Access-Token' => $token],
$body
);
if ($response['status'] < 200 || $response['status'] >= 300) {
throw new RuntimeException('Shopify GraphQL request failed');
}
$errors = $response['body']['errors'] ?? [];
if (is_array($errors) && $errors !== []) {
throw new RuntimeException('Shopify GraphQL returned errors');
}
return (array) ($response['body']['data'] ?? []);
}