
# Evästepurkki

Oletusarvoisesti kohteen Phasis `fetch()` ohittaa vastauksissa olevat `Set-Cookie`-tiedot eikä lähetä pyyntöjen mukana `Cookie`-otsaketta. Se on palvelinpuolen upotuksen kannalta hyvä oletus: tavallisesti et halua yhden käyttäjän vastauksen vaikuttavan toisen käyttäjän pyyntöön.

Jos tarvitset evästeitä esimerkiksi istunnon tilasta riippuvassa työnkulussa, kirjautumisen takaa tietoja keräävässä työkalussa tai selaimen toimintaa testeissä jäljittelevässä koodissa, liitä evästepurkki funktiolla `$engine->setCookieJar($jar)`.

## Rajapinta

Evästepurkiksi käy mikä tahansa olio, joka toteuttaa kaksi metodia:

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

Sekä PHP-oliot että kohteen JS puolen `JsObject`-oliot toimivat, jos niissä on vastaavat jäsenet. Välittämällä arvon `null` purkki tyhjennetään.

Phasis kutsuu metodia `get(url)` kerran jokaista pyyntöhyppyä kohden (joten uudelleenohjaus toiseen palvelimeen saa käyttöönsä tuoreet evästeet) ja metodia `set(url, line)` kerran kutakin vastauksen `Set-Cookie`-otsaketta kohden. Evästepolitiikka, kuten verkkotunnuksen täsmäytys, polun rajaus, vanheneminen, `SameSite` ja `Secure`, on purkin vastuulla, ei kohteen Phasis.

## Muistissa oleva evästepurkki (testit)

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

Tämä riittää onnistuvan polun testijärjestelyyn, mutta ohittaa kohteet `Domain=`, `Path=`, `Expires=` sekä määritteet `Secure`/`HttpOnly`/`SameSite`. Älä käytä tätä luottamusrajan ylittävään toimintaan.

## Symfony BrowserKit

Jos kohteen Symfony HTTP-kirjastot on jo asennettu, `BrowserKit\CookieJar` hoitaa käytännöt oikein.

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

## Kohteen JS puolen purkki

Jos purkki sijaitsee kohteen JS puolella — esimerkiksi koska haluat tarkastella sitä tai lisätä siihen alkutietoja kohteesta JavaScript — sido se JS-oliona:

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

Samoja metodeja `get`/`set` kutsutaan riippumatta siitä, onko vastaanottaja PHP-olio vai `JsObject`.

## Pyyntökohtainen rajaus

Purkki sijaitsee realmissa ja säilyy jokaisen `fetch()`-kutsun yli, kunnes se tyhjennetään funktiolla `setCookieJar(null)`. Jos haluat rajata purkin yhteen pyyntöketjuun, tee se erikseen:

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

## Tarkastelu kohteesta PHP

`$engine->getCookieJar()` palauttaa sille välitetyn arvon — hyödyllistä testien tarkistuksissa.

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

## Katso myös

- [Fetch-siirtotapa](https://phasis.inline0.dev/fi/docs/interop/fetch-transport) — evästepurkki toimii kohteen Phasis uudelleenohjaussilmukan **sisällä** ja hyödyntää asennettua siirtotapaa.
- [Verkko-API:t (WPT)](https://phasis.inline0.dev/fi/docs/compatibility/web-apis) — Fetch-paketin testit, jotka kattavat evästeiden toiminnan.
