
# مخزن ملفات تعريف الارتباط

افتراضيًا، تتجاهل `fetch()` في Phasis ملفات تعريف الارتباط `Set-Cookie` الواردة في الاستجابات، ولا ترسل ترويسة `Cookie` في الطلبات. وهذا هو الإعداد المناسب للتضمين على الخادم؛ فعادةً لا تريد أن تؤثر استجابة مستخدم في طلب مستخدم آخر.

إذا كنت تحتاج إلى ملفات تعريف الارتباط — لتشغيل تدفق يعتمد على حالة الجلسة، أو الكشط بعد تسجيل الدخول، أو محاكاة سلوك المتصفح في الاختبارات — فأرفق مخزنًا باستخدام `$engine->setCookieJar($jar)`.

## الواجهة

يمكن أن يكون المخزن أي كائن يستجيب لطريقتين:

```
get(url: string): string         // returns a "Cookie:" header value, e.g. "sid=abc; pref=dark"
set(url: string, header: string): void   // receives one Set-Cookie line
```

تعمل كائنات PHP وكذلك كائنات `JsObject` الموجودة في JS ذات الأعضاء المطابقة. يؤدي تمرير `null` إلى إفراغ المخزن.

يستدعي Phasis الدالة `get(url)` مرة لكل انتقال في الطلب (لذا تحصل التحويلات إلى مضيف مختلف على ملفات تعريف ارتباط حديثة)، ويستدعي `set(url, line)` مرة لكل ترويسة `Set-Cookie` في الاستجابة. تقع مسؤولية *سياسة* ملفات تعريف الارتباط — مطابقة النطاق وتحديد المسار وانتهاء الصلاحية و`SameSite` و`Secure` — على عاتق المخزن، لا Phasis.

## مخزن داخل الذاكرة (للاختبارات)

```php
final class MemoryJar
{
    /** @var array<string, array<string, string>> host → name → "name=value" */
    private array $store = [];

    public function get(string $url): string
    {
        $host = parse_url($url, PHP_URL_HOST) ?? '';
        return implode('; ', $this->store[$host] ?? []);
    }

    public function set(string $url, string $header): void
    {
        $host = parse_url($url, PHP_URL_HOST) ?? '';
        [$nv] = explode(';', $header, 2);
        [$name, $value] = explode('=', trim($nv), 2) + ['', ''];
        if ($name !== '') {
            $this->store[$host][$name] = "$name=$value";
        }
    }
}

$engine->setCookieJar(new MemoryJar());
```

هذا كافٍ لتركيبة اختبار لمسار ناجح، لكنه يتجاهل `Domain=` و`Path=` و`Expires=` وسمات `Secure`/`HttpOnly`/`SameSite`. لا تستخدمه لأي شيء يتجاوز حدود الثقة.

## Symfony BrowserKit

إذا كانت مكتبات HTTP الخاصة بـSymfony مثبتة لديك بالفعل، فسيتعامل `BrowserKit\CookieJar` مع السياسة على النحو الصحيح.

```php
use Symfony\Component\BrowserKit\CookieJar as BrowserCookieJar;
use Symfony\Component\BrowserKit\Cookie;

final class SymfonyJarAdapter
{
    public function __construct(private BrowserCookieJar $jar) {}

    public function get(string $url): string
    {
        $cookies = $this->jar->allValues($url);
        return implode('; ', array_map(
            fn ($n, $v) => "$n=$v",
            array_keys($cookies),
            array_values($cookies),
        ));
    }

    public function set(string $url, string $header): void
    {
        $cookie = Cookie::fromString($header, $url);
        $this->jar->set($cookie);
    }
}

$engine->setCookieJar(new SymfonyJarAdapter(new BrowserCookieJar()));
```

## مخزن من جهة JS

إذا كان مخزنك موجودًا في جهة JS — مثلًا لأنك تريد فحصه أو تعبئته مسبقًا من JavaScript — فاربطه عبر كائن JS:

```js
const jar = new Map();
$jar.get = (url) => Array.from(jar.entries()).map(([k, v]) => `${k}=${v}`).join('; ');
$jar.set = (url, header) => {
  const [nv] = header.split(';');
  const [name, value] = nv.split('=');
  jar.set(name.trim(), value.trim());
};
```

```php
$engine->eval($script);
$engine->setCookieJar($engine->eval('$jar'));
```

يُستدعى الأسلوبان `get`/`set` نفسيهما سواء كان الكائن المستقبِل PHP أو `JsObject`.

## النطاق لكل طلب

يعيش المخزن ضمن الـ realm — ويستمر عبر كل `fetch()` إلى أن يُفرغ باستخدام `setCookieJar(null)`. لتقييد المخزن بتدفق طلب واحد، افعل ذلك صراحةً:

```php
$engine->setCookieJar($jar);
$engine->eval('await runLoginFlow()');
$engine->setCookieJar(null);
```

## الفحص من PHP

يعيد `$engine->getCookieJar()` القيمة التي مُررت إليه، ما يفيد في التأكيدات ضمن الاختبارات.

```php
$jar = new MemoryJar();
$engine->setCookieJar($jar);
$engine->eval('await fetch("https://api.example.com/login", { method: "POST" })');

assertNotEmpty($engine->getCookieJar()->get('https://api.example.com/'));
```

## راجع أيضًا

- [ناقل Fetch](https://phasis.inline0.dev/ar/docs/interop/fetch-transport) — يعمل مخزن ملفات تعريف الارتباط **داخل** حلقة التحويل في Phasis، ومضافًا إلى أي ناقل ثبّتّه.
- [واجهات الويب (WPT)](https://phasis.inline0.dev/ar/docs/compatibility/web-apis) — اختبارات حزمة Fetch التي تغطي سلوك ملفات تعريف الارتباط.
