Armazenamento de cookies
Por padrão, Phasis fetch() ignora Set-Cookie das respostas e não envia o cabeçalho Cookie nas solicitações. Esse é o padrão adequado para incorporação no lado do servidor — normalmente, você não quer que a resposta de um usuário influencie a solicitação de outro.
Se você precisa de cookies — para executar um fluxo que depende do estado da sessão, fazer scraping após o login ou reproduzir o comportamento do navegador em testes — vincule um armazenamento com $engine->setCookieJar($jar).
A interface
O armazenamento pode ser qualquer objeto que implemente dois métodos:
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
Objetos PHP e JS do lado JsObject com membros correspondentes funcionam. Passar null limpa o armazenamento.
Phasis chama get(url) uma vez por etapa da solicitação (assim, redirecionamentos para outro host recebem cookies atualizados) e set(url, line) uma vez para cada cabeçalho Set-Cookie na resposta. A política de cookies — correspondência de domínio, escopo do caminho, expiração, SameSite, Secure — é responsabilidade do armazenamento, não de Phasis.
Armazenamento em memória (testes)
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());
Isso basta para um fixture de teste de caminho feliz, mas ignora Domain=, Path=, Expires= e os atributos Secure/HttpOnly/SameSite. Não o use em situações que atravessem uma fronteira de confiança.
Symfony BrowserKit
Se você já tem instaladas as bibliotecas HTTP de Symfony, BrowserKit\CookieJar gerencia a política corretamente.
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()));
Armazenamento do lado JS
Se o armazenamento estiver do lado JS — por exemplo, se você quiser inspecioná-lo ou preenchê-lo a partir de JavaScript —, vincule-o por meio de um objeto 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());
};
$engine->eval($script);
$engine->setCookieJar($engine->eval('$jar'));
Os mesmos métodos get/set são chamados tanto quando o receptor é um objeto PHP quanto quando é um JsObject.
Escopo por solicitação
Um armazenamento fica no realm — persiste em cada fetch() até ser limpo com setCookieJar(null). Para limitar o armazenamento a um único fluxo de solicitações, faça isso explicitamente:
$engine->setCookieJar($jar);
$engine->eval('await runLoginFlow()');
$engine->setCookieJar(null);
Inspecionar a partir de PHP
$engine->getCookieJar() retorna o valor que foi passado — útil para verificações em testes.
$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/'));
Veja também
- Transporte fetch — o armazenamento de cookies funciona dentro do loop de redirecionamento de Phasis, sobre o transporte instalado.
- APIs da Web (WPT) — testes do Fetch Pack que cobrem o comportamento dos cookies.