PackageTrack
Sign in Get early access

azjezz/psl

Abandoned; use php-standard-library/php-standard-library. PHP Standard Library

6.2.1 13M downloads/mo #1049 most downloaded on Packagist php-standard-library/php-standard-library

What this package is like to depend on

Last release 3 months ago

23 May 2026

Release timing varies

gaps range from 8 days to 7 months

Some releases are documented

notes for 31 of 72 stable releases

Nothing withdrawn

no release was ever pulled

6 years old

74 releases · first in 2020

21 releases in the last 12 months

see the full history below

Release timeline

74 releases · Dec 2020 to May 2026
2021 2022 2023 2024 2025 2026
Release Pre-release

Releases

latest 60 of 74
  1. 6.2.1 23 May 2026
    Release notes

    Security Release

    This release fixes a server-side HTTP/2 vulnerability in the Psl\H2 component (GHSA-pw9p-jvrm-f7rm).

    Impact

    Psl\H2\ServerConnection did not validate that the total bytes received in HTTP/2 DATA frames matched the content-length header declared in the initial HEADERS frame, in violation of RFC 9113 §8.1.1 and §8.1.2.6. #777

    A malicious client could:

    • Send more DATA bytes than declared, smuggling additional content past application-level size limits.
    • Send fewer DATA bytes than declared and close the stream early, causing applications that trust the declared length to behave incorrectly.

    This affects consumers using Psl\H2\ServerConnection directly to accept untrusted client traffic. Consumers of documented high-level PSL APIs are not affected.

    Patches

    • Parses and validates content-length on server-side HEADERS receive (RFC 9110 §8.6: must be a non-negative decimal integer).
    • Tracks cumulative DATA frame payload length per stream.
    • Throws Psl\H2\Exception\StreamException on mismatch or overflow.

    Client-side validation is intentionally not performed, as RFC 9110 §9.3.2 permits HEAD responses to declare content-length without sending DATA.

    Additional fixes

    • Psl\H2\ConnectionTrait::waitForSendWindow() now flushes pending buffered writes before suspending. Without this, frames written inside a buffered() block never reach the wire, and a peer that only sends WINDOW_UPDATE after seeing our DATA would deadlock.

    Upgrade

    composer require php-standard-library/psl:^6.2.1
    

    Credit

    Discovered during internal review prior to public exploitation.

    Open source →
    Release notes

    security

    • fix(h2): validate content-length header against received DATA on server connections, preventing HTTP/2 request smuggling on Psl\H2\ServerConnection (GHSA-pw9p-jvrm-f7rm)
    Open source →
  2. 6.2.0 23 May 2026
    Release notes

    PSL 6.2.0

    A massive release — three new networking stack components (HTTP, SMTP, DNS), the EitherOrBoth type with full-outer-join iterators, a major IO toolkit expansion, and broad covariance improvements across the type system.

    New Components

    HTTP Stack

    • HTTP\Message — version-agnostic HTTP message abstractions. Request/Response value objects with streaming bodies (ReadHandleInterface), FieldMap (ordered, case-insensitive headers with lazy index), ProtocolVersion covering HTTP/1.0 through HTTP/3, trailers as Async\Awaitable<FieldMap>, status/method constants per RFC 9110, and Transaction/Exchange for informational (1xx) responses and HTTP/2 server-push pairs.
    • HTTP\Client — async HTTP/1.1 and HTTP/2 client with automatic protocol negotiation via ALPN. Connection pooling (H1 idle reuse, H2 session sharing across concurrent requests), event-driven stream dispatch, transparent reconnection on GOAWAY/TCP reset, RedirectClient and RetryClient decorators, per-request SendConfiguration, SSRF protection via DeniedDestinationsMiddleware, SOCKS5 proxy and HTTP CONNECT tunnel support, H2 flow control with BDP auto-tuning, and 104 integration tests against httpbun.

    Mail Stack

    • MIME — comprehensive RFC 2045–2049 toolkit. Media type parsing and content negotiation, MIME part construction with automatic transfer encoding, streaming multipart bodies and parsing (alternative, related, form, generic), Content-Disposition with safe filename extraction, RFC 2231 parameter encoding with continuations and charset conversion, content sniffing from bytes or seekable handles, S/MIME signing/verification/encryption/decryption per RFC 5652/8551, and DKIM signing with RSA-SHA256 and Ed25519-SHA256 per RFC 6376/8463.
    • Message — RFC 5322 internet message construction, parsing, and serialization. Typed header fields with fluent with*() mutation, address methods accepting string|Mailbox|AddressList, streaming serialize()/parse(), reply/reply-all/forward with automatic threading headers, RFC 5321 SMTP envelope derivation, and full RFC 5322 address parsing including RFC 2047 encoded-word support.
    • SMTP — RFC 5321 SMTP client with connection pooling. Low-level Connection for protocol-level operations and high-level Transport managing the full lifecycle (EHLO/HELO, STARTTLS, AUTH, send, RSET). Implicit TLS on port 465 and STARTTLS upgrade with automatic detection, SMTP pipelining (RFC 2920), BDAT chunking (RFC 3030), DSN (RFC 3461), REQUIRETLS (RFC 8689), MT-PRIORITY (RFC 6710), DELIVERBY (RFC 2852), FUTURERELEASE (RFC 4865), BINARYMIME/8BITMIME/SMTPUTF8 negotiation, IDN punycode for international addresses, partial recipient success tracking, CRLF/null byte injection protection, and five authentication mechanisms: PLAIN, LOGIN, XOAUTH2, CRAM-MD5, SCRAM-SHA-256.

    DNS Stack

    • DNS — async DNS resolution with full protocol support. SystemResolver mirrors OS DNS behavior; UDP and pooled TCP resolvers with automatic TCP fallback on truncation; DNS-over-TLS (DoT) and DNS-over-HTTPS (DoH, RFC 8484). RacingResolver races multiple nameservers concurrently, SplitHorizonResolver routes by domain, SearchDomainResolver expands short names, HostsFileResolver checks the OS hosts file, CachedResolver decorator with TTL-aware caching, and StaticResolver for tests. Cross-platform system configuration loading on Linux, macOS, and Windows. EDNS0 extensions (cookies, client subnet, padding, NSID, keepalive). 20+ record types covering A, AAAA, NS, CNAME, MX, TXT, SRV, SOA, PTR, CAA, SSHFP, TLSA, SVCB, HTTPS, LOC, NAPTR, DS, DNSKEY, RRSIG, NSEC, NSEC3.
    • DNSSEC — full DNSSEC validation chain. SecureResolver validates RRSIG signatures, TrustChainResolver walks DS/DNSKEY from root to target zone, CachedTrustChainResolver for performance, StaticTrustChainResolver for offline use. NSEC and NSEC3 authenticated denial of existence proofs. Seven signature algorithms: RSA/SHA-1, RSA/SHA-256, RSA/SHA-512, ECDSA P-256, ECDSA P-384, Ed25519, Ed448. Specific exceptions for signature failures, broken trust chains, invalid proofs, and unsigned responses.

    EitherOrBoth + Full-Outer-Join Iterators

    • EitherOrBoth — three-variant disjoint union (Left/Right/Both) for values that may be present on either or both of two sides. Inspired by Rust's itertools::EitherOrBoth and Haskell's Data.These. Unlike Either, no side is privileged. Use cases: three-way diffs (insert/delete/update events), layered config merging, multi-source enrichment, dual-validation with independent failure paths, snapshot comparison, request/response pairing. Full surface: map, mapLeft, mapRight, mapAny, swap, proceed, apply, containsLeft, containsRight, plus left()/right()/both() free constructors.
    • Iter\merge_join_by / Iter\merge_join_by_key — full-outer-join stream producers yielding EitherOrBoth events. merge_join_by is a lazy two-cursor merge over sorted inputs (O(1) memory, Comparison\Order-returning comparator). merge_join_by_key is a hash-based variant for keyed inputs that need no pre-sorting (O(|right|) memory).

    IO Toolkit Expansion

    Eight new handle types for streaming composition:

    • IterableReadHandle — lazily consume an iterable<string> without buffering.
    • ConcatReadHandle — read from two handles in sequence, switching at EOF.
    • JoinedReadWriteHandle — combine separate read and write handles into one.
    • TeeWriteHandle — fan out writes to two handles with backpressure buffering.
    • SinkWriteHandle / SinkReadHandle / SinkReadWriteHandle/dev/null-like handles for discarding writes and reporting EOF immediately on reads.
    • TruncatedReadHandle — silently report EOF after N bytes.
    • BoundedReadHandle — throw RuntimeException if the underlying handle exceeds N bytes.
    • FixedLengthReadHandle — read exactly N bytes, throw on premature EOF.

    Plus IO\copy_chunked() and IO\copy_bidirectional_chunked() for explicit chunk-size control.

    Type System: Covariance

    Read-only template parameters across the library are now annotated @template-covariant, letting values flow into wider declarations:

    • Async\Awaitable<T>, Promise\PromiseInterface<T>
    • Result\ResultInterface<T>, Result\Success<T>, Result\Failure<T, Te>
    • Option\Option<T>
    • Either\Either<TLeft, TRight>, Either\Left<TLeft>, Either\Right<TRight>
    • Tree\NodeInterface<T>, Tree\LeafNode<T>, Tree\TreeNode<T>
    • Immutable Collection interfaces and implementations (Map, Set, Vector)

    Async\Sequence, KeyedSequence, Semaphore, and KeyedSemaphore now correctly distinguish contravariant inputs from covariant outputs.

    HTTP/2 (H2)

    • New unified Configuration replacing the deprecated ClientConfiguration and ServerConfiguration. Both ClientConnection and ServerConnection accept it. Client-side BDP auto-tuning is now available when maxReceiveWindowSize is set on the unified config.

    TCP & Type Additions

    • TCP\bindTo — bind to a specific local address before connecting or listening. Available on both ConnectConfiguration and ListenConfiguration with withBindTo() builders; connect() respects it via socket.bindto.
    • Type\bool() — now coerces 'true'/'false' string literals (thanks @veewee, #735).
    • Type\class_string — allow null argument to assert or coerce a bare class-string.
    • HTTP\Client\SendConfiguration::$connectionTimeout — per-request maximum duration for TCP + TLS handshake, using a linked cancellation token.

    Fixes

    • IO\copy() flushes the writer if it implements BufferedWriteHandleInterface — no data left in buffers.
    • Async\State no longer captures $this in queued callbacks, fixing delayed GC of Deferred/Awaitable chains.
    • URI correctly parses bare IPv6 addresses (e.g., http://::1/path) as IPHost instead of misparsing as a registered name with numeric port.
    • H2 separates maxConcurrent (peer's limit on our streams) from peerMaxConcurrent (our limit on peer's streams), so client's own SETTINGS no longer limit its outgoing streams.
    • H2\BDPEstimator emits an initial connection-level WINDOW_UPDATE during initialize(), bringing the receive window from the RFC default (65535) up to initialWindowSize to prevent flow-control stalls under burst concurrency.
    • H2 waiter notification copies the list before iterating and properly removes satisfied waiters — no iteration corruption or memory leaks.
    • IO\ResourceHandle read/write callbacks and cancellation subscriptions null out the suspension reference before resuming or throwing — no more "Must call suspend() before calling throw()" errors during handle destruction or shutdown races.
    • RFC 2047 encoded-word encoder no longer embeds CRLF line folding in the output; folding is now the header serializer's responsibility, fixing header/body separation in serialized messages.

    Deprecations

    Will be removed in PSL 7.0:

    • TCP\Socket — use ConnectConfiguration::$bindTo / ListenConfiguration::$bindTo.
    • H2\ClientConfiguration and H2\ServerConfiguration — use the unified H2\Configuration.

    CI

    • Added httpbun, microsocks, and tinyproxy services to unit-tests, code-coverage, mutation-tests, and package-tests workflows for HTTP client integration testing.

    Install: composer require php-standard-library/psl:^6.2

    Open source →
    Release notes

    features

    • feat(either-or-both): introduce EitherOrBoth component - a three-variant disjoint union (Left / Right / Both) for values that may be present on either or both of two sides, inspired by Rust's itertools::EitherOrBoth and Haskell's Data.These. Primary use case: three-way diff of two collections (insert / delete / update events). Secondary: layered config merge, multi-source enrichment, dual-validation, snapshot comparison. Full map / mapLeft / mapRight / mapAny / swap / proceed / apply / containsLeft / containsRight surface; left() / right() / both() free constructors.
    • feat(iter): add Iter\merge_join_by and Iter\merge_join_by_key - full-outer-join stream producers that yield EitherOrBoth events as a rewindable Iter\Iterator. merge_join_by is a lazy two-cursor merge over sorted inputs (O(1) memory on first traversal, Psl\Comparison\Order-returning comparator, matching Rust's itertools::merge_join_by); merge_join_by_key is a hash-based variant for keyed inputs that do not need to be pre-sorted (O(|right|) memory).
    • feat(io): add IO\IterableReadHandle - a streaming ReadHandleInterface that lazily consumes an iterable<string> without buffering the entire content in memory
    • feat(io): add IO\ConcatReadHandle - reads from two handles in sequence, switching to the second when the first reaches EOF
    • feat(io): add IO\JoinedReadWriteHandle - joins a ReadHandleInterface and WriteHandleInterface into a single read-write handle, delegating all operations to the respective underlying handle
    • feat(io): add IO\TeeWriteHandle - writes to two handles simultaneously with backpressure buffering when the second handle is slower
    • feat(io): add IO\SinkWriteHandle - a /dev/null-like write handle that discards all written data
    • feat(io): add IO\SinkReadHandle - a read handle that is always at EOF, unlike MemoryHandle('') which only reports EOF after the first read
    • feat(io): add IO\SinkReadWriteHandle - a sink that discards writes and always reports EOF on reads
    • feat(io): add IO\TruncatedReadHandle - reads up to N bytes from an underlying handle, silently reporting EOF when the limit is reached
    • feat(io): add IO\BoundedReadHandle - reads up to N bytes from an underlying handle, throwing RuntimeException if the underlying handle has more data than the limit allows
    • feat(io): add IO\FixedLengthReadHandle - reads exactly N bytes from an underlying handle, throwing RuntimeException on premature EOF
    • feat(io): add IO\copy_chunked() and IO\copy_bidirectional_chunked() - variants of IO\copy() and IO\copy_bidirectional() that accept a custom chunk size
    • feat(http-client): add SendConfiguration::$connectionTimeout - per-request maximum duration for establishing a connection (TCP + TLS handshake), using a linked cancellation token
    • feat(type): support 'true'/'false' string literals in Type\bool() coercion - #735 by @verweto
    • feat(mime): introduce MIME component - comprehensive MIME toolkit implementing RFC 2045-2049 and related standards
      • Media type parsing, validation, and content negotiation (MediaType, MediaRange, MediaPreferences) per RFC 2045, RFC 6838, RFC 9110
      • MIME part construction with automatic transfer encoding (Part\Text, Part\Data) per RFC 2045
      • Streaming multipart body construction and parsing (MultiPart\Composite, MultiPart\Alternative, MultiPart\Related, MultiPart\Form, MultiPart\Parser) per RFC 2046, RFC 2387, RFC 7578
      • Immutable header collection with RFC 5322 line folding (Headers)
      • Content-Disposition parsing with safe filename extraction (ContentDisposition) per RFC 2183
      • Content-ID parsing, generation, and cid: URI support (ContentId) per RFC 2392
      • RFC 2231 parameter encoding/decoding with continuations and charset conversion (Parameters)
      • Content sniffing from bytes and seekable handles (Sniff\from_string, Sniff\from_handle)
      • S/MIME signing, verification, encryption, and decryption (SMIME\Signer, SMIME\Verifier, SMIME\Encryptor, SMIME\Decryptor) per RFC 5652, RFC 8551
      • DKIM message signing with RSA-SHA256 and Ed25519-SHA256 (DKIM\Signer) per RFC 6376, RFC 8301, RFC 8463
    • feat(message): introduce Message component - RFC 5322 internet message construction, parsing, and serialization
      • Typed header fields with fluent with*() methods (Message) per RFC 5322
      • Address methods accept string|Mailbox|AddressList for convenience
      • Message body as PartInterface from the MIME component per RFC 2045
      • Streaming serialize() and parse() accepting string or ReadHandleInterface
      • Reply, reply-all, and forward with automatic threading headers (In-Reply-To, References) per RFC 5322
      • SMTP envelope derivation (Envelope) per RFC 5321
      • RFC 5322 address parsing: Mailbox, Group, AddressList with RFC 2047 encoded-word support
    • feat(smtp): introduce SMTP component - RFC 5321 SMTP client with connection pooling, TLS, and authentication
      • Low-level Connection implementing Network\StreamInterface for protocol-level SMTP operations
      • High-level Transport managing the full SMTP lifecycle: connect, EHLO/HELO, STARTTLS, AUTH, send, RSET
      • Connection pooling with automatic reuse across multiple sends via TCP\SocketPool
      • Implicit TLS (port 465) and STARTTLS upgrade (RFC 3207) with automatic detection
      • EHLO with HELO fallback per RFC 5321
      • SMTP pipelining (RFC 2920) for reduced round-trips
      • BDAT chunking (RFC 3030) to avoid dot-stuffing overhead on large messages
      • Enhanced status codes (RFC 3463) with structured EnhancedStatusCode parsing
      • DSN delivery status notifications (RFC 3461) via SendConfiguration
      • REQUIRETLS (RFC 8689) for end-to-end TLS enforcement
      • MT-PRIORITY (RFC 6710) message priority with STANAG 4406 levels
      • DELIVERBY (RFC 2852) delivery deadline specification
      • FUTURERELEASE (RFC 4865) deferred delivery via Duration or DateTimeInterface
      • BINARYMIME (RFC 3030), 8BITMIME (RFC 6152), SMTPUTF8 (RFC 6531) capability negotiation
      • Punycode IDN encoding for internationalized domain names in addresses
      • Partial recipient success with DeliveryReport for per-recipient rejection tracking
      • CRLF and null byte injection protection via PossibleAttackException
      • Five authentication mechanisms: PLAIN (RFC 4616), LOGIN, XOAUTH2, CRAM-MD5 (RFC 2195), SCRAM-SHA-256 (RFC 7677)
      • Immutable TransportConfiguration and SendConfiguration with fluent with*() builders
      • Configurable pipelining, chunking, chunk size, and partial success behavior
    • feat(dns): introduce DNS component - async DNS resolution with full protocol support
      • SystemResolver mirrors OS DNS behavior, usable as a default parameter value
      • UDP and pooled TCP resolvers with automatic TCP fallback on truncation
      • DNS-over-TLS (DoT) via TLS client configuration on TCPResolver
      • RacingResolver races multiple nameservers concurrently for fastest response
      • SplitHorizonResolver routes queries by domain name for split-horizon DNS
      • SearchDomainResolver expands short names using search domain lists
      • HostsFileResolver checks the OS hosts file before network queries
      • CachedResolver decorator with TTL-aware caching via Cache\StoreInterface
      • StaticResolver for hardcoded records in tests and development
      • Cross-platform system configuration loading (Linux, macOS, Windows) via async process execution
      • EDNS0 support: DNS cookies, client subnet, padding, NSID, TCP keepalive, key tag, extended DNS error
      • 20+ record types: A, AAAA, NS, CNAME, MX, TXT, SRV, SOA, PTR, CAA, SSHFP, TLSA, SVCB, HTTPS, LOC, NAPTR, DS, DNSKEY, RRSIG, NSEC, NSEC3
      • DNS-over-HTTPS (DoH) via HTTPSResolver using the HTTP client (RFC 8484)
      • DNS name validation with null byte and label length enforcement
      • ResponseCode helper methods: isSuccess(), isError(), isServerError(), isNameError()
    • feat(dnssec): introduce DNSSEC component - full DNSSEC validation chain
      • SecureResolver validates RRSIG signatures on every response
      • TrustChainResolver walks DS/DNSKEY chain from root to target zone
      • CachedTrustChainResolver caches trust chain results for performance
      • StaticTrustChainResolver for offline/air-gapped environments
      • NSEC and NSEC3 authenticated denial of existence proof validation
      • 7 signature algorithms: RSA/SHA-1, RSA/SHA-256, RSA/SHA-512, ECDSA P-256, ECDSA P-384, Ed25519, Ed448
      • 4 specific validation exceptions: SignatureFailedException, BrokenTrustChainException, InvalidProofException, UnsignedResponseException
    • feat(http-message): introduce HTTP Message component - version-agnostic HTTP message abstractions
      • Request and Response immutable value objects with streaming body (ReadHandleInterface)
      • FieldMap ordered, case-insensitive header field collection with lazy index
      • ProtocolVersion enum covering HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3
      • Trailers modelled as Async\Awaitable<FieldMap> for HTTP/2 and chunked HTTP/1.1
      • HTTP status code and method constants per RFC 9110
      • reason_phrase() function for HTTP/1.x status line serialization
      • Fluent with*() mutation methods on both Request and Response
      • Transaction groups the final response with informational (1xx) responses and server push exchanges
      • Exchange represents a pushed request/response pair for HTTP/2 server push
    • feat(http-client): introduce HTTP Client component - async HTTP/1.1 and HTTP/2 client with connection pooling
      • Client with automatic protocol negotiation via ALPN (HTTP/2 preferred, HTTP/1.1 fallback)
      • PooledConnector with HTTP/1.x idle connection reuse and HTTP/2 session sharing across concurrent requests
      • HTTP/2 multiplexing with event-driven stream dispatch via H2Multiplexer and per-stream H2Stream state
      • Transparent reconnection on connection failure (GOAWAY, TCP reset) via pool-backed reconnect closures
      • RedirectClient decorator following 301/302/303/307/308 redirects with method rewriting per RFC 9110, cross-origin credential stripping, and auto-referrer
      • RetryClient decorator with configurable exponential backoff and jitter for transport-level failures
      • SendConfiguration for per-request overrides (body size limits, TLS, protocol versions, tunnel) merged with ClientConfiguration defaults
      • DeniedDestinationsMiddleware for SSRF protection against private IP ranges (RFC 1918, RFC 4193, loopback, link-local)
      • Connection-level middleware via HandlerInterface / MiddlewareInterface chain with access to peer address and TLS state
      • SOCKS5 proxy support via ClientConfiguration::$proxy using Psl\Socks\Connector
      • HTTP CONNECT tunnel support via ClientConfiguration::$tunnel with TLS and proxy authentication
      • noTunneling host bypass rules (exact match, domain suffix, wildcard)
      • H2 flow control with BDP auto-tuning for dynamic receive window sizing
      • Lazy, pull-based response body reading via ResponseBodyHandle implementing ReadHandleInterface
      • 104 integration tests against httpbun covering methods, redirects, auth, caching, cookies, concurrency, and streaming
    • feat(h2): introduce unified Configuration replacing deprecated ClientConfiguration and ServerConfiguration
      • Both ClientConnection and ServerConnection now accept Configuration in addition to their legacy config types
      • ClientConnection now supports BDP auto-tuning when using Configuration with maxReceiveWindowSize set
    • feat(tcp): add bindTo option to ConnectConfiguration for binding to a specific local address before connecting
    • feat(tcp): add bindTo option to ListenConfiguration for binding to a specific local address before listening
    • feat(tcp): add withBindTo() fluent builder method to both ConnectConfiguration and ListenConfiguration
    • feat(tcp): connect() now respects ConnectConfiguration::$bindTo by setting the socket.bindto stream context option
    • feat(type): Allow null argument to Type\class_string to assert or coerce bare class-string

    type system

    • chore(types): annotate read-only template parameters with @template-covariant across the library, allowing values to flow into wider declarations:
      • Async\Awaitable<T>, Promise\PromiseInterface<T>
      • Result\ResultInterface<T>, Result\Success<T>, Result\Failure<T, Te>
      • Option\Option<T>
      • Either\Either<TLeft, TRight>, Either\Left<TLeft>, Either\Right<TRight>
      • Tree\NodeInterface<T>, Tree\LeafNode<T>, Tree\TreeNode<T>
    • chore(collection): annotate immutable collection template parameters with @template-covariant (CollectionInterface, AccessibleCollectionInterface, IndexAccessInterface, MapInterface, Map, SetInterface, Set, VectorInterface, Vector); mutable collections remain invariant.
    • chore(async): annotate Sequence, KeyedSequence, Semaphore, KeyedSemaphore template parameters with the correct variance; keys/inputs are @template-contravariant (write-position only) and outputs are @template-covariant (read-position only).
    • chore(collection): relax Vector::getIterator() and MutableVector::getIterator() return type from Iterator<int<0, max>, T> to Iterator<int, T>.

    fixes

    • fix(io): IO\copy() now flushes the writer after copying if it implements BufferedWriteHandleInterface, ensuring no data remains in an internal buffer
    • fix(async): State::subscribe() and State::invokeCallbacks() no longer capture $this in queued closures, preventing delayed garbage collection of Deferred/Awaitable chains
    • fix(uri): bare IPv6 addresses (e.g., http://::1/path) are now correctly parsed as IPHost instead of being misparsed as a registered name with a numeric port
    • fix(h2): separate maxConcurrent (peer's limit on our streams) from peerMaxConcurrent (our limit on peer's streams) in StreamTable, preventing the client's own SETTINGS from limiting its outgoing streams
    • fix(h2): BDPEstimator now produces an initial connection-level WINDOW_UPDATE during initialize() to bring the receive window from the RFC default (65535) up to initialWindowSize, preventing flow-control stalls when many concurrent streams receive data simultaneously
    • fix(h2): notifyWindowWaiters() now copies the waiter list before iterating and properly removes satisfied waiters, preventing iteration corruption and memory leaks
    • fix(io): ResourceHandle readable/writable callbacks now null out the suspension reference before calling resume(), preventing "Must call suspend() before calling throw()" errors during handle destruction
    • fix(io): ResourceHandle::doRead() and doWrite() cancellation subscriptions now null out the suspension reference before throwing, preventing double-wake when cancellation and close race during PHP shutdown
    • fix(encoding): RFC 2047 encoded-word encoder no longer embeds CRLF line folding in the encoded output; line folding is now the responsibility of the header serializer, fixing header/body separation issues in serialized messages

    deprecations

    • deprecated(tcp): Socket class -- use ConnectConfiguration::$bindTo or ListenConfiguration::$bindTo instead. Will be removed in PSL 7.0.
    • deprecated(h2): ClientConfiguration -- use Configuration instead. Will be removed in PSL 7.0.
    • deprecated(h2): ServerConfiguration -- use Configuration instead. Will be removed in PSL 7.0.

    ci

    • ci: add httpbun, microsocks, and tinyproxy services to unit-tests, code-coverage, mutation-tests, and package-tests workflows for HTTP client integration testing
    Open source →
  3. 6.1.2 23 May 2026
    Release notes

    Security Release

    This release fixes a server-side HTTP/2 vulnerability in the Psl\H2 component (GHSA-pw9p-jvrm-f7rm).

    Impact

    Psl\H2\ServerConnection did not validate that the total bytes received in HTTP/2 DATA frames matched the content-length header declared in the initial HEADERS frame, in violation of RFC 9113 §8.1.1 and §8.1.2.6. #778

    A malicious client could:

    • Send more DATA bytes than declared, smuggling additional content past application-level size limits.
    • Send fewer DATA bytes than declared and close the stream early, causing applications that trust the declared length to behave incorrectly.

    This affects consumers using Psl\H2\ServerConnection directly to accept untrusted client traffic. Consumers of documented high-level PSL APIs are not affected.

    Patches

    • Parses and validates content-length on server-side HEADERS receive (RFC 9110 §8.6: must be a non-negative decimal integer).
    • Tracks cumulative DATA frame payload length per stream.
    • Throws Psl\H2\Exception\StreamException on mismatch or overflow.

    Client-side validation is intentionally not performed, as RFC 9110 §9.3.2 permits HEAD responses to declare content-length without sending DATA.

    Additional fixes

    • Psl\H2\ConnectionTrait::waitForSendWindow() now flushes pending buffered writes before suspending. Without this, frames written inside a buffered() block never reach the wire, and a peer that only sends WINDOW_UPDATE after seeing our DATA would deadlock.

    Upgrade

    composer require php-standard-library/psl:^6.1.2
    

    Credit

    Discovered during internal review prior to public exploitation.

    Open source →
  4. 6.1.1 20 Mar 2026
    Release notes

    PSL 6.1.1

    Str\chr() and Str\from_code_points() now reject invalid Unicode code points

    Str\chr() previously returned an empty string for invalid code points (negative values, surrogates, values above U+10FFFF) because mb_chr() returns false and it was silently cast to string. It now throws Str\Exception\OutOfBoundsException.

    Str\from_code_points() had a hand-rolled UTF-8 encoder that silently produced invalid byte sequences; encoding surrogates, wrapping out-of-range values via modulo, and accepting negative inputs. The implementation has been replaced with a simple loop over Str\chr(), making both functions fully consistent. Invalid code points now throw Str\Exception\OutOfBoundsException.

    use Psl\Str;
    
    // These all threw no error before, now they throw OutOfBoundsException:
    Str\chr(-1);
    Str\chr(0xD800);        // surrogate
    Str\chr(0x110000);      // above Unicode max
    
    Str\from_code_points(72, 0xD800, 111);  // throws on the surrogate

    Valid inputs are unaffected — chr() and from_code_points() produce identical output for all valid Unicode code points (U+0000..U+D7FF, U+E000..U+10FFFF).

    Explicit function resolution across the codebase

    All ambiguous function calls have been made explicit. Every call site now uses either a use function import for global PHP functions or namespace\foo() for same-namespace functions.

    Documentation

    • Str\width(), Str\truncate(), and Str\width_slice() PHPDoc now explicitly states that width is defined by mb_strwidth() / mb_strimwidth(), and cross-references related functions like Str\length(), Str\Grapheme\length(), and Str\Grapheme\slice().

    Testing

    • The H2 rate limiter window-reset test is now skipped on Windows, where usleep() resolution is too coarse for sub-millisecond timing assertions.
    Open source →
    Release notes

    fixes

    • fix(str): Str\chr() now throws OutOfBoundsException for invalid Unicode code points instead of silently returning an empty string
    • fix(str): Str\from_code_points() now validates code points and throws OutOfBoundsException for out-of-range values, surrogates, and negative inputs instead of producing invalid UTF-8; implementation now delegates to Str\chr() for consistent behavior

    other

    • chore(str): clarify width(), truncate(), and width_slice() PHPDoc to explicitly reference mb_strwidth()/mb_strimwidth() semantics
    • chore: make all function calls explicit across the codebase, eliminating PHP namespace fallback resolution
    • chore(h2): skip timer-sensitive rate limiter test on Windows
    Open source →
  5. 6.1.0 19 Mar 2026
    Release notes

    PSL 6.1.0

    In PSL 5.x, we focused on the foundational networking stack-TCP, TLS, Unix sockets, UDP, and connection pooling. It was all about getting the low-level plumbing right.

    With the 6.x series, we're moving up the stack and diving into protocols. Our ultimate goal is to bring robust support for HTTP/2, DNS, SMTP, WebSockets, and more. PSL 6.1.0 is the crucial first step: it delivers the core infrastructure that all of these upcoming features will rely on.

    What's Coming Next?

    Everything in 6.1 was built with a clear destination in mind. We are paving the way for:

    • 🌐 HTTP Client - Powered by our new H2 and TLS implementations, featuring automatic protocol negotiation, HTTP/1.1 fallback, and connection pooling.
    • 🖥️ HTTP Server – A fully asynchronous HTTP/1.1 and HTTP/2 server with middleware support.
    • 🔍 DNS – A complete async resolver supporting DNSSEC, DNS-over-TLS, caching, and racing resolvers.
    • 📧 SMTP – Fully asynchronous email delivery.
    • 🔌 WebSockets – Supported both standalone over HTTP/1.1 and via H2's extended CONNECT.

    The components introduced today are the engine for this roadmap. The new H2 connections will drive the HTTP client and server, the new async Cache will back the DNS resolver, and the new Compression system will handle content-encoding seamlessly.


    What's New in 6.1.0

    🗜️ Streaming Compression

    We've added streaming compression and decompression natively to IO handles. By defining your own CompressorInterface or DecompressorInterface (brotli, gzip, zstd, etc.), PSL gives you four handle decorators to wire them directly into the IO system:

    • CompressingReadHandle & CompressingWriteHandle
    • DecompressingReadHandle & DecompressingWriteHandle

    We've also included compress() and decompress() convenience functions for simple, one-shot operations. Under the hood, write handles implement the new BufferedWriteHandleInterface for explicit flushing and cancellation, while read handles accept configurable chunk sizes. Compressors automatically reset after calling finish(), making them easily reusable across streams.

    📦 HPACK (HTTP/2 Header Compression)

    This release includes a complete RFC 7541 encoder and decoder, featuring static table lookups, dynamic table indexing, and Huffman coding.

    We wanted to be absolutely certain of its reliability, so we tested it against 14 independent implementations from the http2jp test suite. That translates to 1,172 tests and over 102,000 assertions, covering every encoding variant and edge case with full roundtrip verification.

    H2 (HTTP/2 Binary Framing)

    We’ve shipped full support for the HTTP/2 binary framing protocol (RFC 9113), plus key extensions.

    To keep responsibilities clean, connections are split by role. ServerConnection handles client prefaces, response headers, server pushes, Alt-Svc, and ORIGIN. Meanwhile, ClientConnection manages connection prefaces, priority signaling, and extended CONNECT.

    Comprehensive Frame Support:

    • All 10 core frame types.
    • ALTSVC (RFC 7838) for HTTP/3 migration signaling.
    • ORIGIN (RFC 8336) for connection coalescing.
    • PRIORITY_UPDATE (RFC 9218) for extensible prioritization.

    Smart, Async-Native Flow Control:
    We've designed flow control to get out of your way. sendAllData() automatically chunks payloads by window size and waits for updates. waitForSendWindow() suspends the fiber entirely (zero polling!) and resumes exactly when the window opens. Multiple fibers can wait on different streams with independent cancellation, and connection-level updates efficiently wake all relevant waiters.

    Additional H2 Features:

    • BDP auto-tuning for dynamic receive window sizing.
    • Built-in rate limiting to prevent SETTINGS, PING, or RST_STREAM floods.
    • Auto-GOAWAY on protocol errors, eliminating manual error handling.
    • Deep stream introspection (getStreamState(), activeStreamCount(), isConnected()).
    • Extended CONNECT (RFC 8441) to bootstrap WebSockets over H2.
    • Immutable ServerConfiguration and ClientConfiguration using fluent with* builders.

    🧠 Async-Safe Memory Cache

    We're introducing an async-safe, in-memory LRU cache. The standout feature here is per-key atomicity powered by KeyedSequence.

    If two fibers request the same cache key simultaneously, only one will compute the result. The other simply waits and receives the cached value—preventing cache stampedes and eliminating duplicate work.

    • LocalStore: A bounded LRU cache with a configurable max size and TTL support. It uses an event loop timer for proactive expiration, dropping to zero overhead when there are no expiring entries.
    • NullStore: A dummy cache that never stores and always recomputes. It's perfect for testing or temporarily disabling caching without having to modify your calling code.

    🔌 IO Enhancements

    We've introduced BufferedWriteHandleInterface, which extends the standard WriteHandleInterface with a flush() method. This is essential for handles that buffer data internally (like the new compression writers) and need an explicit "send everything now" trigger with full cancellation support.

    Open source →
    Release notes

    features

    • feat(io): introduce Psl\IO\BufferedWriteHandleInterface, extending WriteHandleInterface with flush() for handles that buffer data internally before writing to an underlying resource
    • feat: introduce Compression component with streaming compression/decompression abstractions for IO handles. Provides CompressorInterface, DecompressorInterface, four handle decorators (CompressingReadHandle, CompressingWriteHandle, DecompressingReadHandle, DecompressingWriteHandle), and convenience functions compress() and decompress()
    • feat: introduce HPACK component - RFC 7541 HPACK header compression for HTTP/2
    • feat: introduce H2 component - HTTP/2 binary framing protocol implementation
    • feat: introduce Cache component - async-safe in-memory LRU cache with per-key atomicity via KeyedSequence, proactive TTL expiration via event loop
    Open source →
  6. 6.0.3 18 Mar 2026
    Release notes

    PSL 6.0.3

    No code changes. This release improves the release infrastructure.

    What changed

    • Annotated tags: Split repository tags are now created as annotated tags via the GitHub API, removing the "unverified" warning shown on 6.0.0-6.0.2 tags.
    • Immutable tags: All 62 repositories now have tag immutability rulesets. Tags cannot be deleted, updated, or force-pushed.
    • Maintenance branch sync: The splitter now syncs the maintenance branch (e.g. 6.0.x) to the tag before splitting, ensuring split repos always receive the correct commits for patch releases.

    Full changelog

    See CHANGELOG.md for details.

    Open source →
  7. 6.0.2 18 Mar 2026
    Release notes

    PSL 6.0.2

    Patch release fixing a bug in IO\Reader that affected non-blocking stream reads (TLS, TCP, etc.).

    Bug fixes

    IO: Reader no longer treats empty non-blocking reads as EOF

    Reader::readUntil() and Reader::readUntilBounded() assumed that an empty read() meant end-of-stream. On non-blocking handles (TLS, TCP, Unix sockets), read() can return empty before data arrives. This caused readLine() to return the entire stream content as a single string instead of splitting into individual lines.

    This bug affected any code using IO\Reader with network streams. If you were using readLine(), readUntil(), or readUntilBounded() on a non-blocking stream and getting unexpected results, this is the fix.

    Docs: source links point to correct paths

    Documentation source links (See src/Psl/Default/ for the full API) now link to packages/default/src/Psl/Default/ instead of the non-existent top-level src/Psl/Default/.

    Full changelog

    See CHANGELOG.md for details.

    Open source →
  8. 6.0.1 18 Mar 2026
    Release notes

    chore: update changelog (#683)

    Open source →
    Release notes
    • fix(io): Reader::readUntil() and Reader::readUntilBounded() no longer treat empty reads from non-blocking streams as EOF, fixing readLine() returning the entire content instead of individual lines when used with non-blocking streams
    • fix(docs): source links now correctly point to packages/{name}/src/Psl/ instead of the non-existent top-level src/Psl/ path
    • internal: add splitter audit command to verify organization repository settings (wiki, issues, discussions, PRs, tag immutability).
    Open source →
  9. 6.0.0 17 Mar 2026
    Release notes

    PSL 6.0.0

    PSL 6.0 is the biggest release in the project's history. New home, new packages, new capabilities.

    A new home

    PSL has moved. The repository, the organization, the website - everything has a new address:

    The azjezz/psl package is now abandoned. Run composer require php-standard-library/php-standard-library to switch.

    The namespace has not changed. It is Psl\, and it will always remain Psl\.

    61 standalone packages

    PSL is now split into 61 independently installable packages. You no longer need to pull in the entire library.

    Need just type-safe coercion? composer require php-standard-library/type

    Building an async TCP server? composer require php-standard-library/tcp

    Working with URIs? composer require php-standard-library/uri

    Every package declares its own dependencies, so you only get what you actually use. The full library install still works for those who want everything:

    composer require php-standard-library/php-standard-library

    All 61 packages live under the php-standard-library GitHub organization, each with its own read-only split repository for Composer.

    New components

    URI, IRI, URL

    Full RFC-compliant resource identifier handling:

    • URI - RFC 3986 parsing, normalization, reference resolution, and RFC 6570 URI Template expansion (Levels 1-4)
    • IRI - RFC 3987 Internationalized Resource Identifiers with Unicode support, Punycode, and IDNA 2008
    • URL - Strict URL type with scheme/authority validation and default port stripping

    Punycode

    Standalone RFC 3492 Punycode encoding and decoding for internationalized domain names.

    Cancellation tokens

    A new cancellation system replaces the old Duration $timeout pattern across all async/IO operations:

    • CancellationTokenInterface - base contract
    • TimeoutCancellationToken - auto-cancels after a duration
    • SignalCancellationToken - manually triggered cancellation
    • LinkedCancellationToken - cancelled when either of two inner tokens fires

    More highlights

    • TaskGroup and WaitGroup for structured concurrency
    • QuotedPrintable and EncodedWord encoding (RFC 2045, RFC 2047)
    • Streaming Base64/Hex/QuotedPrintable IO handles
    • TLS\Listener for wrapping any listener with TLS
    • TCP\RestrictedListener for IP/CIDR-based access control
    • Network\CompositeListener for accepting from multiple listeners
    • BufferedReadHandleInterface with readByte(), readLine(), readUntil()
    • Configuration objects for TCP, Unix, UDP, and Socks

    Breaking changes

    This is a major release with breaking changes. The most impactful:

    Cancellation replaces timeouts. All null|Duration $timeout parameters are now CancellationTokenInterface $cancellation = new NullCancellationToken().

    // Before (5.x)
    $data = $reader->read(timeout: Duration::seconds(5));
    
    // After (6.0)
    $data = $reader->read(cancellation: new Async\TimeoutCancellationToken(Duration::seconds(5)));

    Naming conventions. All variables, parameters, and properties now use $camelCase.

    Configuration objects. TCP\listen(), TCP\connect(), Unix\listen(), UDP\Socket::bind(), and Socks\Connector now accept configuration objects instead of individual parameters.

    Removed timeout exceptions. IO\Exception\TimeoutException, Network\Exception\TimeoutException, Process\Exception\TimeoutException, and Shell\Exception\TimeoutException are removed. Use Async\Exception\CancelledException instead.

    TLS renamed. TLS\ServerConfig -> TLS\ServerConfiguration, TLS\ClientConfig -> TLS\ClientConfiguration.

    See the full CHANGELOG for the complete list.

    Bug fixes

    • RetryConnector backoff sleep now respects cancellation tokens
    • IO\write(), IO\write_line(), IO\write_error(), IO\write_error_line(), and Str\format() no longer crash when the message contains % characters and no arguments are passed

    Thank you

    PSL is built by its community. Thank you to everyone who contributed code, reported bugs, sponsored the project, or simply used it in production.

    Open source →
    Release notes

    breaking changes

    • BC - All null|Duration $timeout parameters across IO, Network, TCP, TLS, Unix, UDP, Socks, Process, and Shell components have been replaced with CancellationTokenInterface $cancellation = new NullCancellationToken(). This enables both timeout-based and signal-based cancellation of async operations.
    • BC - Removed Psl\IO\Exception\TimeoutException - use Psl\Async\Exception\CancelledException instead.
    • BC - Removed Psl\Network\Exception\TimeoutException - use Psl\Async\Exception\CancelledException instead.
    • BC - Removed Psl\Process\Exception\TimeoutException - use Psl\Async\Exception\CancelledException instead.
    • BC - Removed Psl\Shell\Exception\TimeoutException - use Psl\Async\Exception\CancelledException instead.
    • BC - Psl\IO\CloseHandleInterface now requires an isClosed(): bool method.
    • BC - Network\SocketInterface::getLocalAddress() and Network\StreamInterface::getPeerAddress() no longer throw exceptions. Addresses are resolved at construction time and cached, making these O(1) property lookups with no syscall.
    • BC - BufferedReadHandleInterface::readLine() now always splits on "\n" instead of PHP_EOL. Trailing "\r" is stripped, so both "\n" and "\r\n" line endings are handled consistently across all platforms. Use readUntil(PHP_EOL) for system-dependent behavior.
    • BC - Psl\TLS\ServerConfig renamed to Psl\TLS\ServerConfiguration.
    • BC - Psl\TLS\ClientConfig renamed to Psl\TLS\ClientConfiguration.
    • BC - All variables and parameters across the codebase now use $camelCase naming instead of $snake_case.
    • BC - TCP\listen(), TCP\connect(), TCP\Socket::listen(), TCP\Socket::connect() now accept configuration objects (TCP\ListenConfiguration, TCP\ConnectConfiguration) instead of individual parameters for socket options.
    • BC - Unix\listen() and Unix\Socket::listen() now accept Unix\ListenConfiguration instead of individual parameters.
    • BC - UDP\Socket::bind() now accepts UDP\BindConfiguration instead of individual parameters.
    • BC - TCP\Socket setter/getter methods (setReuseAddress, setReusePort, setNoDelay, etc.) have been removed. Use configuration objects instead.
    • BC - TCP\Connector constructor now accepts TCP\ConnectConfiguration instead of bool $noDelay.
    • BC - Socks\Connector constructor changed from (string $proxyHost, int $proxyPort, ?string $username, ?string $password, ConnectorInterface $connector) to (ConnectorInterface $connector, Socks\Configuration $configuration).
    • BC - Renamed ingoing to ongoing across Semaphore, Sequence, KeyedSemaphore, and KeyedSequence (hasIngoingOperations() -> hasOngoingOperations(), getIngoingOperations() -> getOngoingOperations(), etc.).

    features

    • feat(async): introduce Psl\Async\CancellationTokenInterface for cancelling async operations
    • feat(async): introduce Psl\Async\NullCancellationToken - no-op token used as default parameter value
    • feat(async): introduce Psl\Async\SignalCancellationToken - manually triggered cancellation via cancel(?Throwable $cause)
    • feat(async): introduce Psl\Async\TimeoutCancellationToken - auto-cancels after a Duration, replacing the old Duration $timeout pattern
    • feat(async): introduce Psl\Async\LinkedCancellationToken - cancelled when either of two inner tokens is cancelled, useful for combining a request-scoped token with an operation-specific timeout
    • feat(async): introduce Psl\Async\Exception\CancelledException - thrown when a cancellation token is triggered; the cause (e.g., TimeoutException) is attached as $previous. Use $e->getToken() to identify which token triggered the cancellation.
    • feat(async): Async\sleep() now accepts an optional CancellationTokenInterface parameter, allowing early wake-up on cancellation
    • feat(async): Awaitable::await() now accepts an optional CancellationTokenInterface parameter
    • feat(async): Sequence::waitFor() and Sequence::waitForPending() now accept an optional CancellationTokenInterface parameter
    • feat(async): Semaphore::waitFor() and Semaphore::waitForPending() now accept an optional CancellationTokenInterface parameter
    • feat(async): KeyedSequence::waitFor() and KeyedSequence::waitForPending() now accept an optional CancellationTokenInterface parameter
    • feat(async): KeyedSemaphore::waitFor() and KeyedSemaphore::waitForPending() now accept an optional CancellationTokenInterface parameter
    • feat(channel): SenderInterface::send() and ReceiverInterface::receive() now accept an optional CancellationTokenInterface parameter
    • feat(network): ListenerInterface::accept() now accepts an optional CancellationTokenInterface parameter
    • feat(tcp): TCP\ListenerInterface::accept() now accepts an optional CancellationTokenInterface parameter
    • feat(unix): Unix\ListenerInterface::accept() now accepts an optional CancellationTokenInterface parameter
    • feat(tls): TLS\Acceptor::accept(), TLS\LazyAcceptor::accept(), TLS\ClientHello::complete(), and TLS\Connector::connect() now accept an optional CancellationTokenInterface parameter - cancellation propagates through the TLS handshake
    • feat(tls): TLS\TCPConnector::connect() and TLS\connect() now pass the cancellation token through to the TLS handshake
    • feat(async): introduce Psl\Async\TaskGroup for running closures concurrently and awaiting them all with defer() + awaitAll()
    • feat(async): introduce Psl\Async\WaitGroup, a counter-based synchronization primitive with add(), done(), and wait()
    • feat(encoding): introduce Psl\Encoding\QuotedPrintable\encode(), decode(), and encode_line() for RFC 2045 quoted-printable encoding with configurable line length and line ending
    • feat(encoding): introduce Psl\Encoding\EncodedWord\encode() and decode() for RFC 2047 encoded-word encoding/decoding in MIME headers (B-encoding and Q-encoding with automatic selection)
    • feat(tls): introduce TLS\ListenerInterface and TLS\Listener, wrapping any Network\ListenerInterface to perform TLS handshakes on accepted connections
    • feat(encoding): add Base64\Variant::Mime for RFC 2045 MIME Base64 with 76-char line wrapping and CRLF, using constant-time encoding/decoding
    • feat(encoding): introduce streaming IO handles for Base64 (EncodingReadHandle, DecodingReadHandle, EncodingWriteHandle, DecodingWriteHandle), QuotedPrintable (same 4), and Hex (same 4), bridging Psl\IO and Psl\Encoding for transparent encode/decode on read/write
    • feat(io): introduce Psl\IO\BufferedReadHandleInterface, extending ReadHandleInterface with readByte(), readLine(), readUntil(), and readUntilBounded()
    • feat(io): Psl\IO\Reader now implements BufferedReadHandleInterface
    • feat(tcp): introduce TCP\ListenConfiguration and TCP\ConnectConfiguration with immutable with* builder methods
    • feat(unix): introduce Unix\ListenConfiguration with immutable with* builder methods
    • feat(udp): introduce UDP\BindConfiguration with immutable with* builder methods
    • feat(socks): introduce Socks\Configuration with immutable with* builder methods for proxy host, port, and credentials
    • feat(tcp): introduce TCP\RestrictedListener, wrapping a listener to restrict connections to a set of allowed IP\Address and CIDR\Block entries
    • feat(network): introduce Network\CompositeListener, accepting connections from multiple listeners concurrently through a single accept() call
    • feat: introduce URI component - RFC 3986 URI parsing, normalization, reference resolution, and RFC 6570 URI Template expansion (Levels 1–4), with RFC 5952 IPv6 canonical form and RFC 6874 zone identifiers
    • feat: introduce IRI component - RFC 3987 Internationalized Resource Identifier parsing with Unicode support, RFC 3492 Punycode encoding/decoding, and RFC 5891/5892 IDNA 2008 domain name processing
    • feat: introduce URL component - strict URL type with scheme and authority validation, default port stripping for known schemes, and URI/IRI conversion
    • feat: introduce Punycode component - RFC 3492 Punycode encoding and decoding for internationalized domain names
    • fix(tcp): RetryConnector backoff sleep now respects cancellation tokens, allowing retry loops to be cancelled during the delay
    • fix(io, str): IO\write(), IO\write_line(), IO\write_error(), IO\write_error_line(), and Str\format() no longer pass the message through sprintf/vsprintf when no arguments are given, preventing format string errors when the message contains % characters

    migration guide

    Replace Duration timeout parameters with TimeoutCancellationToken:

    // Before (5.x)
    $data = $reader->read(timeout: Duration::seconds(5));
    
    // After (6.0)
    $data = $reader->read(cancellation: new Async\TimeoutCancellationToken(Duration::seconds(5)));
    

    For manual cancellation (e.g., cancel all request IO when a client disconnects):

    $token = new Async\SignalCancellationToken();
    
    // Pass to all request-scoped IO
    $body = $reader->readAll(cancellation: $token);
    
    // Cancel from elsewhere
    $token->cancel();
    
    Open source →
  10. 5.5.0 12 Mar 2026
    Release notes

    PSL 5.5.0

    IO: Bounded Reads

    Reader::readUntilBounded() reads from a handle until a suffix is found, just like readUntil(), but enforces a maximum byte limit. If the suffix is not encountered within $max_bytes, an IO\Exception\OverflowException is thrown.

    This is essential when reading from untrusted sources. for example, capping HTTP header lines so a malicious client cannot exhaust memory by sending an endless line:

    use Psl\IO;
    
    $reader = new IO\Reader($connection);
    
    // Read a header line, but never buffer more than 8KB
    $line = $reader->readUntilBounded("\r\n", max_bytes: 8192);

    Type: Type\json_decoded() and Type\nullish()

    Two new type coercions from @veewee:

    • Type\json_decoded(TypeInterface $inner): accepts a JSON string and transparently decodes it, then coerces the result through $inner. Useful for APIs and form fields that pass structured data as JSON strings.

    • Type\nullish(TypeInterface $inner): matches null, the absence of a key (for shape fields), and the inner type. Ideal for optional-and-nullable shape fields where "missing" and "null" should be treated the same.


    Documentation: psl.carthage.software/ | IO | Type


    Full Changelog: 5.4.0...5.5.0

    Open source →
    Release notes

    features

    • feat(io): added Reader::readUntilBounded(string $suffix, int $max_bytes, ?Duration $timeout) method, which reads until a suffix is found, but throws IO\Exception\OverflowException if the content exceeds $max_bytes before the suffix is encountered - #620 - by @azjezz
    • feat(io): added IO\Exception\OverflowException exception class - #620 - by @azjezz
    • feat(type): add Type\json_decoded() type for transparent JSON string coercion - #619 by @veewee
    • feat(type): add Type\nullish() type for optional-and-nullable shape fields - #618 by @veewee
    Open source →
  11. 5.4.0 10 Mar 2026
    Release notes

    features

    • feat(dict, vec): add filter_nonnull_by and map_nonnull - #576 by @Dima-369
    • feat(tcp): add backlog parameter to TCP\listen() for configuring the pending connection queue size - #617 - by @azjezz
    • feat(tcp): listener now drains the accept backlog in a loop for higher throughput - #617 - by @azjezz

    other

    • chore: update dev dependencies, and re-format the codebase using latest mago version - #616 by @azjezz
    Open source →
  12. 5.3.0 08 Mar 2026
    Release notes

    features

    • feat(io): introduce IO\spool() for memory-backed handles that spill to disk
    Open source →
  13. 5.2.0 07 Mar 2026
    Release notes

    features

    • feat: introduce IP component with immutable, binary-backed Address value object and Family enum
    • feat(cidr): CIDR\Block::contains() now accepts string|IP\Address
    Open source →
  14. 5.1.0 05 Mar 2026
    Release notes

    features

    • feat(tls): introduce TLS\TCPConnector for poolable TLS connections
    • feat(tls): TLS\StreamInterface now extends TCP\StreamInterface, enabling TLS streams to be used with TCP\SocketPoolInterface
    Open source →
  15. 5.0.0 04 Mar 2026
    Release notes

    breaking changes

    • Dropped PHP 8.3 support; minimum is now PHP 8.4 - #584 by @azjezz
    • Migrated to PHPUnit 13 - #584 by @azjezz
    • Complete networking stack rewrite (Network, TCP, Unix) - #585 by @azjezz
    • Psl\Shell internals refactored; dead code removed - #596 by @azjezz
    • Psl\Env\temp_dir() now always returns a canonicalized path - #599 by @azjezz

    features

    • feat: introduce Ansi component - #588 by @azjezz
    • feat: introduce Terminal component - #589 by @azjezz
    • feat: introduce Process component - #578 by @azjezz
    • feat: introduce Binary component - #598 by @azjezz
    • feat: introduce Interoperability component - #582 by @azjezz
    • feat: introduce TLS component - #585 by @azjezz
    • feat: introduce UDP component - #585 by @azjezz
    • feat: introduce CIDR component - #585 by @azjezz
    • feat: introduce Socks component - #585 by @azjezz
    • feat(network): connection pooling, retry logic, socket pairs - #585 by @azjezz
    • feat(datetime): add Period, Interval, TemporalAmountInterface - #595 by @azjezz
    • feat(io): add IO\copy() and IO\copy_bidirectional() - #585 by @azjezz
    • feat(vec): add Vec\flatten() - #583 by @azjezz
    • feat: introduce Crypto component with symmetric/asymmetric encryption, signing, AEAD, KDF, HKDF, key exchange, and stream ciphers - #607 by @azjezz

    fixes, and improvements

    • fix(vec): strict comparison in range() for float precision - #581 by @azjezz
    • fix(filesystem): canonicalize temporary directory for create_temporary_file - #580, #597 by @azjezz

    other

    • docs: documentation website at https://php-standard-library.dev/ - #592, #594 by @azjezz
    • perf: performed optimizations across multiple components, which benchmarks showing up to 100% improvements in certain cases/functions.
    Open source →
  16. 4.3.0 24 Feb 2026
    Release notes

    features

    • feat: introduce Either type - #572 by @simPod
    • feat(type): add uuid type - #568 by @gsteel

    fixes, and improvements

    • fix(shell): terminate the process on timeout - #574 by @azjezz
    • fix(io): correct PHPDoc return type annotation - #571 by @mitelg
    • refactor(phpunit): resolve test case naming deprecations - #573 by @simPod
    Open source →
  17. 4.2.1 29 Jan 2026
    Release notes

    fixes, and improvements

    • fix(tree): explicit type precedence - #566 by @azjezz
    • fix(iter): do not narrow down seek($offset) type - #552 by @azjezz
    • fix(filesystem): release handles before changing permissions when copying files - #550 by @dragosprotung
    • revert(option): revert #475 - #560 by @devnix
    Open source →
  18. 4.2.0 25 Oct 2025
    Release notes

    other

    • chore: add support for PHP 8.5 - #549 by @veewee
    Open source →
  19. 4.1.0 23 Oct 2025
    Release notes

    features

    • feat: add Graph component with directed and undirected graph support - #547 by @azjezz
    • feat: add Tree component for hierarchical data structures - #546 by @azjezz
    • feat(type): add reflection-based type functions for class members - #543 by @azjezz

    other

    • chore: migrate from make to just - #544 by @azjezz
    Open source →
  20. 4.0.1 09 Oct 2025
    Release notes

    fixes, and improvements

    • refactor: remove redundant @var tags from constants - #533 by @azjezz
    Open source →
  21. 4.0.0 15 Sep 2025
    Release notes

    breaking changes

    • Psl\Result\wrap() no longer unwraps nested results - #531 by @azjezz
    • Psl\Collection\Map, Psl\Collection\MutableMap, Psl\Collection\Set, and Psl\Collection\MutableSet now have a more natural JSON serialization - #512 by @josh-rai
    • A large number of intersection interfaces in the Psl\IO and Psl\File namespaces have been removed to simplify the component's hierarchy - #518 by @azjezz
    • Psl\sequence() function has been removed - #519 by @azjezz

    features

    • feat(type): add container type - #513 by @azjezz
    • feat(type): add int_range type - #510 by @george-steel
    • feat(type): add always_assert type - #522 by @azjezz
    • feat(iter): add search_with_keys_opt and search_with_keys functions - #490 by @simon-podlipsky

    fixes, and improvements

    • refactor: improve type inference for non-empty lists - #529 by @azjezz
    • refactor: improve type inference for Iter and Regex - #528 by @azjezz

    other

    • chore: migrate from psalm to mago - #527 by @azjezz
    • chore: replace psalm-specific tags by generic tags - #531 by @azjezz
    Open source →
  22. 3.3.0 03 Mar 2025

    Nothing published for this version

  23. 3.2.0 23 Jan 2025

    Nothing published for this version

  24. 3.1.0 21 Nov 2024

    Nothing published for this version

  25. 3.0.2 13 Sep 2024

    Nothing published for this version

  26. 3.0.1 12 Sep 2024

    Nothing published for this version

  27. 3.0.0 03 Sep 2024

    Nothing published for this version

  28. 2.9.1 05 Apr 2024

    Nothing published for this version

  29. 2.9.0 29 Dec 2023

    Nothing published for this version

  30. 2.8.0 22 Nov 2023

    Nothing published for this version

  31. 2.7.0 19 Jul 2023
    Release notes

    features

    • feat(encoding): introduce Base64\Variant enum to support encoding/decoding different variants - #408 by @Gashmob

    fixes, and improvements

    • fix(option): return Option<never> for Option::none() - #415 by @devnix
    • fix(str): add invariant to avoid unexpected errors when parsing an invalid UTF8 string - #410 by @devnix
    Open source →
  32. 2.6.0 18 May 2023
    Release notes

    features

    • feat(type): introduce Type\converted function - #405 by @veewee
    • feat(type): introduce Type\numeric_string function - #406 by @veewee
    Open source →
  33. 2.5.0 17 Mar 2023
    Release notes

    features

    • feat(result): introduce Result\try_catch function - #403 by @azjezz

    fixes, and improvements

    • fix(file): improve consistency when creating files for write-mode - #401 by @veewee
    Open source →
  34. 2.4.1 26 Jan 2023
    Release notes

    fixes, and improvements

    • fix(type): un-deprecate Psl\Type\positive_int function - #400 by @dragosprotung
    Open source →
  35. 2.4.0 24 Jan 2023
    Release notes

    features

    • feat(range): introduced Psl\Range component - #378 by @azjezz
    • feat(str): introduced Psl\Str\range, Psl\Str\Byte\range, and Psl\Str\Grapheme\range functions - #385 by @azjezz
    • feat(type): introduced Psl\Type\uint function - #393 by @azjezz
    • feat(type): introduced Psl\Type\i8, Psl\Type\i16, Psl\Type\i32, Psl\Type\i64 functions - #392 by @azjezz
    • feat(type): introduced Psl\Type\u8, Psl\Type\u16, Psl\Type\u32 functions - #395 by @KennedyTedesco
    • feat(type): introduced Psl\Type\f32, and Psl\Type\f64 functions - #396 by @KennedyTedesco
    • feat(type): introduced Psl\Type\nonnull function - #392 by @azjezz
    • feat(option): improve options type declarations and add andThen method - #398 by @veewee

    fixes, and improvements

    • fix(vec/dict): Return might be non-empty-list/non-empty-array for map functions - #384 by @dragosprotung

    other

    • chore(async): add async component documentation - #386 by @azjezz

    deprecations

    • deprecated Psl\Type\positive_int function, use Psl\Type\uint instead - by @azjezz
    Open source →
  36. 2.3.1 20 Dec 2022
    Release notes

    fixes, and improvements

    • fix(vec): Vec\reproduce and Vec\range return type is always non-empty-list - #383 by @dragosprotung

    other

    • chore: update license copyright year - #371 by @azjezz
    Open source →
  37. 2.3.0 01 Dec 2022
    Release notes

    other

    • chore: support psalm v5 - #369 by @veewee
    Open source →
  38. 2.2.0 26 Nov 2022
    Release notes

    features

    • feat(option): introduce option component - #356 by @azjezz
    Open source →
  39. 2.1.0 04 Nov 2022
    Release notes

    features

    • introduced a new Psl\Type\unit_enum function - @19d1230 by @azjezz
    • introduced a new Psl\Type\backed_enum function - @19d1230 by @azjezz
    • introduced a new Psl\Type\mixed_vec function - #362 by @BackEndTea
    • introduced a new Psl\Type\mixed_dict function - #362 by @BackEndTea

    fixes, and improvements

    • improved Psl\Type\vec performance - #364 by @BackEndTea
    • improved Psl\Type\float, and Psl\Type\num - #367 by @bcremer

    other

    • updated revolt-php/event-loop to 1.0.0 - @c7bf866 by @azjezz
    • introduced scope-able loader - #361 by @veewee
    • fixed wrong function names in examples - #354 by @jrmajor
    • added reference to PHPStan integration in README.md - #353 by @ondrejmirtes
    Open source →
  40. 2.0.4 10 Oct 2022

    Nothing published for this version

  41. 2.0.3 07 Jun 2022

    Nothing published for this version

  42. 2.0.2 30 May 2022

    Nothing published for this version

  43. 2.0.1 11 May 2022

    Nothing published for this version

  44. 2.0.0 07 May 2022
    Release notes
    • BC - removed Psl\Arr component.

    • BC - removed Psl\Type\is_array, Psl\Type\is_arraykey, Psl\Type\is_bool, Psl\Type\is_callable, Psl\Type\is_float, Psl\Type\is_instanceof, Psl\Type\is_int, Psl\Type\is_iterable, Psl\Type\is_null, Psl\Type\is_numeric, Psl\Type\is_object, Psl\Type\is_resource, Psl\Type\is_scalar, and Psl\Type\is_string functions ( use TypeInterface::matches($value) instead ).

    • BC - removed Psl\Iter\chain, Psl\Iter\chunk, Psl\Iter\chunk_with_keys, Psl\Iter\diff_by_key, Psl\Iter\drop, Psl\Iter\drop_while, Psl\Iter\enumerate, Psl\Iter\filter, Psl\Iter\filter_keys, Psl\Iter\filter_nulls, Psl\Iter\filter_with_key, Psl\Iter\flat_map, Psl\Iter\flatten, Psl\Iter\flip, Psl\Iter\from_entries, Psl\Iter\from_keys, Psl\Iter\keys, Psl\Iter\map, Psl\Iter\map_keys, Psl\Iter\map_with_key, Psl\Iter\merge, Psl\Iter\product, Psl\Iter\pull, Psl\Iter\pull_with_key, Psl\Iter\range, Psl\Iter\reductions, Psl\Iter\reindex, Psl\Iter\repeat, Psl\Iter\reproduce, Psl\Iter\reverse, Psl\Iter\slice, Psl\Iter\take, Psl\Iter\take_while, Psl\Iter\to_array, Psl\Iter\to_array_with_keys, Psl\Iter\values, and Psl\Iter\zip functions.

    • BC - signature of Psl\Iter\reduce_keys function changed from reduce_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(?Ts, Tk): Ts) $function, Ts|null $initial = null): Ts|null to reduce_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(Ts, Tk): Ts) $function, Ts $initial): Ts.

    • BC - signature of Psl\Iter\reduce_with_keys function changed from reduce_with_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(?Ts, Tk, Tv): Ts) $function, Ts|null $initial = null): Ts|null to reduce_with_keys<Tk, Tv, Ts>(iterable<Tk, Tv> $iterable, (callable(Ts, Tk, Tv): Ts) $function, Ts $initial): Ts.

    • BC - removed bundled psalm plugin Psl\Integration\Psalm\Plugin, use php-standard-library/psalm-plugin package instead.

    • dropped support for PHP 8.0

    • BC - signature of Psl\Type\object function changed from object<T of object>(classname<T> $classname): TypeInterface<T> to object(): TypeInterface<object> ( to preserve the old behavior, use Psl\Type\instance_of )

    • introduced Psl\Type\instance_of function, with the signature of instance_of<T of object>(classname<T> $classname): TypeInterface<T>.

    • introduced a new Psl\Async component.

    • refactored Psl\IO handles API.

    • introduced a new Psl\File component.

    • refactor Psl\Shell\execute to use Psl\IO component.

    • introduced a Psl\IO\pipe(): (Psl\IO\CloseReadHandleInterface, Psl\IO\CloseWriteHandleInterface) function to create a pair of handles, where writes to the WriteHandle can be read from the ReadHandle.

    • BC - $encoding argument for Psl\Str functions now accepts Psl\Str\Encoding instead of ?string.

    • introduced a new Psl\Runtime component.

    • introduced a new Psl\Network component.

    • introduced a new Psl\TCP component.

    • introduced a new Psl\Unix component.

    • introduced a new Psl\Channel component.

    • introduced a new IO\write() function.

    • introduced a new IO\write_line() function.

    • introduced a new IO\write_error() function.

    • introduced a new IO\write_error_line() functions.

    • introduced a new Psl\Html\Encoding enum.

    • BC - $encoding argument for Psl\Html functions now accepts Psl\Html\Encoding instead of ?string.

    • BC - Psl\Shell\escape_command function has been removed, no replacement is available.

    • introduced a new Psl\Math\acos function.

    • introduced a new Psl\Math\asin function.

    • introduced a new Psl\Math\atan function.

    • introduced a new Psl\Math\atan2 function.

    • BC - The type of the $numbers argument of Psl\Math\mean has changed to list<int|float> instead of iterable<int|float>.

    • BC - The type of the $numbers argument of Psl\Math\median has changed to list<int|float> instead of iterable<int|float>.

    • introduced a new Psl\Promise component.

    • BC - Psl\Result\ResultInterface now implements Psl\Promise\PromiseInterface

    • BC - Psl\Type\resource('curl')->toString() now uses PHP built-in resource kind notation ( i.e: resource (curl) ) instead of generic notation ( i.e: resource<curl> )

    • BC - Psl\Str, Psl\Str\Byte, and Psl\Str\Grapheme functions now throw Psl\Str\Exception\OutOfBoundsException instead of Psl\Exception\InvaraintViolationsException when $offset is out-of-bounds.

    • BC - Psl\Collection\IndexAccessInterface::at() now throw Psl\Collection\Exception\OutOfBoundsException instead of Psl\Exception\InvariantViolationException if $k is out-of-bounds.

    • BC - Psl\Collection\AccessibleCollectionInterface::slice signature has changed from slice(int $start, int $length): static to slice(int $start, ?int $length = null): static

    • BC - All psl functions previously accepting callable, now accept only Closure.

    • BC - Psl\DataStructure\QueueInterface::dequeue, and Psl\DataStructure\StackInterface::pop now throw Psl\DataStructure\Exception\UnderflowException instead of Psl\Exception\InvariantViolationException when the data structure is empty.

    • BC - Psl\Filesystem\write_file($file, $content) function has been removed, use Psl\File\write($file, $content); instead.

      To preserve the same behavior as the old function, use Psl\File\write($file, $content, Filesystem\is_file($file) ? File\WriteMode::TRUNCATE : File\WriteMode::OPEN_OR_CREATE).

    • BC - Psl\Filesystem\read_file($file, $offset, $length) function has been removed, use Psl\File\read($file, $offset, $length) instead.

    • BC - Psl\Filesystem\append_file($file, $contents) function has been removed, use Psl\File\write($file, $contents, File\WriteMode::APPEND) instead.

    • BC - Psl\Filesystem functions no longer throw Psl\Exception\InvariantViolationException.

      New exceptions:

      • Psl\Filesystem\Exception\NotReadableException thrown when attempting to read from a non-readable node
      • Psl\Filesystem\Exception\NotFileException thrown when attempting a file operation on a non-file node.
      • Psl\Filesystem\Exception\NotDirectoryException thrown when attempting a directory operation on a non-directory node.
      • Psl\Filesystem\Exception\NotSymbolicLinkException thrown when attempting a symbolic link operation on a non-symbolic link node.
      • Psl\Filesystem\Exception\NotFoundException thrown when attempting an operation on a non-existing node.
    • introduced Psl\Hash\Algorithm enum.

    • introduced Psl\Hash\Hmac\Algorithm enum.

    • BC - Psl\Hash\hash, and Psl\Hash\Context::forAlgorithm now take Psl\Hash\Algorithm as an algorithm, rather than a string.

    • BC - Psl\Hash\Hmac\hash, and Psl\Hash\Context::hmac now take Psl\Hash\Hmac\Algorithm as an algorithm, rather than a string.

    • BC - A new method chunk(positive-int $size): CollectionInterface has been added to Psl\Collection\CollectionInterface.

    • introduced a new Psl\OS component.

    • introduced Psl\Password\Algorithm enum

    • BC - all constants of Psl\Password component has been removed.

    • BC - function Psl\Password\algorithms() have been removed.

    • BC - Psl\Result\ResultInterface::getException() method has been renamed to Psl\Result\ResultInterface::getThrowable()

    • BC - Psl\Result\wrap function now catches all Throwables instead of only Exceptions

    • introduced a new Psl\Result\reflect function

    • BC - Psl\Shell\escape_argument function has been removed, Shell\execute arguments are now always escaped.

    • BC - $escape_arguments argument of Shell\execute function has been removed.

    • introduced a new Psl\Shell\ErrorOutputBehavior enum

    • added a new $error_output_behavior argument to Shell\execute function, which can be used to return the command error output content, as well as the standard output content.

    • introduced a new Psl\Shell\unpack function to unpack packed result of Shell\execute ( see Psl\Shell\ErrorOutputBehavior::Packed ).

    • introduced a new Psl\Shell\stream_unpack function to unpack packed result of Shell\execute chunk by chunk, maintaing order ( see Psl\Shell\ErrorOutputBehavior::Packed ).

    Open source →
  45. 2.0.0-rc2 15 Jan 2022 pre-release

    Nothing published for this version

  46. 2.0.0-rc1 08 Jan 2022 pre-release

    Nothing published for this version

  47. 1.9.3 10 Dec 2021

    Nothing published for this version

  48. 1.9.2 10 Nov 2021

    Nothing published for this version

  49. 1.9.1 06 Nov 2021

    Nothing published for this version

  50. 1.9.0 18 Oct 2021

    Nothing published for this version

  51. 1.8.2 08 Dec 2021

    Nothing published for this version

  52. 1.8.1 03 Oct 2021

    Nothing published for this version

  53. 1.8.0 12 Aug 2021

    Nothing published for this version

  54. 1.7.4 08 Dec 2021

    Nothing published for this version

  55. 1.7.3 25 Aug 2021

    Nothing published for this version

  56. 1.7.2 24 May 2021

    Nothing published for this version

  57. 1.7.1 19 May 2021

    Nothing published for this version

  58. 1.7.0 15 May 2021

    Nothing published for this version

  59. 1.6.3 23 Feb 2022

    Nothing published for this version

  60. 1.6.2 08 Dec 2021

    Nothing published for this version

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive