Skip to content

Released version 3.4.0

Latest

Choose a tag to compare

@dg dg released this 13 Jun 01:09
· 9 commits to master since this release

This release brings serious firepower to server-side HTTP handling. The headline is a brand-new SSRF defense kit – IPAddress and UrlValidator let you validate URLs and pin connections before your app ever talks to an attacker-controlled host. On top of that, cookie handling gets a modern overhaul with a type-safe SameSite enum, CHIPS/Partitioned support, and a proper Max-Age attribute, while the new Request::isFrom() gives you reliable same-site request detection – even on Safari. Now on PHP 8.3.

Changes

  • PHP 8.3 is now required. Time to upgrade your runtime if you haven't already.
  • UserStorage is gone – the long-deprecated class has been removed. Use the standard authentication storage instead.
  • Request::getRemoteHost() is deprecated and now returns null – reverse DNS lookups were slow, unreliable, and a privacy footgun. Resolve the hostname yourself from getRemoteAddress() if you really need it (#218).

Deprecations (still working, but plan ahead)

  • The IResponse::SameSite* constants are deprecated in favor of the new SameSite enum.
  • Request::isSameSite() is deprecated – use isFrom() instead.
  • Passing integer 0 as the expiration to Response::setCookie() is deprecated – use null for a session cookie.

✨ New Features

  • SSRF protection, batteries included – the new IPAddress is an immutable IPv4/IPv6 value object with rich predicates (isPublic(), isPrivate(), isLoopback(), isLinkLocal(), isMulticast(), isReserved()), CIDR matching via isInRange(), and IPv4-mapped IPv6 normalization. Pair it with UrlValidator, a configurable guard that vets scheme, port, host allow/blocklists, userinfo, and – optionally with DNS – the resolved IP ranges. It even hands back the resolved IPs so you can pin the connection through CURLOPT_RESOLVE and defeat DNS-rebinding.
  • Request::isFrom() – a single, reliable way to check where a request came from, with site, dest, and user parameters built on the Sec-Fetch-* headers. For browsers without Sec-Fetch support (Safari < 16.4), it transparently falls back to a strict cookie, so same-site detection just works everywhere.
  • Type-safe SameSite enum – setCookie() and Session now accept a proper enum instead of magic strings, so typos become compile-time problems, not silent security holes.
  • Response::setCookie() speaks modern cookie – it now supports the Partitioned attribute (CHIPS) for third-party cookies, emits a Max-Age attribute (which takes precedence over expires and ignores the client clock), and forces Secure automatically when SameSite=None, sparing you a browser rejection.
  • Helpers::expirationToSeconds() – one consistent parser for every expiration value across the library. Numbers are relative seconds, while DateTimeInterface and textual strings like '20 minutes' or '2024-01-01' resolve as absolute times; each caller decides what null means in its own context.
  • Helpers::parseQualityList() – parses HTTP quality-value lists (Accept, Accept-Language, …) into a ranked token map. Request::detectLanguage() was rewritten on top of it and is more correct as a result.