
# Cookie-Speicher

Standardmäßig ignoriert Phasiss `fetch()` `Set-Cookie` aus Antworten und sendet bei Anfragen keinen `Cookie`-Header. Für serverseitiges Einbetten ist das die richtige Standardeinstellung – normalerweise soll die Antwort eines Nutzers die Anfrage eines anderen nicht beeinflussen.

Wenn du Cookies benötigst – etwa für einen Ablauf mit Sitzungsstatus, Scraping hinter einem Login oder Tests, die das Verhalten eines Browsers nachbilden –, binde mit `$engine->setCookieJar($jar)` einen Cookie-Speicher ein.

## Schnittstelle

Der Cookie-Speicher kann jedes Objekt sein, das auf zwei Methoden reagiert:

```
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
```

Sowohl PHP-Objekte als auch JS-seitige `JsObject`s mit passenden Membern funktionieren. Wenn du `null` übergibst, wird der Speicher geleert.

Phasis ruft `get(url)` einmal pro Anfrageweiterleitung auf (damit Weiterleitungen zu einem anderen Host neue Cookies erhalten) und `set(url, line)` einmal für jeden `Set-Cookie`-Header in der Antwort. Die Cookie-Richtlinien – Domain-Abgleich, Pfadbeschränkung, Ablauf, `SameSite`, `Secure` – liegen in der Verantwortung des Cookie-Speichers, nicht von Phasis.

## Speicher im Arbeitsspeicher (Tests)

```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());
```

Das reicht für eine einfache Test-Fixture, berücksichtigt aber weder `Domain=`, `Path=`, `Expires=` noch die Attribute `Secure`/`HttpOnly`/`SameSite`. Verwende sie nicht über Vertrauensgrenzen hinweg.

## Symfony BrowserKit

Wenn die Symfony-HTTP-Bibliotheken bereits installiert sind, verwaltet `BrowserKit\CookieJar` die Richtlinien korrekt.

```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()));
```

## Cookie-Speicher auf JS-Seite

Wenn sich dein Cookie-Speicher auf der JS-Seite befindet – etwa, weil du ihn von JavaScript aus prüfen oder befüllen möchtest –, binde ihn über ein JS-Objekt ein:

```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'));
```

Die Methoden `get`/`set` werden unabhängig davon aufgerufen, ob der Empfänger ein PHP-Objekt oder ein `JsObject` ist.

## Gültigkeitsbereich pro Anfrage

Ein Cookie-Speicher gehört zur Realm und bleibt über alle `fetch()` hinweg bestehen, bis er mit `setCookieJar(null)` geleert wird. Soll er nur für einen einzelnen Anfrageablauf gelten, richte das ausdrücklich ein:

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

## Von PHP aus prüfen

`$engine->getCookieJar()` gibt den übergebenen Wert zurück – praktisch für Assertions in Tests.

```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/'));
```

## Siehe auch

- [Fetch-Transport](https://phasis.inline0.dev/de/docs/interop/fetch-transport) – der Cookie-Speicher läuft **innerhalb** der Weiterleitungsschleife von Phasis und wird über den installierten Transport gelegt.
- [Web-APIs (WPT)](https://phasis.inline0.dev/de/docs/compatibility/web-apis) – die Fetch-Pack-Tests zum Cookie-Verhalten.
