رفتن به محتوای اصلی
سرویکس وب‌سرویس و API داده‌های بازار ایران

راهنمای PHP برای API ارز

دریافت نرخ ارز با PHP از وب‌سرویس و API سرویکس

اتصال امن PHP 8.2 به وب‌سرویس و API نرخ ارز سرویکس را با cURL، نگهداری سمت سرور API Key، timeout، اعتبارسنجی JSON، کنترل تازگی و retry محدود پیاده‌سازی و تست کنید.

این راهنما قرارداد احرازشده supported-assets سرویکس را با PHP 8.2 یا جدیدتر پیاده‌سازی می‌کند. نمونه کامل و بدون وابستگی Composer در مسیر docs/examples/php، لایه HTTP را از اعتبارسنجی قرارداد جدا کرده است تا همه مسیرهای موفق و ناموفق بدون تماس با production تست شوند.

کد را فقط روی سرور، queue worker، job زمان‌بندی‌شده یا CLI قابل اعتماد و با افزونه cURL اجرا کنید. API Key یا response احرازشده سرویکس نباید وارد کد مرورگر، URL، HTML عمومی، analytics، گزارش خطا یا log عمومی شود.

تنظیم سمت سرور

export SERVIX_API_KEY="<your-servix-api-key>"
export SERVIX_ASSET_CODE="USD_RLS"

php -l docs/examples/php/src/ServixApiClient.php
php docs/examples/php/tests/ServixApiClientTest.php
php docs/examples/php/example.php

ServixApiClient::fromEnvironment() کلید را هنگام شروع process می‌خواند. برای توسعه و production کلید جدا بسازید، دسترسی به environment یا secret manager را محدود کنید و بعد از احتمال افشا کلید را فوری لغو کنید.

ارسال درخواست با cURL

transport تست‌شده redirect را می‌بندد، timeout اتصال و کل درخواست را مشخص می‌کند، فقط protocolهای HTTP و HTTPS را می‌پذیرد و status، header امن و body را به validator می‌دهد. API Key فقط در header درخواست قرار می‌گیرد.

<?php

$handle = curl_init(
    $baseUrl . '/api/v1/assets/supported',
);
$responseHeaders = [];

curl_setopt_array($handle, [
    CURLOPT_CONNECTTIMEOUT_MS => 3_000,
    CURLOPT_TIMEOUT_MS => 10_000,
    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_HTTPHEADER => [
        'Accept: application/json',
        'X-API-Key: ' . $apiKey,
    ],
    CURLOPT_PROTOCOLS => CURLPROTO_HTTPS | CURLPROTO_HTTP,
    CURLOPT_RETURNTRANSFER => true,
]);

$body = curl_exec($handle);
if ($body === false) {
    throw new ServixNetworkException(
        'Servix network request failed.',
    );
}
$status = (int) curl_getinfo(
    $handle,
    CURLINFO_RESPONSE_CODE,
);
curl_close($handle);

try {
    $payload = json_decode(
        $body,
        true,
        64,
        JSON_THROW_ON_ERROR,
    );
} catch (JsonException $exception) {
    throw new ServixSchemaException(
        'Servix returned malformed JSON.',
    );
}

بررسی دسترسی و تازگی

$asset = null;
foreach ($payload['assets'] ?? [] as $candidate) {
    if (is_array($candidate)
        && ($candidate['code'] ?? null) === $assetCode) {
        $asset = $candidate;
        break;
    }
}
if ($asset === null) {
    throw new ServixUnavailableException();
}

foreach (['providerSupported', 'latestValueAvailable', 'stale'] as $field) {
    if (!array_key_exists($field, $asset)
        || !is_bool($asset[$field])) {
        throw new ServixSchemaException();
    }
}
if (!$asset['providerSupported']
    || !$asset['latestValueAvailable']) {
    throw new ServixUnavailableException();
}
if ($asset['stale']
    || ($asset['availabilityStatus'] ?? null) !== 'FRESH') {
    throw new ServixStaleDataException();
}
if ((!is_int($asset['latestValue'])
    && !is_float($asset['latestValue']))
    || !is_finite((float) $asset['latestValue'])) {
    throw new ServixSchemaException();
}

نسخه کامل HTTPS، HTTP محدود به loopback تست، شکل asset code، timezone در businessTime، هماهنگی تازگی، عدد finite و request ID امن را هم پیش از ساخت AssetQuote immutable بررسی می‌کند.

قرارداد response احرازشده

{
  "code": "USD_RLS",
  "providerSupported": true,
  "latestValueAvailable": true,
  "latestValue": "<protected-market-value>",
  "businessTime": "<source-timestamp>",
  "availabilityStatus": "FRESH",
  "stale": false
}

businessTime زمان خود داده است. وضعیت‌های STALE، MISSING و UNKNOWN را حالت‌های واقعی محصول بدانید. برای داده unavailable صفر نسازید و مقدار قدیمی را بدون برچسب stale استفاده نکنید. کدهای پایان‌یافته به _RLS ریالی هستند؛ تبدیل به تومان را در لایه نمایش خودتان انجام دهید.

خطای HTTP و retry محدود

وضعیترفتار PHP
خطای اتصال یا timeout در cURLحداکثر سه بار با فاصله نمایی retry کنید و بعد فقط دسته خطای امن را برگردانید.
400، 401، 403، 404درخواست بدون تغییر را retry نکنید؛ request، API Key، دسترسی حساب یا asset code را اصلاح کنید.
429سهمیه روزانه تمام شده است؛ polling را تا پنجره بعدی متوقف کنید.
500، 502، 503، 504retry محدود خطای موقت را اجرا کنید و بعد امن fail شوید.
JSON یا قرارداد خرابresponse را رد کنید؛ نوع فیلد را حدس نزنید و مقدار ساختگی نسازید.

تست‌ها یک transport ساختگی تزریق می‌کنند و URL، header، timeout، mapping موفق، backoff شبکه و 5xx، رفتار 401 و 429، JSON خراب، boolean ناقص، داده stale و unavailable، asset ناشناخته و تنظیم ناامن را می‌سنجند. هیچ کلید واقعی یا response بازار production برای تست لازم نیست.

cache و ادامه مسیر

فقط response احرازشده و معتبر را در بک‌اند cache کنید و businessTime را کنار آن نگه دارید. cache را میان کاربران مشترک کنید، TTL را کوتاه‌تر از پنجره تازگی قابل قبول بگذارید و برای هر مرورگر polling جدا نسازید. احراز هویت، نمادهای پشتیبانی‌شده، خطا و سهمیه، راهنمای Spring Boot و راهنمای Python را هم ببینید.

ساخت حساب و فعال‌سازی دسترسی API · مقایسه پلن‌ها و سهمیه روزانه